C 语言学习笔记——11(函数指针与指针函数)

下面通过一系列由浅入深的 C 语言例子,详细说明指针函数 (返回指针的函数)和函数指针(指向函数的指针)的区别与用法,最终结合结构体展示高级应用。


一、基础概念区分

术语 定义 示例声明
指针函数 一个函数,其返回值类型是指针 int* func();
函数指针 一个指针,它指向某个函数的入口 int (*p)(int);

二、指针函数(返回指针的函数)

例1:返回静态局部变量的地址(浅)

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

int* getPositive() {
    static int arr[] = {1, 2, 3};  // 静态数组,生命周期贯穿程序
    return arr;  // 返回数组首地址(int*)
}

int main() {
    int *p = getPositive();
    for (int i = 0; i < 3; i++) {
        printf("%d ", p[i]);  // 输出 1 2 3
    }
    return 0;
}

⚠️ 注意:绝不能返回局部普通变量的地址,因为函数结束后其内存被回收。使用 static 或动态分配内存是安全的。

例2:返回动态分配的内存地址(深一层)

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

char* duplicateString(const char* src) {
    if (!src) return NULL;
    char* dst = (char*)malloc(strlen(src) + 1);
    if (dst) strcpy(dst, src);
    return dst;  // 返回堆内存指针
}

int main() {
    char* msg = duplicateString("Hello, pointer function!");
    if (msg) {
        printf("%s\n", msg);
        free(msg);  // 记得释放内存
    }
    return 0;
}

三、函数指针(指向函数的指针)

例3:简单函数指针调用(浅)

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 (*p)(int, int);  // 声明函数指针,可指向返回int、两个int参数的函数
    
    p = add;
    printf("add: %d\n", p(5, 3));  // 输出8
    
    p = sub;
    printf("sub: %d\n", p(5, 3));  // 输出2
    
    return 0;
}

例4:函数指针作为函数参数(中)

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

// 定义一个操作类型:接收两个int,返回int
typedef int (*Operation)(int, int);

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }

// 高阶函数:接收一个操作函数指针
int calculate(int x, int y, Operation op) {
    return op(x, y);
}

int main() {
    printf("add: %d\n", calculate(10, 20, add));
    printf("mul: %d\n", calculate(10, 20, mul));
    return 0;
}

例5:结构体中的函数指针(中高)

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

// 定义"动物"结构体,包含数据成员和"方法"(函数指针)
typedef struct {
    char name[32];
    int age;
    void (*speak)(const char*);   // 函数指针,指向说话行为
} Animal;

// 具体的行为实现
void dogSpeak(const char* name) {
    printf("%s says: Woof! Woof!\n", name);
}
void catSpeak(const char* name) {
    printf("%s says: Meow~\n", name);
}

int main() {
    Animal dog = {"Buddy", 3, dogSpeak};
    Animal cat = {"Kitty", 2, catSpeak};
    
    dog.speak(dog.name);
    cat.speak(cat.name);
    return 0;
}

例6:结构体 + 函数指针 + 返回函数指针的指针函数(深)

场景:一个工厂函数,根据传入的类型返回对应的函数指针(即选择不同的行为)。

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

// 定义"计算器"函数指针类型
typedef int (*CalcFunc)(int, int);

// 具体算法
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; }

// 定义策略结构体,包含名称和对应的函数指针
typedef struct {
    char op[8];
    CalcFunc func;
} CalcStrategy;

// 指针函数:根据操作符字符串返回对应的函数指针
CalcFunc getCalculator(const char* op) {
    // 静态策略表(也可以动态创建,这里用静态数组)
    static CalcStrategy table[] = {
        {"add", add},
        {"sub", sub},
        {"mul", mul}
    };
    int size = sizeof(table) / sizeof(table[0]);
    for (int i = 0; i < size; i++) {
        if (strcmp(op, table[i].op) == 0) {
            return table[i].func;   // 返回函数指针
        }
    }
    return NULL;  // 未找到
}

