一、函数基本概念
1.1 函数定义
概念:把一个功能的实现流程封装起来,使用户留下接口进行调用
作用:参数创建该功能进行封装操作,返回值即通过功能显示的产出
1.2 函数组成要素
- 返回值类型:根据函数功能而定,需要在函数头中指定子程序类的返回值类型
- 参数名:在函数体中提取需要传递的变量
- 参数列表:对外声明的一个窗口,用于在获取需要传递什么参数到函数内
- 函数体:在函数头下的一对花括号内,具有自动生成的函数类属性
二、返回值
2.1 返回值作用
- 一般需要返回与功能关联的结果
- 指定变量的值直接传入函数
2.2 返回值类型
// 示例:返回整型值的函数
int add(int a, int b) {return a + b;// 返回计算结果
}
三、参数传递
3.1 值传递 (Pass by Value)
概念:将参数定义为所有变量类型的,在函数体内对参数进行任何修改
特点:不要修改原始参数,函数内操作的是参数的副本
void swap_by_value(int a, int b) {int temp = a;a = b;b = temp;// 只修改副本,不影响原始值
}
3.2 地址传递 (Pass by Reference/Address)
概念:把变量的地址作为输入函数
特点:在函数体中可以通过指针操作数据本身的值,因此可以修改传入的参数
void swap_by_reference(int *a, int *b) {int temp = *a;*a = *b;*b = temp;// 修改原始值
}
四、特殊函数类型
4.1 静态函数 (Static Functions)
符号:使用 static
关键字限制函数的可见范围
作用:减少函数名字冲突的概率
使用方法:
- 通过本文件的普通函数间接调用静态函数
- 获得静态函数的地址,后跟随该地址直接访问该函数
- 【推荐】把静态函数定义在头文件中,然后在所有需要用到的地方包含该头文件
// 在头文件中声明
static void helper_function(void)
{
// 静态函数实现
}
// 通过普通函数间接调用
void public_function(void) {helper_function();// 间接调用静态函数
}
4.2 回调函数 (Callback Functions)
概念:设计一个函数是供其他函数调用,由第三方间接调用
作用:可以方便与其他人做项目进行对接
使用场景:当我们设计一个功能的封装以满足要求条件来执行时,你可以留下一个接口让未来的使用对象具体地执行(函数的地址)
// 回调函数类型定义
typedef void (*callback_func)(int);// 接收回调函数的接口
void process_data(int data, callback_func callback) {
// 处理数据...callback(data);// 调用回调函数
}// 具体的回调函数实现
void my_callback(int result) {printf("处理结果: %d\n", result);
}
4.3 函数指针数组
概念:通过函数创建一个函数的内部存储空间自己的调用
作用:用于编写中需要保存的函数指针和语句的数据库,利用特殊性来对所有函数信息进行编译
// 函数指针类型定义
typedef void (*operation_func)(int);// 函数指针数组
operation_func operations[] = {function1,function2,function3,NULL
};// 遍历调用
void execute_operations(int value) {for (int i = 0; operations[i] != NULL; i++) {operations[i](value);}
}
五、字符串处理函数
5.1 内存操作函数 (memxxxx系列)
特点:直接操作内存,效率高
#include <string.h>
#include <stdlib.h>// 内存复制 - 处理重叠内存时使用
void *memmove(void *dest, const void *src, size_t n);// 内存复制 - 不处理重叠,效率更高
void *memcpy(void *dest, const void *src, size_t n);// 内存比较
int memcmp(const void *s1, const void *s2, size_t n);// 内存设置
void *memset(void *s, int c, size_t n);// 内存分配并初始化为0(建议使用calloc会初始化malloc不会)
void *calloc(size_t nmemb, size_t size);
// 内存重新分配
void *reallocarray(void *ptr, size_t nmemb, size_t size);// 内存分配
void *malloc(size_t size);
// 内存重新分配
void *realloc(void *ptr, size_t size);
5.2 字符串操作函数 (strxxx系列)
特点:专门处理以null结尾的字符串
#include <string.h>
// 字符串复制
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);// 字符串连接
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);// 字符串比较
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);// 字符串长度
size_t strlen(const char *s);// 查找字符
char *strchr(const char *s, int c); // 首次出现
char *strrchr(const char *s, int c); // 最后一次出现// 查找子串
char *strstr(const char *haystack, const char *needle);// 字符串分割
char *strtok(char *str, const char *delim);
5.3 注意事项
注意各函数之间的差异:
memxxxx
系列:操作指定字节数的内存块,不关心null终止符strxxxx
系列:操作以null结尾的字符串,自动处理字符串长度
六、函数设计最佳实践
6.1 函数接口设计原则
- 参数列表应该简洁明了
- 返回值应该明确表示函数执行结果
- 使用const修饰不希望被修改的参数
- 为函数提供清晰的文档注释
6.2 错误处理
// 返回错误码的函数示例
typedef enum {SUCCESS,INVALID_PARAM,MEMORY_ERROR,FILE_ERROR
} error_code_t;error_code_t process_file(const char *filename) {if (filename == NULL) {return INVALID_PARAM;}// 处理逻辑...return SUCCESS;
}
6.3 函数复用性
概念:在同一个进程中调用函数必须有一个直接连接的条件
建议:通过函数指针、回调机制等方式提高函数的复用性和灵活性