函数大体上就是:分离问题复杂度,让数据之间隔离。每个函数拥有独立内存区域。
函数定义:确切指定该函数的具体功能。
语法: 类型 函数名(形式参数)
代码块
函数原型(函数声明):告知编译器其函数类型
eg:Void show_n_char(char n,int num); //带参数
int *func(void)l; //不带任何参数
PS:在其中可根据喜好省略变量名,但建议加入描述性的参数名
旧式函数声明:int main();(不建议采用,某些编译器可以编译通过,但容易产生参数错误匹配问题)
最安全最方便的使用方法:可把原型置于一个单独的文件中,当其它源文件需要这个函数的原型时,就使用#include 指令包含该文件。
形参与实参
形式参量:被调函数中的局部变量 ANSI C形式要求在每个变量前声明其类型
PS:参数声明需位于标志函数体开始的话括号之前,普通局部变量在开始花括号之后声明
实际参数:调用函数分配给被调函数变量的特定数值 可以是常量、变量、表达式,但执行时要先计算其值,然后将该值复制给被调函数中相应的形式参量。
实参传递给形参: 能转换就换,不能转换就报错;转换时会把实际参数值转换成和形式参数相同的数值。
“值传递”:内存上参数的拷贝
改变调用函数中的变量:不复制地址,传递的只是数值(可以用指针解决)
返回值:
return:从函数返回一个值
当函数返回值的类型和声明的类型不相同时,实际返回值是当把指定要返回的值赋给一个具有所声明的返回类型的变量时得到的数值。
return语句的另一作用:终止执行函数,并把控制权返回给调用函数的下一个语句
return;语句只能用在void类型的函数中
当使用 <>时,查找顺序是在编译器设置指定的include文件的对应目录下面
当使用 “ ” 时,优先在当前编辑的源代码目录下找,如找不到就在系统目录中找。常用于用户自己设计的头文件
函数调用:导致该函数的执行
大体上就是流程转移:主调函数→被调函数(执行)→主调函数
步骤:
1. 根据函数调用约定传递参数
2. 保存函数的返回地址(栈空间)
3. 为函数内部开辟内存空间
4. 保留调用方 栈环境(当前硬件(CPU环境))
5. 执行函数体二进制代码,函数执行结束后传递返回值到eax寄存器中
6. 恢复寄存器
7. 撤销被分配的函数内存空间
8. 取得返回地址并返回
①调用约定如果是C语言 则程序返回到返回地址 由调用方清理变量的内存空间
②调用约定如果是 std call 则 由被调用方清理然后再回到返回地址中
9. 由调用者平衡参数
△调用约定:
· 参数的内存空间由调用方撤销掉
· C方式由main函数撤销,其他是函数自己撤销
· C方式可以支持多参
△ 运行程序时一闪就过:可以加上 system(“pause”);(系统支持的命令就可以)
递归
基本原理:
1. 每一级调用都有自己的变量
2. 每一次函数调用都会有一次返回(不能直接返回到main()中的初始调用部分,通过递归的每一级逐步返回)
3. 位于递归调用前的语句和各级被调用函数具有相同的执行顺序,反之
4. 虽然每一级递归都有自己的变量,但函数代码不会得到复制
5. 递归中必须包含可以终止递归调用的语句