int main() {
    CalcFunc f = getCalculator("mul");
    if (f) {
        printf("Result: %d\n", f(6, 7));  // 输出42
    }
    
    f = getCalculator("add");
    if (f) {
        printf("Result: %d\n", f(100, 200)); // 输出300
    }
    return 0;
}

例7:复杂结构体 + 函数指针作为成员 + 动态分发(最深度)

模拟一个简单的图形面积计算系统,使用结构体存储类型和计算面积的函数指针,并使用指针函数来创建不同的图形对象。

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

// 前置声明
typedef struct Shape Shape;

// 函数指针类型:计算面积的函数,参数为Shape*,返回double
typedef double (*AreaFunc)(const Shape*);

// 图形结构体:包含类型标识、特定数据(用union)和面积计算方法指针
struct Shape {
    int type;          // 0: circle, 1: rectangle
    union {
        struct { double radius; } circle;
        struct { double width, height; } rect;
    } data;
    AreaFunc area;     // 函数指针
};

// 具体面积实现
double circleArea(const Shape* s) {
    double r = s->data.circle.radius;
    return M_PI * r * r;
}

double rectangleArea(const Shape* s) {
    return s->data.rect.width * s->data.rect.height;
}

// 指针函数:创建圆形对象(返回Shape*)
Shape* createCircle(double radius) {
    Shape* s = (Shape*)malloc(sizeof(Shape));
    if (!s) return NULL;
    s->type = 0;
    s->data.circle.radius = radius;
    s->area = circleArea;
    return s;
}

// 指针函数:创建矩形对象
Shape* createRectangle(double w, double h) {
    Shape* s = (Shape*)malloc(sizeof(Shape));
    if (!s) return NULL;
    s->type = 1;
    s->data.rect.width = w;
    s->data.rect.height = h;
    s->area = rectangleArea;
    return s;
}

int main() {
    Shape* shapes[2];
    shapes[0] = createCircle(5.0);
    shapes[1] = createRectangle(4.0, 6.0);
    
    for (int i = 0; i < 2; i++) {
        if (shapes[i]) {
            printf("Area: %.2f\n", shapes[i]->area(shapes[i]));
            free(shapes[i]);
        }
    }
    return 0;
}

该例中:

  • 函数指针 area 作为结构体成员,实现多态。
  • 指针函数 createCircle / createRectangle 返回动态分配的 Shape* 指针。

四、总结

  • 指针函数:本质是函数,返回一个地址(指针)。常用于返回字符串、数组、结构体指针或动态内存。
  • 函数指针:本质是指针,保存函数的入口地址。用于回调函数、策略模式、动态绑定等。
  • 两者结合结构体,可以实现类似 C++ 中类的简单封装和多态行为,是 C 语言高级编程的重要技巧。

通过以上例子,从最简单的返回静态数组,到动态内存分配,再到结构体成员函数指针,最后模拟图形工厂,可以全面理解这两个概念的区别与协作。

相关推荐
妄汐霜8 小时前
小白学习笔记(MyBatis)
笔记·学习·mybatis
cch89188 小时前
汇编与C语言:底层对话VS高效指挥
c语言·开发语言·汇编
♪-Interpretation8 小时前
第七节:Python的内置容器
开发语言·python
承渊政道8 小时前
【优选算法】(实战:栈、队列、优先级队列高频考题通关全解)
数据结构·c++·笔记·学习·算法·leetcode·宽度优先
551只玄猫8 小时前
【数学建模 matlab 实验报告8】回归分析
开发语言·数学建模·matlab·课程设计·实验报告
盐焗西兰花8 小时前
鸿蒙学习实战之路-Share Kit系列(14/17)-手机间碰一碰分享实战
学习·智能手机·harmonyos
liulilittle8 小时前
OPENPPP2 1.0.0.26145 正式版发布:内核态 SYSNAT 性能飞跃 + Windows 平台避坑指南
开发语言·网络·c++·windows·通信·vrrp
arvin_xiaoting8 小时前
OpenClaw学习总结_II_频道系统_6:iMessage集成详解
学习