mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6mobile wallpaper 7
2317 字
6 分钟
C语言指针复习指北
2026-06-27

一、内存与地址:数据的“住所”#

  • 计算机的内存可以看作一栋巨大的公寓楼。每个房间(内存单元)都有唯一的门牌号(地址),房间的大小是1字节。
  • 当你声明一个变量(如 int a;),系统会在这栋楼里为它预留连续的几个房间(int 型占4个房间),并在这个房间群里存放数据。
  • 变量的名字(如 a)是贴在房间门口的名牌,方便程序员识别;而变量的地址(如 0x1000)则是这个房间群在楼栋里的精确坐标。

二、指针的本质:存储“门牌号”的便签纸#

指针变量本身也是一个房间,但它里面不放普通的数据(如数字10),而是存放着另一个房间的门牌号(地址)

  • 声明指针int *p; 表示:“我要准备一张便签纸(变量p),这张便签纸将来只能记录‘存放整型数据’的房间的门牌号。”
  • 赋值操作p = &a; 表示:“把变量a的门牌号抄写在这张便签纸p上。”从此我们说p指向a

两个运算符的拟人化职责

  • &(取地址符):相当于问路。你对变量a说:“你的门牌号是多少?”它就会告诉你它的地址。
  • *(解引用符):相当于按图索骥。你拿着便签纸p,根据上面的门牌号找到那个房间,然后可以进去查看或修改房间里存放的物品(数据)。
int a = 10; // a是一个房间,里面住着数字10
int *p; // p是一个空便签纸
p = &a; // 把a的门牌号写在p上
printf("%d", *p); // 通过p找到a的房间,读出10
*p = 20; // 通过p找到a的房间,强行把里面的数字改成20

三、指针的运算:“向前走几步”#

指针的加减法不是简单的数字加减,而是有步长概念的。

  • 当指针p指向一个int型房间时,p + 1并不是地址值加1,而是地址值加上 sizeof(int)(通常是4)。这相当于让指针跳过当前这个房间群,直接移动到相邻的下一个同类型房间群
  • 这个特性使得指针非常适合遍历数组,因为数组就是连续排列的一排同类型房间。
int arr[3] = {100, 200, 300};
int *p = arr; // p指向arr[0]的房间
printf("%d", *(p+1)); // p+1跳过一个int的距离,找到arr[1],输出200

四、数组名:“隐姓埋名的地址”#

  • 数组名在大多数情况下(如赋值给指针时),会自动“褪去”数组的身份,表现为指向数组首元素的地址(即arr等价于&arr[0])。
  • 但数组名是个**“固执”的常量地址**,它不允许被修改指向(即不能写arr = p),因为它要永远忠实于自己那一排房间的起始位置。

等价关系

  • arr[i] 是“从起始房间向后数第i个房间里的数据”。
  • *(arr + i) 是“指针算术后解引用”,两者完全等价。

五、函数传参:“复印件”与“原件”的博弈#

5.1 传值调用(交出复印件)#

当函数被调用时,实参将自己的数值副本交给形参。此时形参在函数内部另开了新的房间,实参房间里的原数据毫发无伤。

  • 拟人化:你把一份文件的内容抄在另一张纸上交给助手,助手在复印件上涂改,原件依然干净。

5.2 传址调用(交出房间钥匙)#

当函数参数是指针时,我们传递的是实参的地址(门牌号)。函数内部通过这个门牌号找到实参的房间,进行直接修改。

  • 拟人化:你把房间的钥匙(地址)直接交给助手,助手进门把家具(数据)挪了位置,你回来后发现房间确实变了。
void swap(int *px, int *py) { // 收下两个门牌号
int temp = *px; // 顺着门牌号px找到房间,取出值
*px = *py; // 把py房间的值搬到px房间
*py = temp;
}
// 调用时必须传递变量的门牌号:swap(&a, &b);

六、多级指针:“便签纸的便签纸”#

  • 指针变量本身也是一个房间,也有自己的门牌号。如果另一个指针存放的是这个指针变量的门牌号,那么它就是一个二级指针
  • 拟人化:你在第一张便签纸(一级指针p)上写了变量a的门牌号。为了防止便签纸丢失,你又拿了一张新便签纸(二级指针pp),在上面写下了“第一张便签纸放在哪个抽屉里”的柜子号。
int a = 10;
int *p = &a; // p是便签纸,写着a的门牌
int **pp = &p; // pp是便签纸,写着p的门牌(即柜子号)
printf("%d", **pp); // 先找柜子取出p便签,再顺着p便签找到a房间,取出10

