此文用来记录
好的,我们来仔细讲 C语言指针,它是C语言最核心也最“魔法”的概念之一。为了理解,我会从用处和表现形式两方面解释,并配上例子。
一、指针的用处(为什么需要指针)
- 直接操作内存
- 指针就是一个变量,但它存储的不是数据本身,而是数据在内存中的地址。
- 通过指针可以直接访问和修改内存中的数据。
- 用途:提高效率、操作数组或大型数据结构而不必复制数据。
int a = 10; int *p = &a; // p保存了a的地址 *p = 20; // 通过指针修改a printf("%d\n", a); // 输出20 - 函数间共享数据 / 传递引用
- 在C中,函数参数默认是“值传递”,函数内修改不会影响原变量。
- 如果想让函数修改外部变量,就需要传入指针(地址)。
void addOne(int *x) { (*x)++; } int main() { int n = 5; addOne(&n); printf("%d\n", n); // 输出6 } - 动态内存管理
- 指针可以和
malloc、free一起使用,动态申请和释放内存。 - 用途:创建数组、链表、树等灵活数据结构。
int *arr = (int*)malloc(5 * sizeof(int)); for(int i=0;i<5;i++) arr[i] = i; free(arr); // 使用完记得释放 - 指针可以和
- 构建复杂数据结构
- 链表、树、图等数据结构都依赖指针来连接节点。
- 例如链表节点:
typedef struct Node { int data; struct Node *next; } Node; - 函数指针和回调
- 可以保存函数地址,实现回调和策略模式。
void sayHello() { printf("Hello\n"); } void (*funcPtr)() = sayHello; funcPtr(); // 调用函数
二、指针的表现形式(指针长什么样)
- 声明指针
int *p; // p是指向int类型的指针 char *c; // c是指向char类型的指针 double *d; // d是指向double类型的指针 - 获取地址
- 使用
&运算符获取变量地址。
int a = 10; int *p = &a; // p存的是a的地址 - 使用
- 访问指针指向的数据
- 使用
*解引用(dereference)操作符。
printf("%d\n", *p); // 输出10 *p = 20; // 修改a - 使用
- 指针运算
- 指针可以加减整数(按类型大小移动内存地址)。
int arr[3] = {1,2,3}; int *p = arr; // 指向arr[0] printf("%d\n", *(p+2)); // 输出3 - NULL指针
- 指针未指向有效地址时可以设为
NULL,防止野指针。
int *p = NULL; if(p != NULL) *p = 10; // 避免访问非法内存 - 指针未指向有效地址时可以设为
总结
| 方面 | 内容 |
|---|---|
| 用处 | 操作内存、共享数据、动态内存、数据结构、函数回调 |
| 表现形式 | 指针变量(int *p)、获取地址(&a)、解引用(*p)、指针运算、NULL指针 |
💡 小提示:
指针的核心就是“变量的地址”,一旦理解了“地址”和“解引用”,你就能理解大部分C语言高级技巧。
如果你愿意,我可以画一张 指针的图解,让你直观理解“变量、地址、指针、解引用”之间的关系,看一眼就明白。
void sayHello() { printf("Hello\n"); }
void (*funcPtr)() = sayHello;
funcPtr(); // 调用函数 ,,这是什么意思?平常起的作用是什么?
好的,我们来详细拆解你写的这段 函数指针代码,弄清楚它是什么意思、平常有什么用。
代码回顾
void sayHello() {
printf("Hello\n");
}
void (*funcPtr)() = sayHello;
funcPtr(); // 调用函数
一、逐行解析
- 定义一个普通函数
void sayHello() {
printf("Hello\n");
}
sayHello是一个函数,功能是打印"Hello\n"。- 返回类型是
void,没有参数。
- 定义函数指针并赋值
void (*funcPtr)() = sayHello;
- 这里出现了 函数指针。
void (*funcPtr)()的意思:funcPtr是一个指针变量;- 它指向的函数 返回类型是
void,参数为空。
= sayHello是把sayHello函数的地址赋给指针。- 这样
funcPtr就“指向”了sayHello函数。
⚠️ 注意:函数名 sayHello 本身就是函数的地址,不需要加 &,C语言里函数名会自动转换成地址。
- 通过指针调用函数
funcPtr();
funcPtr指向sayHello,加上()就相当于调用sayHello()。- 输出结果是:
Hello
二、函数指针的作用
- 动态选择函数
- 你可以在运行时决定调用哪个函数,而不是写死。
void add() { printf("Add\n"); } void sub() { printf("Sub\n"); } void (*op)(); if(userChoice == 1) op = add; else op = sub; op(); // 动态调用 - 回调函数
- 常用于库函数或API中,让调用者提供自己要执行的函数。
void timer(void (*callback)()) { // 一秒后调用callback callback(); } - 函数数组 / 表驱动
- 用函数指针数组快速选择处理逻辑,避免大量
if/else。
void func1() { printf("1\n"); } void func2() { printf("2\n"); } void (*funcs[2])() = {func1, func2}; funcs[1](); // 调用 func2 - 用函数指针数组快速选择处理逻辑,避免大量
- 实现多态 / 策略模式(在C语言里)
- 不同的行为可以通过指针动态绑定,不用改调用代码。
✅ 总结:
funcPtr就像是函数的“遥控器”,可以随时指向某个函数,然后通过它去调用函数。- 平常用途:
- 动态选择函数
- 回调机制
- 表驱动 / 策略模式
如果你想,我可以画一张 函数指针图解,直观展示“函数、地址、指针、调用”的关系,比文字容易理解

Comments NOTHING