C语言-指针函数和函数指针

发布于:2025-05-16 ⋅ 阅读:(16) ⋅ 点赞:(0)

在C语言中,"指针函数"和"函数指针"是容易混淆但完全不同的概念。以下是详细的技术解析:


一、指针函数(返回指针的函数)
定义:返回指针类型的函数
声明格式:返回值类型* 函数名(参数列表)
作用:用于返回内存地址(指针),常用于动态内存分配和数据结构操作

// 返回整型指针的函数
int* create_int_array(int size) {
    int *arr = (int*)malloc(size * sizeof(int));
    return arr;  // 返回动态分配的数组首地址
}

// 返回字符串指针的函数
char* get_greeting() {
    return "Hello, World!";  // 返回字符串常量地址
}

典型应用场景:

  1. 工厂模式创建对象
  2. 内存分配函数(如malloc)
  3. 链表/树节点创建函数

注意事项:

// 错误示例:返回局部变量地址
int* dangerous_func() {
    int local = 100;
    return &local;  // 局部变量在函数结束后被销毁,返回的指针失效
}

二、函数指针(指向函数的指针)
定义:指向函数入口地址的指针变量
声明格式:返回值类型 (*指针名)(参数列表)
作用:实现回调机制、函数动态调用、策略模式等高级功能

// 声明函数指针类型
typedef int (*MathFunc)(int, int);

// 函数指针的使用示例
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

int main() {
    MathFunc operation = add;
    printf("3+5=%d\n", operation(3,5));  // 输出8
    
    operation = sub;
    printf("8-3=%d\n", operation(8,3));  // 输出5
    return 0;
}

典型应用场景:

  1. 事件处理回调(如GUI编程)
  2. 函数表驱动开发(如状态机)
  3. 动态库函数调用(dlopen/dlsym)
  4. 排序算法中的比较函数(qsort)

复杂声明解析:

// 解读:signal是函数,参数int和void(*)(int),返回void(*)(int)
void (*signal(int sig, void (*handler)(int)))(int);

// 使用typedef简化
typedef void (*SigHandler)(int);
SigHandler signal(int sig, SigHandler handler);

三、对比表格

特征 指针函数 函数指针
本质 返回指针的函数 指向函数的指针变量
声明重点 int* func() 星号在返回值位置 int (*func_ptr)() 星号在变量名旁
内存占用 函数代码段 指针变量(通常4/8字节)
典型用途 资源创建/获取地址 动态调用/回调机制
操作权限 定义函数逻辑 仅能调用指向的函数
赋值方式 函数返回值自动赋值 需显式赋值函数地址

四、高级用法示例

  1. 函数指针数组(命令模式)
void start() { printf("Starting...\n"); }
void stop() { printf("Stopping...\n"); }
void reboot() { printf("Rebooting...\n"); }

int main() {
    void (*commands[])() = {start, stop, reboot};
    
    int choice;
    printf("Enter command (0-start, 1-stop, 2-reboot): ");
    scanf("%d", &choice);
    
    if(choice >=0 && choice <=2) {
        commands[choice]();  // 动态调用
    }
    return 0;
}
  1. 结合结构体(策略模式)
typedef struct {
    float (*calc)(float, float);  // 计算策略
    char symbol;                  // 运算符
} Operation;

float add(float a, float b) { return a + b; }
float multiply(float a, float b) { return a * b; }

int main() {
    Operation ops[] = {
        {add, '+'},
        {multiply, '*'}
    };
    
    for(int i=0; i<2; i++) {
        float res = ops[i].calc(3.5, 2);
        printf("3.5 %c 2 = %.1f\n", ops[i].symbol, res);
    }
    return 0;
}
  1. 回调函数(事件处理)
// 注册回调函数类型
typedef void (*EventCallback)(int event_type);

// 事件处理器
void event_handler(int event) {
    printf("Received event: %d\n", event);
}

// 模拟事件触发函数
void trigger_event(EventCallback cb) {
    cb(1001);  // 触发事件
}

int main() {
    trigger_event(event_handler);
    return 0;
}

五、核心注意事项

  1. 函数指针类型匹配:

    int func1(char) {...}
    void func2(int) {...}
    
    int (*fp1)(char) = func1;  // 正确
    int (*fp2)(int) = func1;   // 警告:参数类型不匹配
    void (*fp3)(int) = func2;  // 正确
    
  2. 现代C的改进:

    // C11新增的类型安全写法
    int (*fp)(int) = &func;  // 显式取地址
    int result = (*fp)(10);  // 标准调用方式
    
  3. 调试技巧:

    printf("Function address: %p\n", (void*)fp);  // 打印函数地址
    
  4. 跨平台问题:

    // Windows的__stdcall调用约定
    typedef int (__stdcall *WinAPIProc)(int);
    

掌握这两个概念的区分和使用,是理解C语言高级编程(如操作系统开发、驱动程序开发)的关键基础。建议通过实际项目(如实现命令行解析器、设计插件系统等)来加深理解。


网站公告

今日签到

点亮在社区的每一天
去签到