Lazy loaded image
知识小记
🍇函数与递归
Words 1562Read Time 4 min
2026-3-23
2026-3-23
type
Post
status
Published
date
Mar 23, 2026
slug
Cfunc
summary
C语言中的函数与递归小记
tags
笔记
思考
category
知识小记
icon
password
类型
日期
标签
概述
函数与递归
状态
编程不是看会的,也不是听会的,而是练会的,所以应尽量在计算机旁阅读本 书,以便把书中的程序输入到计算机中进行调试,顺便再做做上机练习。

Plans

  1. 掌握多参数、单返回值的数学函数的定义和使用方法
  1. 学会用typedef定义结构体
  1. 函数调用时用实参给形参赋值的过程
  1. 学会定义局部变量和全局变量
  1. 理解调用栈和栈帧,学会用gdb查看调用栈并选择栈帧
  1. 理解地址和指针
  1. 理解递归定义和递归函数
  1. 理解可执行文件中的正文段、数据段和BSS段
  1. 熟悉堆栈段,了解栈溢出的常见原因

Notes

自定义结构体

上述代码中定义了一个名为point的结构体,包括两个域:double型的x和y。
💡
在C语言中,定义结构体的方法为“struct 结构体名称{ 域定义 };”,注意花括 号的后面还有一个分号。
所有用到Point的地方都得写一个struct。有一个方法可以避 开这些struct,让结构体用起来和int、double这样的“原生”类型更接近:

函数调用与参数传递

形参与实参

函数的形参和在函数内声明的变量都是该函数的局部变量。无法访问其他函数的局部变量。局部变量的存储空间是临时分配的,函数执行完毕时,局部变量的空间将被释放,其中的值无法保留到下次使用。在函数外声明的变量是全局变量,可以被任何函数使用。

调用栈

调用栈描述的是函数之间的调用关系。它由多个栈帧(Stack Frame)组成,每个栈帧对应着一个未运行完的函数。
栈帧中保存了该函数的返回地址和局部变量,因而不仅能在执行 完毕后找到正确的返回地址,还很自然地保证了不同函数间的局部变量互不相干——因为不 同函数对应着不同的栈帧。
💡
C语言用调用栈(Call Stack)来描述函数之间的调用关系。调用栈由栈帧 (Stack Frame)组成,每个栈帧对应着一个未运行完的函数。

指针

为什么要用指针?
C 语言函数参数默认是值传递。如果写成 swap(int a, int b),只会交换副本,函数外原变量不变。用指针后,传入的是变量地址,函数里修改的是“原变量本体”。
用 int* a 声明的变量a是指向int型变量的指针。赋值 a = &b 的含义是把变量b的地址存放在指针a中,表达式 *a 代表a指向的变量,既可以放在赋值符号的左边(左值),也可以放在右边(右值)。
💡
*a是指“a指向的变量”,而不仅是“a指向的变量所拥有的值。例如,*a = *a + 1就是让a指向的变量自增1。

数组作为参数和返回值

💡
是错误的,因为sizeof(a)无法得到数组的大小。把数组作为参数传递给函数时,实际上只有数组的首地址作为指针传递给了函数。
换句话说,在函数定义中的int a[]等价于int *a。在只有地址信息的情况下,是无法知道数组里有多少个元素的。
以数组为参数调用函数时,实际上只有数组首地址传递给了函数,需要另加一个参数表示元素个数。除了把数组首地址本身作为实参外,还可以利用指针加减法把其他元素的首地址传递给函数。

把函数作为函数的参数

💡
指向常数的“万能”的指针:const void *,它可以通过强制类型转化变成任意类型的指针。对于本题来说,排序的对象是整型数组,因此要这样写:

递归

💡
递归就是“自己用到自己”的意思。
“间接地用到自己”也算递归。
可以递归定义“常量表达式”(以下简称表达式): (1)整数和浮点数都是表达式。 (2)如果A是表达式,则(A)是表达式。 (3)如果A和B都是表达式,则A+B、A-B、A*B、A/B都是表达式。 (4)只有通过(1)、(2)、(3)定义出来的才是表达式。

递归函数

数学函数也可以递归定义。例如,阶乘函数f(n)=n!可以定义为:
notion image
💡
C语言支持递归,即函数可以直接或间接地调用自己。但要注意为递归函数 编写终止条件,否则将产生无限递归。
递归调用时新建了一个栈帧,并且跳转到了函数开头处执行,就好比皇帝找大臣、大臣找知府这样的过程。尽管同一时刻可以有多个栈帧(皇帝、大臣、知府同时处于“等待下级回话”的状态),但“当前代码行”只有一个。

头文件

这是一个头文件。什么是头文件呢?实践者的理解方式就是——不加这一行时会出现什 么错误,反过来就说明了这一行的作用。不加这一行的编译警告是:
头文件的作用就是:包含了一些函数,供主程序使用。下表中列出了一些常用函数和对应的头文件
notion image
 
上一篇
SQL
下一篇
Vim 语法速记