1. 函数的基本概念
-
函数定义:完成特定功能的独立代码块
-
函数作用:
-
代码复用
-
模块化编程
-
提高可读性和可维护性
-
计算机的函数是一个固定的程序段,或称其为一个子程序。它在可以实现固定运算功能的同时,还带有一个入口和一个出口,所谓的入口,就是函数所带来的各个参数,可以通过这个入口,把函数的参数带入子程序,供计算机处理,所谓出口,就是指函数的函数值,在计算机求得之后,由此带回给调用它的程序。
2. 函数组成
返回类型 函数名(参数列表) {
// 函数体
[声明部分]
[执行语句]
[return 表达式;]
}
3. 函数声明与定义
-
函数声明(原型):
返回类型 函数名(参数类型列表);
例如:
int max(int a, int b);
-
函数定义:
返回类型 函数名(参数列表) { // 函数实现 }
4. 函数参数
-
形式参数(形参):函数定义时声明的参数
-
实际参数(实参):函数调用时传入的具体值
-
参数传递方式:
-
值传递(默认方式)
-
地址传递(通过指针)
-
实参的类型必须与对应的形象类型匹配,函数有几个形参,调用时就必须提供数量相同的实参。
5. 返回值
-
使用
return
语句返回一个值 -
返回值类型必须与函数声明类型一致(或可隐式转换)
-
无返回值函数使用
void
类型
6. 函数调用
-
一般形式:
函数名(实参列表);
-
调用方式:
-
作为表达式的一部分
-
作为独立语句
-
作为另一个函数的参数
-
7. 函数分类
7.1 按来源分
-
库函数(标准函数):如
printf()
,scanf()
-
用户自定义函数
7.2 按返回值分
-
有返回值函数
-
无返回值函数(void)
7.3 按参数分
-
有参函数
-
无参函数
8. 递归函数
-
函数直接或间接调用自身
-
必须包含递归终止条件
-
示例:阶乘计算
int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); }
9. 变量的作用域与存储类别
9.1 作用域
-
局部变量:函数内部定义,只在函数内有效
-
全局变量:函数外部定义,整个程序可见
9.2 存储类别
-
auto
:自动变量(默认) -
static
:静态变量(保持值不变) -
register
:寄存器变量(建议编译器将变量存储在寄存器中) -
extern
:外部变量(声明在其他文件中定义的变量)
10. 函数指针
-
指向函数的指针变量
-
声明形式:
返回类型 (*指针名)(参数类型列表);
-
示例:
int (*pFunc)(int, int); // 声明函数指针 pFunc = max; // 指向max函数 int result = pFunc(3,5); // 通过指针调用函数
11. 可变参数函数
-
参数数量可变的函数
-
使用
stdarg.h
头文件中的宏:-
va_list
:声明参数列表变量 -
va_start
:初始化参数列表 -
va_arg
:获取下一个参数 -
va_end
:清理参数列表
-
-
示例:实现一个简单的可变参数求和函数
#include <stdarg.h> int sum(int count, ...) { va_list args; va_start(args, count); int total = 0; for (int i = 0; i < count; i++) { total += va_arg(args, int); } va_end(args); return total; }
12. 内联函数
-
使用
inline
关键字声明 -
编译器尝试将函数调用替换为函数体代码
-
适用于短小、频繁调用的函数
-
示例:
inline int square(int x) { return x * x; }
13. 函数设计最佳实践
-
函数应保持单一职责原则
-
函数长度不宜过长(建议不超过一屏)
-
函数命名应清晰表达其功能
-
合理设计参数数量和返回值
-
避免使用全局变量进行函数间通信
-
对参数进行有效性检查
-
添加适当的注释说明函数用途和参数含义
14. 常用库函数示例
数学函数(math.h)
-
sqrt(x)
:平方根 -
pow(x,y)
:x的y次幂 -
sin(x)
,cos(x)
:三角函数
字符串函数(string.h)
-
strcpy(dest, src)
:字符串复制 -
strcat(dest, src)
:字符串连接 -
strcmp(s1, s2)
:字符串比较
输入输出函数(stdio.h)
-
printf()
:格式化输出 -
scanf()
:格式化输入 -
fgets()
:从文件/标准输入读取字符串
15. 函数与数组
-
数组作为函数参数时,实际传递的是数组首地址
-
示例:
void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } }
16. 函数与结构体
-
结构体可以作为函数参数和返回值
-
通常使用指针传递结构体以提高效率
-
示例:
struct Point { int x; int y; }; void printPoint(struct Point *p) { printf("(%d, %d)", p->x, p->y); }
17. 回调函数
-
通过函数指针实现的机制,允许一个函数调用另一个函数
-
常用于事件处理、排序算法等场景
-
示例:
void process(int (*callback)(int)) { int result = callback(10); printf("Result: %d\n", result); } int doubleNum(int x) { return x * 2; } // 调用 process(doubleNum);
18. main函数的特殊形式
int main(void) { ... } // 无参数形式
int main(int argc, char *argv[]) { ... } // 带命令行参数形式
20.注意
1.为什么需要函数?
函数的本质是可以被重复调用的、功能相对比独立的程序段。函数的引入实现了两个目的;一是便于结构化、模块化编程;二是解决代码的重复。
2. 避免函数副作用
-
理想情况下,函数应只通过参数和返回值通信
-
避免过度使用全局变量
3. 避免过长的函数
-
函数体不宜过长(通常不超过一屏)
-
过长的函数难以维护和理解
-
建议将大函数拆分为多个小函数