函数
-
函数是一组一起执行任务的语句,函数是一个可执行C程序必不可少的条件(至少一个main()函数),函数的定义形式
returnType functionName() {
bodyOf of the function
} -
定义函数的意义
- 为某个经常使用的功能定义一个函数,可以提高代码的简洁性
- 封装函数功能的实现细节,提供一个可用的接口
- 可以构建函数库,使软件开发变得更加高效
-
函数的组成部分
- 返回类型
- 函数返回值的默认类型为int,若没有返回值,则返回类型为:void
- 标准函数库中的常见函数返回值的含义】
- main 函数的返回值为函数结束的状态
- printf 函数的返回值为字符常量的字符个数
- 返回值的注意事项
- 一个函数最多能返回一个值(swift语言中使用
元组
实现了多返回值方案) - 若指定了返回值得类型,却未返回任何值,此时函数的返回值为一个未知的数
- 一个函数最多能返回一个值(swift语言中使用
- 函数名称
- 函数调用时使用的实际名称
- 函数签名
- 函数名与参数列表共同构成了函数签名
- 参数
- 为函数调用时的实际参数占位,函数可能不包含参数
- 参数的类型
- 形参
- 形参的作用域仅限于该函数,在进入函数时被创建,退出函数时被销毁
- 不能在函数内部定义与形参同名的变量,否则会将形参覆盖
- 实参
- 实参的个数必须与形参的个数相同
- 实参的类型必须与形参的类型一致,否则将造成数据失真
- 形参
- 参数列表
- 包含参数的类型、顺序、数量
- 函数参数的传递方式
- 值传递
- 将参数的实际值复制给形式参数,对实际参数没有影响
- 地址传递
- 将参数的地址复制给形式参数,对实际参数有影响
- 引用传递
- 将参数的引用复制给形式参数,对实际参数有影响
- 值传递
- 函数主体
- 函数执行的一系列语句
- 返回类型
-
函数的声明
- 为编译器提供函数的相关信息,在编译时只会被拷贝一次,可以重复声明
- 注意
- 函数在使用之前需要先定义或声明
- 每个声明的函数必须定义,否则链接时会报错
- 函数声明一般写在.h文件中,在使用时,用#include包含该文件
- 函数声明时,若有参数,参数列表是必须的,参数名不是必须的,即函数声明时可以没有参数名
-
函数的注意事项
- 不能定义同名函数
- 函数一般具有文件作用域,不允许嵌套定义
- 函数的嵌套调用要遵循堆栈规则
- 调用未定义和声明的函数,编译器只会发出警告
- 有时候需要写一个空函数,以便在后期的开发中实现相应的功能
-
函数的执行过程
- 调用函数,操作系统为函数分配一定空间的内存
- 在函数的内存空间定义形参,并将实参的值赋值给形参
- 对形参进行操作,完成指定功能
- 函数返回,操作系统撤销为函数分配的内存
-
示例
#include <stdio.h>
// 值传递
void swap1(int a, int b);
// 指针传递
void swap2(int *a, int *b);
// 引用传递
void swap3(int &a, int &b);
int main()
{
// 定义两个变量用于交换
int a = 10;
int b = 20;
// 值传递,不会改变a,b的值
swap1(a, b);
printf("a=%d, b=%d\n", a, b);
// 指针传递,会改变a,b的值
swap2(&a, &b);
printf("a=%d, b=%d\n", a, b);
// 引用传递,会改变a,b的值
swap3(a, b);
printf("a=%d, b=%d\n", a, b);
return 0;
}
// 值传递
void swap1(int a, int b)
{
//定义中间变量
int temp;
temp = a;
a = b;
b = temp;
}
//指针传递
void swap2(int *a, int *b)
{
//定义中间变量
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void swap3(int &a, int &b)
{
//定义中间变量
int temp;
temp = a;
a = b;
b = temp;
}
递归函数
- 递归函数注意事项
- 递归是函数反复调用自己
- 每个递归函数都必须有一个出口,一般通过改变参数来实现
- 符合堆栈规则,一般都可以使用递归
- 由于递归需要保持大量的中间数据,所以开销较大
- 迭代与递归的差别
- 迭代常常可以弥补递归开销较大的缺陷
- 迭代可以实现递归,反之不然
- 当递归带来的其他所有方面的好处足以弥补它开销大的缺陷时才使用递归,否则使用迭代