C语言指针
前言
本节内容十分的重要,所以需要非常认真的对待,我也会可能的用最容易理解的方式进行讲解!!!
🧭 C语言指针终极详解——从零到精通,逐层击破!
指针是C语言的灵魂,但也是新手最头疼的部分。别怕!这篇教程将用 保姆级讲解 + 超多生活化比喻,带你彻底征服指针!
一、指针的本质——内存世界的「GPS坐标」
1. 内存就像快递柜
计算的内存被划分成无数个小格子(字节),每个格子有唯一编号(地址)。
- 变量:快递柜里的包裹📦(数据)
- 指针:记录包裹所在柜子编号的纸条📝
int num = 10;
// 假设num存放在编号0x1000的柜子
printf("变量地址:%p", &num); // 输出0x1000
2. 指针变量——专门存地址的「地址簿」
- 声明指针:告诉编译器这个本子记录哪种柜子的地址
重点:int *p; // 记录“整数柜”的地址 char *cp; // 记录“字符柜”的地址int *中的*表示这是一个指针变量,int指明指向的数据类型。
二、指针的「三步操作」——从入门到熟练
1. 第一步:给地址簿绑定柜子(赋值)
用&获取变量地址,存入指针:
int num = 99;
int *p = # // p里记下num的地址0x1000
2. 第二步:按地址找包裹(解引用)
用*访问指针指向的值:
printf("柜子里的值:%d", *p); // 输出99
*p = 200; // 修改柜子里的值 → num变成200
关键理解:
p是地址(0x1000)*p是地址里的值(200)
3. 第三步:指针的「关系网」
- 指针与指针:可以比较地址是否相同
int *p1 = # int *p2 = # if (p1 == p2) { // true,指向同一地址 printf("地址相同!"); }
三、NULL指针——避免「野指针」的保险锁
1. 什么是野指针?
指针未初始化时,存储的是随机地址(像胡乱写的假地址🗑️),访问会导致崩溃。
int *p; // 野指针!
*p = 10; // ❌ 危险!可能破坏其他数据
2. 安全初始化
int *p = NULL; // 初始化为空指针(地址0)
if (p != NULL) {
*p = 10; // 安全操作
}
重要规则:
- 访问
NULL指针会导致程序崩溃(如打开不存在的柜子) - 函数返回指针时,若出错常返回
NULL
四、指针算术——地址的「跳跃游戏」
指针加减法不是数学运算,而是按类型大小移动地址!
1. 基础规则
int arr[3] = {10, 20, 30};
int *p = &arr[0]; // p指向10
p++; // p跳转到&arr[1](地址+4,假设int占4字节)
printf("%d", *p); // 输出20
公式:新地址 = 原地址 ± n * sizeof(类型)
2. 遍历数组的高级技巧
int arr[5] = {1,2,3,4,5};
for(int *ptr=arr; ptr < arr+5; ptr++) {
printf("%d ", *ptr); // 输出1 2 3 4 5
}
解析:
arr是数组首地址(等价于&arr[0])arr+5是第6个元素的地址(结束条件)
五、指针与数组——「一体两面」的亲密关系
1. 数组名是常量指针
int arr[3] = {10,20,30};
printf("arr[1] = %d", *(arr + 1)); // 输出20
禁止操作:
arr++; // ❌ 数组名是常量,不能修改!
2. 指针模拟数组
int *p = arr;
p[1] = 99; // 等价于arr[1] = 99
底层原理:p[1]会被编译器转换为*(p + 1)
六、多级指针——「套娃」寻址
1. 二级指针(指针的指针)
int num = 100;
int *p = # // p存储num的地址
int **pp = &p; // pp存储p的地址
printf("num = %d", **pp); // 输出100
内存图示:
pp → p → num
2. 应用场景
- 动态二维数组
- 修改函数外的指针变量
七、函数与指针——「隔空取物」的魔法
1. 指针作为函数参数(传址调用)
void addTen(int *num) {
*num += 10; // 修改外部变量
}
int main() {
int x = 5;
addTen(&x); // x变成15
}
对比传值调用:
- 传值:函数内修改不影响外部变量
- 传址:通过指针直接修改内存
2. 返回指针的函数
int* createArray(int size) {
int *arr = (int*)malloc(size * sizeof(int));
return arr; // 返回动态数组指针
}
// 使用后必须释放内存!
int *myArr = createArray(10);
free(myArr);
致命错误:
int* dangerous() {
int num = 10;
return # // ❌ 返回局部变量地址!
}
解析:函数结束后局部变量内存被回收,指针变野指针!
八、指针的「死亡陷阱」——必须避免的错误
1. 操作越界指针
int arr[3] = {1,2,3};
int *p = &arr[3]; // ❌ 越界!arr最大索引是2
*p = 4; // 破坏未知内存
2. 误解指针类型
float f = 3.14;
int *p = (int*)&f; // 强制转换类型
printf("%d", *p); // 输出乱码!二进制解释不同
3. 忘记释放动态内存
int *arr = malloc(100 * sizeof(int));
// ...使用后...
free(arr); // 必须释放!
九、实战训练营——巩固指针技能
练习1:字符串反转
用指针实现字符串反转函数:
void reverseString(char *str) {
char *start = str;
char *end = str + strlen(str) - 1;
while (start < end) {
char temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
练习2:动态二维数组
用指针的指针创建二维数组:
int **matrix = malloc(3 * sizeof(int*));
for(int i=0; i<3; i++) {
matrix[i] = malloc(3 * sizeof(int));
}
// 使用后逐行释放
💡 终极总结口诀
指针即地址,变量门牌号。
声明带星号,类型要配套。
取址用&符,解引用星号。
算术按类型,数组关系妙。
函数传地址,返回谨慎保。
NULL防野针,内存泄漏要除掉!
学习建议:
- 多画内存图理解指针指向
- 写代码时添加注释说明指针作用
- 使用调试器观察指针地址变化
掌握指针,你就掌握了C语言的精髓!🚀任何问题欢迎随时交流,遇到问题多画内存图,理解会更深刻哦~
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Matou🚢!
评论


