函数
1、函数中的形参只有在函数被调用时,也就是实参传入时,才会创建内存空间。且形参和实参虽然值相同,但所在的内存空间是不同的。
2、数组传参后,在函数中对数组的操作其实是对原数组的操作,并不会像1
中说的那样再创建一个相同的数组。这是因为数组传参时传给函数的是指针。函数内对数组的操作都是基于指针的操作。
3、printf()
函数的返回值是整型,且是成功打印到屏幕上的字符个数。注意,也就是printf()
中格式字符串内的字符个数(不包含格式字符串末尾的终止字符’\0’)。
4、在C语言的大型工程中,函数一般都是作为模块与主源文件分开写的。
我们知道.c
结尾的文件是源文件,.h
结尾的是头文件,主源文件是用于存放main()
函数的源文件,而main()
函数中调用的诸多函数都是作为函数模块
与主函数分开写。函数模块
包含头文件
与源文件
,头文件
用于存放函数的声明,源文件
用于存放函数的定义。
这样分开写使得工程编写更有效率,且代码结构更清晰。且分开写也能实现代码隐藏(有利于代码商业化)。
5、include<头文件>
导入的是编译器自带的库函数,include"头文件"
导入的是自定义的函数。
递归函数
1、递归函数就是函数自己调用自己。但是注意,自己调用自己这个行为一定要有终止的时候,即要为自我调用设置一个终止条件,否则就会永无止境地调用下去,内存占用不断增大,最终导致栈溢出,称为死递归。
2、递归函数中要有一个分支语句来判断是否到达递归尽头。
3、无论是嵌套函数(函数对其他函数的调用),还是递归函数(函数对自己的调用),每一次的调用都会开辟一块新的内存空间,用于存放当次调用所创建的数据。所以不能永久地调用下去,因为这样会不断开辟新的内存空间,最终导致栈溢出。
4、循环分为递归循环和迭代循环,递归代码量少但资源消耗大,循环代码量大但效率高。
5、写递归函数的要点:1、将数学运算公式找出来。2、用分支语句编写结束条件。
6、当函数可写为类似以下公式时,优先选择递归循环:

函数栈帧空间
1、函数栈帧空间
存在于栈区,是专门用于存储函数的空间,也就是函数在被调用时申请的空间。
2、单个进程的内存分区,按照低地址到高地址为:静态区
、堆区
、栈区
。
栈区就像是个倒扣的杯子,处于低地址的栈顶
是杯口,处于高地址的栈底
是杯底。
栈区存储的一般是三个:局部变量
、形式参数
、函数栈帧空间
。
每个函数中的局部变量
存储在所定义的函数栈帧空间
中,也就是在那个函数里定义的局部变量
,就存储在哪个函数的函数栈帧空间
中。而形式参数
与函数栈帧空间
相互独立:
上图为递归函数的内存视图:
main()
函数最先调用,所以在栈底
;main()
函数中定义的局部变量r
和n都存储在main()
的函数栈帧空间内部;当main()
函数第一次调用Fact()
函数时,先为形参
开辟内存空间,再为Fact()
函数开辟内存空间。
当被调用的函数执行完成,就会依次从栈顶
出栈,也就是消亡。
3、函数根据自己的调用顺序,按照栈
的存储规则来确定存储顺序,即:先进后出,后进先出
。
也就是:
先调用的函数存储在高地址,后调用的函数存储在低地址。
消亡的顺序是:
低地址的函数先出栈
,高地址的函数后出栈
。
所以,一般存储在栈底
的都是main()
函数,因为main()
函数是第一个被调用的函数。