七、指针数组与数组指针(身份辨析)#

这是C语言中两个极易混淆的概念,关键在于识别运算符的优先级和结合性。

7.1 指针数组(int *p[3])——“存放多张便签的收纳盒”#

  • 身份认定:由于[]优先级高于*p先与[3]结合,表明它本质上是一个数组,只是数组里装的不是普通数字,而是3张指向int类型的便签(指针)。
  • 拟人化:这是一个有三层抽屉的收纳盒,每个抽屉里放着一张写有不同房间门牌号的纸条。

7.2 数组指针(int (*p)[3])——“指向一排房间的门牌”#

  • 身份认定:括号让p先与*结合,表明它本质上是一个指针,这个指针指向的是一个完整的、包含3个int元素的数组。
  • 拟人化:它不是一张普通的房间门牌,而是一整排联排别墅的起始门牌号。拿着它,你能定位到一整排房间。
int arr[3] = {1,2,3};
int (*p)[3] = &arr; // 注意:必须取整个数组的地址&arr
printf("%d", (*p)[1]); // 先找到整排房子,再取第1间,输出2

八、const与指针:“锁”的位置决定权限#

const像是一把锁,锁在指针的不同位置,限制的对象截然不同。

声明形式锁的位置(拟人解读)指针自身能否改指指向的内容能否改
const int *p;锁在房间里的物品可以(便签纸可擦写)不可以(物品被锁)
int * const p;锁在便签纸本身不可以(便签纸粘死)可以(物品随便挪)
const int * const p;两边都上了锁不可以不可以

记忆要点const*的左边,保护的是“所指之物”;const*的右边,保护的是“指针本身”。


九、函数指针:“指向一段流程的门牌”#

  • 函数在被编译后,也会占据内存中的一块区域用于存放指令,这块区域的起始地址就是函数的入口地址
  • 函数指针就是专门存放这个入口地址的变量。
  • 拟人化:函数名像是挂在某个办公室门口的牌子(入口地址)。你把这块牌子的编号抄下来(赋给函数指针),之后通过这个编号就能找到这间办公室,让里面的职员(函数体)开始工作。
int add(int x, int y) { return x + y; }
int main() {
int (*f)(int, int); // 声明一张便签,专门记“返回int,参数两个int”的办公室门牌
f = add; // 把add办公室的门牌抄下来
printf("%d", f(3, 5)); // 找到办公室,让职员计算3+5,输出8
return 0;
}

十、动态内存分配:“临时租用的房间”#

  • 普通变量(局部变量)的房间是在函数调用时由系统自动分配的,函数结束时会强制回收,房客必须搬走。
  • malloc函数相当于向操作系统这个“大房东”申请临时租用若干间连续的房间。租期由程序员决定,只要不主动free,这些房间就永远属于你。
  • free函数相当于退租,将房间归还给系统。如果退租后不把指向该区域的指针置为NULL,这个指针就成了野指针——它手里还攥着旧门牌号,但那片区域已经被房东收回去另作他用了,贸然闯入会导致程序崩溃。
#include <stdlib.h>
int *p = (int*)malloc(3 * sizeof(int)); // 申请3间连续的int房间
if (p != NULL) {
p[0] = 10;
free(p); // 退租
p = NULL; // 把废纸撕掉,防止误闯
}

十一、常见陷阱的警示#

  1. 野指针(迷路的门牌):声明了int *p;却未赋值,里面的值是内存残留的随机编号。你拿着这个随机编号去敲门,很可能敲到系统核心区域,操作系统会立刻终止程序(段错误)。
  2. 内存泄漏(只借不还):使用malloc申请了房间,但忘记调用free。程序长期运行,大房东会发现所有房间都被你占着却不退租,最终无房可租,程序卡死。
  3. 返回局部变量地址(过期的邀请函):函数内部的局部变量在函数结束后房间就被回收。如果你把它的地址返回给外部,外部拿到的是一张过期的门牌号,里面的数据随时可能被其他程序覆盖。

核心速查对照表#

操作意图代码形式
声明指向int的指针int *p;
取变量地址赋给指针p = &a;
解引用修改值*p = 100;
声明指向“数组(长度5)”的指针int (*p)[5];
声明“存放5个指针”的数组int *p[5];
声明指向函数的指针int (*f)(int, int);
动态申请连续内存(int*)malloc(n * sizeof(int));
释放并清空指针free(p); p = NULL;
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

C语言指针复习指北
https://blog.sherry.qzz.io/posts/c/c语言指针复习指北/
作者
Sherry
发布于
2026-06-27
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录