函数参数传递有两种方式:
传址调用:传递变量的地址,函数内通过指针可以修改原变量
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y); // 传址调用
// x=20, y=10
}
绝对不要返回局部变量的地址(函数结束后局部变量被销毁)
// 错误示例
int* wrong_func() {
int local = 10;
return &local; // 危险!局部变量地址
}
// 正确示例1:返回全局变量指针
int global_var = 100;
int* correct_func1() {
return &global_var;
}
// 正确示例2:返回动态分配内存
int* correct_func2() {
int *p = malloc(sizeof(int));
*p = 200;
return p; // 调用者负责free
}
函数指针是指向函数的指针变量,可以用于动态调用函数。
// 函数指针声明
int (*func_ptr)(int, int);
// 赋值
func_ptr = add;
// 调用
int result = func_ptr(3, 4);
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
// 函数指针数组
int (*ops[])(int, int) = {add, sub, mul};
将函数作为参数传递给另一个函数,实现灵活的行为定制。
#include <stdlib.h>
int compare(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int main() {
int arr[] = {5, 2, 8, 1, 9};
qsort(arr, 5, sizeof(int), compare);
}
Linux内核中广泛使用函数指针数组实现面向对象的多态。
// 基本语法
返回类型 (*函数指针名)(参数类型列表);
// 示例
int (*add_ptr)(int, int);
void (*print_ptr)(const char*);
// 定义回调类型
typedef int (*compare_func)(const void*, const void*);
// 使用回调
void sort(int *arr, int size, compare_func cmp) {
// 使用cmp进行比较
}
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void*, const void*));
#include <stdio.h>
// 传值调用:无效
void swap_by_value(int a, int b) {
int temp = a;
a = b;
b = temp;
printf("函数内: a=%d, b=%d\n", a, b);
}
// 传址调用:有效
void swap_by_address(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
printf("函数内: *a=%d, *b=%d\n", *a, *b);
}
int main() {
int x = 10, y = 20;
printf("调用前: x=%d, y=%d\n", x, y);
swap_by_value(x, y);
printf("传值调用后: x=%d, y=%d\n", x, y);
swap_by_address(&x, &y);
printf("传址调用后: x=%d, y=%d\n", x, y);
return 0;
}
编译命令:gcc -o pass_by_value_vs_address pass_by_value_vs_address.c
#include <stdio.h>
#include <stdlib.h>
// 危险:返回局部变量地址
int* dangerous_func() {
int local_var = 100;
return &local_var; // 未定义行为
}
// 正确:返回全局变量指针
int global_var = 200;
int* get_global_ptr() {
return &global_var;
}
// 正确:返回静态变量指针
int* get_static_ptr() {
static int static_var = 300;
return &static_var;
}
// 正确:返回动态分配内存
int* get_dynamic_mem(int value) {
int *p = (int*)malloc(sizeof(int));
if (p != NULL) {
*p = value;
}
return p;
}
int main() {
// 错误用法
// int *p1 = dangerous_func();
// printf("危险函数: %d\n", *p1); // 未定义行为
// 正确用法
int *p2 = get_global_ptr();
printf("全局变量: %d\n", *p2);
int *p3 = get_static_ptr();
printf("静态变量: %d\n", *p3);
int *p4 = get_dynamic_mem(400);
if (p4 != NULL) {
printf("动态内存: %d\n", *p4);
free(p4);
}
return 0;
}
编译命令:gcc -o return_pointer return_pointer.c
#include <stdio.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div_int(int a, int b) { return b != 0 ? a / b : 0; }
int main() {
// 函数指针声明与赋值
int (*operation)(int, int);
operation = add;
printf("3 + 4 = %d\n", operation(3, 4));
operation = sub;
printf("3 - 4 = %d\n", operation(3, 4));
operation = mul;
printf("3 * 4 = %d\n", operation(3, 4));
operation = div_int;
printf("3 / 4 = %d\n", operation(3, 4));
// 函数指针数组
int (*ops[])(int, int) = {add, sub, mul, div_int};
char *op_names[] = {"+", "-", "*", "/"};
for (int i = 0; i < 4; i++) {
printf("10 %s 5 = %d\n", op_names[i], ops[i](10, 5));
}
return 0;
}
编译命令:gcc -o function_pointer function_pointer.c
#include <stdio.h>
#include <stdlib.h>
// 比较函数:升序
int compare_asc(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
// 比较函数:降序
int compare_desc(const void *a, const void *b) {
return (*(int*)b - *(int*)a);
}
// 打印数组
void print_array(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// 通用排序函数
typedef int (*compare_func)(const void*, const void*);
void sort_array(int *arr, int size, compare_func cmp) {
qsort(arr, size, sizeof(int), cmp);
}
int main() {
int arr1[] = {5, 2, 8, 1, 9, 3};
int arr2[] = {5, 2, 8, 1, 9, 3};
int size = sizeof(arr1) / sizeof(arr1[0]);
printf("原始数组: ");
print_array(arr1, size);
sort_array(arr1, size, compare_asc);
printf("升序排序: ");
print_array(arr1, size);
sort_array(arr2, size, compare_desc);
printf("降序排序: ");
print_array(arr2, size);
return 0;
}
编译命令:gcc -o callback_qsort callback_qsort.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 模拟内核file_operations结构
struct file_operations {
int (*open)(const char *path);
int (*read)(int fd, void *buf, int count);
int (*write)(int fd, const void *buf, int count);
int (*close)(int fd);
};
// 模拟设备实现
static int my_open(const char *path) {
printf("打开设备: %s\n", path);
return 0;
}
static int my_read(int fd, void *buf, int count) {
printf("从设备读取 %d 字节\n", count);
strcpy((char*)buf, "设备数据");
return strlen("设备数据");
}
static int my_write(int fd, const void *buf, int count) {
printf("向设备写入: %s (%d字节)\n", (const char*)buf, count);
return count;
}
static int my_close(int fd) {
printf("关闭设备\n");
return 0;
}
// 操作表
struct file_operations my_fops = {
.open = my_open,
.read = my_read,
.write = my_write,
.close = my_close
};
// 使用操作表的通用函数
int device_operation(struct file_operations *fops, const char *path) {
int fd = fops->open(path);
char buf[100];
fops->read(fd, buf, sizeof(buf));
printf("读取到: %s\n", buf);
fops->write(fd, "Hello Device", 12);
fops->close(fd);
return 0;
}
int main() {
device_operation(&my_fops, "/dev/my_device");
return 0;
}
编译命令:gcc -o kernel_pattern kernel_pattern.c
Q1: 传值调用和传址调用有什么区别? A: 传值调用传递变量的副本,函数内修改不影响原变量;传址调用传递变量的地址,函数内通过指针可以修改原变量。传址调用效率更高(避免大结构体复制),且可以修改实参。
Q2: 函数返回指针时需要注意什么? A: 绝对不要返回局部变量的地址(函数结束后内存被释放)。应该返回全局变量、静态变量的指针,或动态分配的内存(调用者负责free)。
Q3: 什么是函数指针?有什么用途? A: 函数指针是指向函数的指针变量,可以用于动态调用函数。用途包括:回调模式、函数指针数组实现分发表、qsort等通用算法、模拟面向对象的多态。
Q4: 如何实现类似qsort的回调机制?
A: 定义函数指针类型,将比较函数作为参数传递。例如:typedef int (*compare_func)(const void*, const void*),然后将具体比较函数传入排序函数。
Q5: 内核中的file_operations模式是什么? A: 这是Linux内核中广泛使用的面向对象模式。通过结构体中的函数指针实现多态,不同设备驱动实现相同接口的函数。应用程序通过统一的系统调用接口操作不同设备。
#include <stdio.h>
#include <stdlib.h>
#include <string.h}
// 交换函数
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 比较函数
int compare(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
// 回调函数类型
typedef void (*callback_func)(int);
// 使用回调的函数
void process_array(int *arr, int size, callback_func cb) {
for (int i = 0; i < size; i++) {
cb(arr[i]);
}
}
// 回调实现:打印
void print_element(int x) {
printf("%d ", x);
}
// 回调实现:加倍
void double_element(int *x) {
*x *= 2;
}
int main() {
// 传址调用
int a = 10, b = 20;
printf("交换前: a=%d, b=%d\n", a, b);
swap(&a, &b);
printf("交换后: a=%d, b=%d\n", a, b);
// qsort使用
int arr[] = {5, 2, 8, 1, 9};
int size = 5;
qsort(arr, size, sizeof(int), compare);
printf("排序后: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 回调模式
process_array(arr, size, print_element);
printf("\n");
return 0;
}
编译命令:gcc -o function_demo function_demo.c
注意:代码示例中有一个语法错误(#include <string.h} 应该是 #include <string.h>),实际编译时需要修正。