C语言函数指针解析

C语言函数指针解析

一、函数指针的本质

函数指针是存储函数内存地址的变量,它允许程序在运行时动态调用不同的函数。与数据指针不同,函数指针指向的是可执行代码段。

c 复制代码
/* 典型声明方式 */
int (*func_ptr)(int, int);  // 可指向任何接受两个int参数且返回int的函数

二、核心语法详解

1. 声明与初始化

函数指针的声明必须与目标函数签名严格匹配:

c 复制代码
#include <stdio.h>

// 基础函数定义
int Add(int a, int b) { return a + b; }
int Sub(int a, int b) { return a - b; }

int main() {
    // 初始化方式(两种等效)
    int (*fp1)(int, int) = Add;   // 直接赋值
    int (*fp2)(int, int) = &Sub;  // 取地址赋值
    
    printf("5+3=%d\n", fp1(5, 3));  // 输出8
    printf("5-3=%d\n", (*fp2)(5, 3)); // 输出2
    
    return 0;
}

2. 类型定义简化

使用typedef提升代码可读性:

c 复制代码
typedef int (*ArithmeticFunc)(int, int);

ArithmeticFunc fp = Add;  // 简化后的声明

三、实际应用场景

1. 回调函数实现

函数指针最常见的用途是实现回调机制:

c 复制代码
// 回调函数类型定义
typedef void (*Logger)(const char*);

// 业务函数
void ProcessData(int data, Logger log) {
    char buf[50];
    sprintf(buf, "Processing: %d", data);
    log(buf);  // 通过函数指针回调
}

// 具体回调实现
void ConsoleLogger(const char* msg) {
    printf("[LOG] %s\n", msg);
}

int main() {
    ProcessData(42, ConsoleLogger);  // 输出:[LOG] Processing: 42
    return 0;
}

2. 函数指针数组

创建可扩展的操作表:

c 复制代码
ArithmeticFunc operations[] = {
    Add,
    Sub,
    [](int a, int b) { return a * b; },  // 注意:此lambda语法为C++特性,纯C需替换为具名函数
    [](int a, int b) { return a / b; }
};

// 纯C替代方案
int Multiply(int a, int b) { return a * b; }
int Divide(int a, int b) { return a / b; }
ArithmeticFunc c_operations[] = {Add, Sub, Multiply, Divide};

四、工程实践建议

1. 错误预防

c 复制代码
/* 必须检查空指针 */
if (func_ptr != NULL) {
    func_ptr(1, 2);
}

/* 避免签名不匹配 */
// int WrongFunc(float a, float b); 
// func_ptr = WrongFunc;  // 编译错误!

2. 典型应用案例

c 复制代码
/* 标准库qsort用法 */
#include <stdlib.h>
int CompareInt(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {5, 2, 9, 1};
    qsort(arr, 4, sizeof(int), CompareInt);
    // 排序结果:1, 2, 5, 9
    return 0;
}

五、总结对比

特性 函数指针 普通函数调用
运行时灵活性 可在运行时改变指向 编译期固定
性能开销 无额外开销 无额外开销
典型用途 回调/插件/策略模式 直接功能实现

提示:在C++中可考虑更安全的std::function,但在C项目中函数指针仍是核心机制。