C语言函数完全指南
编程小白也能理解的函数知识点汇总
函数是C语言程序的基本构建块,理解函数是掌握C语言的关键一步
什么是函数?
函数就像一个独立的机器,它接受输入(参数),执行特定任务,然后返回结果。
为什么要用函数?
- 代码复用:一次编写,多次使用
- 模块化:将大程序分解成小模块
- 易于维护:修改一处,影响全局
- 抽象化:隐藏实现细节,简化调用
函数的基本结构
返回类型 函数名(参数列表) {
// 函数体 – 执行任务的代码
return 返回值; // 可选
}
// 函数体 – 执行任务的代码
return 返回值; // 可选
}
示例:加法函数
int add(int a, int b) {
int result = a + b;
return result;
}
int result = a + b;
return result;
}
函数声明与定义
函数声明
告诉编译器函数的存在(函数原型)
int add(int a, int b); // 声明
函数定义
实现函数的具体功能
int add(int a, int b) { // 定义
return a + b;
}
return a + b;
}
声明通常放在头文件(.h)中,定义放在源文件(.c)中
参数传递:传值 vs 传引用
传递方式 | 特点 | 示例 | 何时使用 |
---|---|---|---|
传值 (Pass by Value) | 传递原始数据的副本,函数内修改不影响原始数据 | void modify(int x) { x = 10; } | 当不需要修改原始数据时 |
传引用 (Pass by Reference) | 传递内存地址,函数内修改直接影响原始数据 | void modify(int *x) { *x = 10; } | 需要修改原始数据或处理大型数据时 |
实际应用示例
// 传值示例
void swap_by_value(int a, int b) {
int temp = a;
a = b;
b = temp;
}
// 传引用示例
void swap_by_ref(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void swap_by_value(int a, int b) {
int temp = a;
a = b;
b = temp;
}
// 传引用示例
void swap_by_ref(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
main() 函数
x = 5, y = 10
x = 5, y = 10
swap() 函数
a = 0x1000, b = 0x1004
a = 0x1000, b = 0x1004
printf() 函数
格式化输出
格式化输出
函数调用栈可视化
当函数被调用时,系统会为其在内存中分配一个栈帧
- 每个函数调用有自己的栈帧
- 栈帧存储参数、局部变量和返回地址
- 函数结束后,其栈帧被释放
递归函数
函数调用自身的过程称为递归
递归三要素
- 递归结束条件(避免无限递归)
- 每次递归问题规模减小
- 递归调用自身
示例:计算阶乘
int factorial(int n) {
// 结束条件
if (n == 0 || n == 1)
return 1;
// 递归调用
return n * factorial(n – 1);
}
// 结束条件
if (n == 0 || n == 1)
return 1;
// 递归调用
return n * factorial(n – 1);
}
递归虽简洁,但可能消耗大量栈空间,可能导致栈溢出
函数指针
指向函数的指针变量,可用于实现回调函数
声明函数指针
// 声明一个指向函数的指针
// 该函数接受两个int参数,返回int
int (*operation)(int, int);
// 该函数接受两个int参数,返回int
int (*operation)(int, int);
使用函数指针
int add(int a, int b) { return a+b; }
int sub(int a, int b) { return a-b; }
int main() {
int (*operation)(int, int);
operation = add; // 指向add函数
printf(“5+3=%d”, operation(5,3)); // 输出8
operation = sub; // 指向sub函数
printf(“5-3=%d”, operation(5,3)); // 输出2
}
int sub(int a, int b) { return a-b; }
int main() {
int (*operation)(int, int);
operation = add; // 指向add函数
printf(“5+3=%d”, operation(5,3)); // 输出8
operation = sub; // 指向sub函数
printf(“5-3=%d”, operation(5,3)); // 输出2
}
作用域规则
局部变量
- 在函数内部声明
- 只在声明它的函数内可见
- 函数退出时被销毁
全局变量
- 在所有函数的外部声明
- 整个程序可见
- 程序结束时才销毁
int global = 10; // 全局变量
void func() {
int local = 5; // 局部变量
// 可以访问global和local
}
int main() {
// 可以访问global
// 不能访问func的local变量
}
void func() {
int local = 5; // 局部变量
// 可以访问global和local
}
int main() {
// 可以访问global
// 不能访问func的local变量
}
常用库函数示例
函数类别 | 常用函数 | 作用 | 头文件 |
---|---|---|---|
输入输出 | printf(), scanf() | 格式化输入输出 | stdio.h |
字符串处理 | strlen(), strcpy() | 字符串操作 | string.h |
数学函数 | sqrt(), pow() | 数学计算 | math.h |
内存管理 | malloc(), free() | 动态内存分配 | stdlib.h |
字符处理 | isalpha(), tolower() | 字符分类和转换 | ctype.h |
常见错误与最佳实践
常见错误
- 函数声明与定义不一致
- 忘记返回非void函数的返回值
- 递归没有终止条件导致栈溢出
- 在函数返回后使用局部变量的地址
- 函数参数类型不匹配
最佳实践
- 保持函数功能单一(一个函数完成一个任务)
- 函数名应准确描述其功能
- 限制函数的长度(通常不超过一屏)
- 为函数和参数添加注释说明
- 优先选择传引用方式处理大型数据结构
- 使用const保护不修改的参数