摘要
在学习 C 语言指针时,很多同学会卡在“指针数组”“二级指针”这些概念上,感觉代码能跑,但就是不知道有什么用。
本文通过一个学生成绩管理的小功能,把“指针数组”“指向指针的指针”真正用起来,结合完整代码,逐行解释指针的变化过程,让你明白:
- 指针数组到底解决了什么问题
- 为什么要用“指向指针的指针”
- 这种写法在真实程序中能做什么
如果你已经学过数组和一级指针,这篇文章可以帮你把知识真正串起来。
描述(实际使用场景)
假设我们在做一个学生成绩管理程序:
- 学校里有多个学生
- 每个学生的成绩单独存放
- 程序需要统一管理这些成绩数据,并依次输出
如果我们直接用二维数组,当然也能做,但灵活性不够。
真实项目里,不同学生的数据往往来自不同位置,这时候就非常适合用指针数组来管理。
于是我们可以这样设计:
- 用一个整型数组
a保存某个学生的成绩 - 用一个指针数组
num,每个元素都指向a中的某一个成绩 - 再用一个指向指针的指针
p,统一遍历这些指针
这和你给出的教材示例在逻辑上是完全一致的,只是换成了一个“能说清用途”的场景。
题解答案(思路说明)
实现思路可以分成四步:
- 定义一个整型数组
a,保存学生的成绩 - 定义一个指针数组
num,让它指向a中的每个元素 - 定义一个指向指针的指针
p,指向num的首元素 - 通过移动
p,间接访问并输出每一个成绩
这个过程看起来绕,但本质是:
用指针数组统一管理数据地址,再用二级指针进行遍历。
题解代码分析
完整代码
#include<stdio.h>intmain(){// 学生成绩数组inta[5]={1,3,5,7,9};// 指针数组,每个元素指向成绩数组中的一个元素int*num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};// 指向指针的指针int**p;inti;// 让 p 指向指针数组 num 的首元素p=num;// 遍历并输出成绩for(i=0;i<5;i++){printf("%d ",**p);p++;}printf("\n");return0;}关键代码逐行讲解
成绩数组
inta[5]={1,3,5,7,9};这一步很简单,相当于存了 5 个学生成绩。
指针数组的作用
int*num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};这里是重点。
num是一个数组- 数组里的每个元素都是
int * - 每个指针都指向成绩数组
a的一个元素
你可以把它理解成:
num 不是存成绩,而是存“成绩的地址”。
指向指针的指针
int**p;这表示:
p指向的是一个int *- 也就是说,
p指向的是num里的某一个元素
p 的初始化
p=num;这一步非常关键:
num代表指针数组首元素的地址p开始指向num[0]此时:
*p等价于num[0]**p等价于a[0]
输出逻辑
printf("%d ",**p);这是整个程序最容易让人迷糊的地方:
p指向num[i]*p得到&a[i]**p得到a[i]的值
指针移动
p++;每次p++:
- 指向下一个
num元素 - 间接访问下一个成绩
示例测试及结果
程序运行输出
1 3 5 7 9对应关系说明
| p 指向 | *p 的值 | **p 的值 |
|---|---|---|
| num[0] | &a[0] | 1 |
| num[1] | &a[1] | 3 |
| num[2] | &a[2] | 5 |
| num[3] | &a[3] | 7 |
| num[4] | &a[4] | 9 |
这样一对照,二级指针的逻辑就非常清楚了。
时间复杂度
- 程序中只有一次
for循环 - 循环次数为
n(这里是 5)
时间复杂度为:
O(n)空间复杂度
- 成绩数组
a占用n个整型空间 - 指针数组
num占用n个指针空间 - 额外只用了一个二级指针
p
空间复杂度为:
O(n)总结
这段代码真正想教你的不是“怎么多写几个星号”,而是:
指针数组适合用来管理多个分散的数据地址
二级指针非常适合统一遍历指针数组
这种写法在真实项目中很常见,比如:
- 命令行参数
argv - 多个字符串的统一管理
- 多个数据块的集中处理
- 命令行参数
如果你现在回头再看教材里的示例,会发现它不再是“为了考试而存在”,而是一个能直接迁移到真实项目里的思想。