下面通过一系列由浅入深的 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 语言高级编程的重要技巧。
通过以上例子,从最简单的返回静态数组,到动态内存分配,再到结构体成员函数指针,最后模拟图形工厂,可以全面理解这两个概念的区别与协作。