Computing · C Programming

Pointers

指针

~ 12 min · v8

指针 & 动态内存

cs-c/pointers · COMP1521
0 / 6

1 一句话定义

指针(pointer)就是一个存着"另一块内存的地址"的变量。

想象一张便利贴,上面写着"东西放在 12 号储物柜"。便利贴本身只是一张纸,但你顺着它能找到真正的东西。指针就是这张便利贴,解引用 *p 就是去 12 号柜子把东西取出来。

2 直觉模型 · 跟着代码一步步走

下面是一段最经典的指针代码。点 单步执行,看栈区变量、堆区分配块、指针箭头如何一步步变化。

内存可视化沙盘

栈区 Stack
堆区 Heap
步骤 0 / 9
点击"播放"或"单步"开始。这里会用大白话告诉你这一步在做什么、为什么这么做。
0
已分配字节
0
已释放字节
0
泄漏字节
0
悬空指针

3 核心要点 · 4 句话学会指针

每条要点都配最小例子。把鼠标悬停在代码上能看到逐字注解。

① 取地址:&
&x 读作"x 的地址"。栈上变量 x 住在某个房间,&x 就是那个房间的门牌号。
int x = 42; int *p = &x; // p 拿到 x 的门牌号
② 解引用:*
*p 读作"按 p 这个门牌号去拿东西"。修改 *p 等价于修改 x 本身。
*p = 100; // 现在 x 也变成 100 printf("%d", x); // 输出 100
③ malloc 拿一块堆内存
栈在函数返回后自动消失;如果你想要一块"长寿"内存,必须从堆要:malloc。
int *arr = malloc(10 * sizeof(int)); arr[0] = 7; // 像数组用
④ free 归还堆内存
堆不会自动收回。谁 malloc 谁 free,否则就是"内存泄漏"。
free(arr); arr = NULL; // 良好习惯:避免悬空

4 错误实验室 · 点一下亲眼看 bug

每个卡片是一种真实会让程序崩溃的错误。点击运行,下面控制台会模拟程序输出 / 段错误 / 内存泄漏检测。

NULL 解引用
访问空指针 SIGSEGV 段错误
悬空指针
free 之后还在用 未定义行为
内存泄漏
忘记 free 内存越用越多
双重释放
同一块内存 free 两次 堆崩溃
// 点击上方任一卡片,查看错误代码与运行效果
$ ./a.out (等待运行...)

5 即时小测 · 6 题验收

前 5 题点选项立即判定;第 6 题是压轴写码挑战——亲手写代码,逐步可视化运行,再提交判定。

去做例题:指针与堆 · 数组翻倍
去做例题
Q6.压轴挑战 · 亲手写一段最小指针程序
  1. 在栈上声明 int x 并赋初值 10。
  2. 声明 int *p,让它指向 x。
  3. 通过 *p 把 x 改成 42(必须用 *p,不能直接写 x = 42)。
  4. 用 malloc 申请能放 3 个 int 的堆内存,赋给指针 arr,并把 arr[0] 设为 7。
  5. 正确 free(arr) 并把 arr 置 NULL——结束时不能有泄漏或悬空指针。
支持的 C 语法子集(点开查看)
int x = 10; // 声明 int 变量 int *p; // 声明指针(未初始化) int *p = &x; // 声明并指向某变量 int *p = NULL; // 空指针 int *arr = malloc(3 * sizeof(int)); // 堆分配 p = &y; x = 5; p = NULL; // 赋值 *p = 42; // 解引用写入 arr[0] = 7; // 数组下标写入 free(arr); // 释放堆内存 // 以 // 开头是注释;每条语句以 ; 结尾
// 写代码后点"运行可视化",这里会高亮当前执行行
栈区 Stack
堆区 Heap
步骤 0 / 0
写完代码后点"运行可视化",这里会逐步解释每一步在做什么。
0
已分配字节
0
已释放字节
0
泄漏字节
0
悬空指针
$ ./a.out (等待运行...)

6 承上启下

键盘快捷键

单步前进
单步后退
Space
播放 / 暂停
R
重置当前演示
?
打开本帮助
Esc
关闭帮助

提示:把鼠标点进上方演示区再按键;在写码框里按 / 只移动光标。