C语言指针进阶 学习笔记

📅 2026/7/30 10:02:23
C语言指针进阶 学习笔记
职坐标学习C语言指针进阶 学习笔记一、字符指针1. 核心概念定义char *ptr;指向字符类型数据的指针。基本用法可以指向单个字符也可以指向字符数组字符串。2. 字符串常量与字符数组 这是字符指针中最容易混淆的概念也是文档的重点。定义方式代码示例内存存储位置可修改性相同字符串地址字符指针const char *p hello;常量区 (只读)不可修改 (通过指针)相同 (指向同一块内存)字符数组char arr[] hello;栈区 (可读写)可修改不同 (各自开辟新内存)结论字符指针指向字符串常量后不能通过指针修改字符串内容如 *(p1) a; 会报错。C/C 会优化字符串常量相同的字符串常量在内存中只有一份所以不同指针指向相同字符串时地址是相同的。字符数组每次定义都会在栈上开辟新的内存块所以地址不同。3. 常量指针 vs 指针常量常量指针 (const char *p)含义指向常量的指针。特点指针指向的内容不能通过该指针修改但指针本身可以改变指向可以指向别的地址。代码示例 const char *p hello; // p[0] H; // 错误不能修改指向的内容 p world; // 正确指针可以指向新的地址指针常量 (char * const p)含义指针本身是常量。特点指针本身不能改变指向初始化后不能指向别处但可以通过指针修改指向的内容。代码示例const char *p hello;// p[0] H; // 错误不能修改指向的内容p world; // 正确指针可以指向新的地址二、指针数组与数组指针 这两个概念仅一字之差但含义完全不同。1. 指针数组定义数据类型 *数组名[长度]; (如 int *p[5];)本质是一个数组数组里的每个元素都是指针。内存存放了多个地址。用途常用于存储多个字符串或管理多个数组。代码示例int a 1, b 2;int *ptrArr[2] {a, b}; // 定义一个指针数组printf(%d, *ptrArr[0]); // 输出 12. 数组指针定义数据类型 (*指针名)[长度]; (如 int (*p)[5];)本质是一个指针指向一个数组。内存只存放一个地址数组的首地址。用途常用于操作二维数组。步长p1 跳过的是整个数组的大小例如 int[5] 跳过 20 字节。代码示例int arr[3] {1, 2, 3};int (*p)[3] arr; // 定义一个数组指针指向包含3个int的数组printf(%d, (*p)[0]); // 输出 1*p 解引用得到数组arr3. 快速区分口诀[] 优先级高于 *。int *p[5]p 先和 [] 结合所以是数组。int (*p)[5]() 强制 p 先和 * 结合所以是指针。三、数组参数与指针数组参数1. 数组传参在函数参数中int arr[]、int arr[10] 和 int *arr 本质上是等价的都退化为指向首元素的指针。2. 指针数组传参形式1void func(int *arr[], int len) —— 明确表示是指针数组。形式2void func(int **ptr, int len) —— 使用二级指针接收。原因指针数组名代表首元素地址而首元素本身就是一个指针int*所以数组名的类型是 int**。代码示例void printPtrArray(int **p, int len) {for(int i 0; i len; i) {printf(%d , *p[i]); // 通过二级指针访问}}}四、函数指针与指针函数1. 函数指针定义指向函数的指针。语法返回值类型 (*指针变量名)(参数列表);示例int (*p)(int, int) getMax;调用(*p)(1, 2) 或 p(1, 2)。代码示例int add(int a, int b) { return a b; }int main() {int (*func_ptr)(int, int) add; // 定义并赋值int result func_ptr(3, 4); // 通过指针调用printf(%d, result); // 输出 7return 0;}2. 指针函数定义返回值是指针的函数。语法返回值类型* 函数名(参数列表);示例int* func(int a);注意不能返回局部变量的地址因为函数结束时局部变量会被销毁通常返回静态变量、全局变量或堆内存的地址。代码示例int* getStaticAddr() {static int num 100; // 必须是static或全局变量return num; // 返回静态变量的地址}3. 对比速记函数指针本质是指针指向函数。指针函数本质是函数返回指针。五、回调函数1. 概念通过函数指针调用的函数。把函数的指针地址作为参数传递给另一个函数当这个指针被用来调用其所指向的函数时就称为回调。2. 实现步骤1.定义回调函数类型使用 typedef 定义函数指针类型。typedef void (*CallbackType)(int);2.实现具体的回调函数编写实际功能的函数如 void myFunc(int t)3.编写接收回调的函数该函数的参数包含回调函数指针。void doWork(CallbackType cb, int t) { cb(t); }4.调用在 main 函数中将具体函数名作为参数传递。3. 代码示例#include stdio.h// 1. 定义回调函数类型typedef void (*CookingCallback)(int);// 2. 实现具体的回调函数void makeFish(int time) {printf(清蒸鱼蒸 %d 分钟\n, time);}void makeMeat(int time) {printf(红烧肉炖 %d 分钟\n, time);}// 3. 编写接收回调的函数void startCooking(CookingCallback callback, int time) {printf(起锅烧油...\n);callback(time); // 调用传进来的函数printf(出锅\n);}int main() {// 4. 调用startCooking(makeFish, 10); // 传入 makeFish 函数startCooking(makeMeat, 60); // 传入 makeMeat 函数return 0;}六、核心知识点速记卡知识点关键总结字符指针char *p str 指向常量区不可改char arr[] 在栈区可改。指针数组int *p[5]数组存指针常用于存多个字符串。数组指针int (*p)[5]指针指数组常用于二维数组传参。函数指针int (*p)(int)指向函数的指针实现多态/回调。指针函数int* func()返回地址的函数勿返局部变量地址。回调函数函数指针作为参数传递实现“策略模式”或解耦。二级指针int **p用于接收指针数组名或修改一级指针的指向。学习建议区分优先级重点练习 * 和 []、() 的结合优先级这是区分“指针数组”和“数组指针”、“函数指针”和“指针函数”的关键。理解内存画图理解字符串常量在常量区而数组在栈区这解释了为什么一个能改一个不能改。实战回调尝试写一个简单的计算器或排序算法如 qsort 的比较函数体会回调函数的灵活性。