从“看不懂”到“能用”:一次搞清 C 语言指针数组

摘要

在学习 C 语言指针时,很多同学会卡在"指针数组""二级指针"这些概念上,感觉代码能跑,但就是不知道有什么用。

本文通过一个学生成绩管理的小功能,把"指针数组""指向指针的指针"真正用起来,结合完整代码,逐行解释指针的变化过程,让你明白:

  • 指针数组到底解决了什么问题
  • 为什么要用"指向指针的指针"
  • 这种写法在真实程序中能做什么

如果你已经学过数组和一级指针,这篇文章可以帮你把知识真正串起来。

描述(实际使用场景)

假设我们在做一个学生成绩管理程序

  • 学校里有多个学生
  • 每个学生的成绩单独存放
  • 程序需要统一管理这些成绩数据,并依次输出

如果我们直接用二维数组,当然也能做,但灵活性不够。

真实项目里,不同学生的数据往往来自不同位置 ,这时候就非常适合用指针数组来管理。

于是我们可以这样设计:

  • 用一个整型数组 a 保存某个学生的成绩
  • 用一个指针数组 num,每个元素都指向 a 中的某一个成绩
  • 再用一个指向指针的指针 p,统一遍历这些指针

这和你给出的教材示例在逻辑上是完全一致的,只是换成了一个"能说清用途"的场景。

题解答案(思路说明)

实现思路可以分成四步:

  1. 定义一个整型数组 a,保存学生的成绩
  2. 定义一个指针数组 num,让它指向 a 中的每个元素
  3. 定义一个指向指针的指针 p,指向 num 的首元素
  4. 通过移动 p,间接访问并输出每一个成绩

这个过程看起来绕,但本质是:

用指针数组统一管理数据地址,再用二级指针进行遍历。

题解代码分析

完整代码

c 复制代码
#include <stdio.h>

int main()
{
    // 学生成绩数组
    int a[5] = {1, 3, 5, 7, 9};

    // 指针数组,每个元素指向成绩数组中的一个元素
    int *num[5] = { &a[0], &a[1], &a[2], &a[3], &a[4] };

    // 指向指针的指针
    int **p;
    int i;

    // 让 p 指向指针数组 num 的首元素
    p = num;

    // 遍历并输出成绩
    for (i = 0; i < 5; i++)
    {
        printf("%d ", **p);
        p++;
    }

    printf("\n");
    return 0;
}

关键代码逐行讲解

成绩数组
c 复制代码
int a[5] = {1, 3, 5, 7, 9};

这一步很简单,相当于存了 5 个学生成绩。

指针数组的作用
c 复制代码
int *num[5] = { &a[0], &a[1], &a[2], &a[3], &a[4] };

这里是重点

  • num 是一个数组
  • 数组里的每个元素都是 int *
  • 每个指针都指向成绩数组 a 的一个元素

你可以把它理解成:

num 不是存成绩,而是存"成绩的地址"。

指向指针的指针
c 复制代码
int **p;

这表示:

  • p 指向的是一个 int *
  • 也就是说,p 指向的是 num 里的某一个元素
p 的初始化
c 复制代码
p = num;

这一步非常关键:

  • num 代表指针数组首元素的地址

  • p 开始指向 num[0]

  • 此时:

    • *p 等价于 num[0]
    • **p 等价于 a[0]
输出逻辑
c 复制代码
printf("%d ", **p);

这是整个程序最容易让人迷糊的地方:

  • p 指向 num[i]
  • *p 得到 &a[i]
  • **p 得到 a[i] 的值
指针移动
c 复制代码
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)

总结

这段代码真正想教你的不是"怎么多写几个星号",而是:

  1. 指针数组适合用来管理多个分散的数据地址

  2. 二级指针非常适合统一遍历指针数组

  3. 这种写法在真实项目中很常见,比如:

    • 命令行参数 argv
    • 多个字符串的统一管理
    • 多个数据块的集中处理

如果你现在回头再看教材里的示例,会发现它不再是"为了考试而存在",而是一个能直接迁移到真实项目里的思想

相关推荐
gao_shengping6 小时前
Queue(队列)两组增删查操作的区别
java·开发语言
发疯幼稚鬼6 小时前
归并排序与快速排序
c语言·数据结构·算法·排序算法
weixin_307779136 小时前
Jenkins Pipeline: Multibranch 插件详解:现代CI/CD的多分支管理利器
运维·开发语言·自动化·jenkins·etl
Da Da 泓6 小时前
多线程(四)【线程安全问题】
java·开发语言·jvm·学习·安全·多线程·线程安全问题
福尔摩斯张6 小时前
TCP协议深度解析:从报文格式到连接管理(超详细)
linux·c语言·网络·c++·笔记·网络协议·tcp/ip
wuk9986 小时前
C# 开发 FTP 客户端
开发语言·c#
光子物联单片机6 小时前
STM32单片机开发入门(十一)STM32CubeIDE下载安装及开发调试说明
c语言·stm32·单片机·嵌入式硬件·mcu
淼淼7636 小时前
Qt拖动工具栏控件到图页中均匀展示
开发语言·c++·windows·qt
二狗哈6 小时前
Cesium快速入门22:fabric自定义着色器
运维·开发语言·前端·webgl·fabric·cesium·着色器