
1. 引言今天学习了 C 语言中通过指针访问数组可以说是指针章节中最难的部分了。很多初学者学到数组和指针的关系时都会觉得「数组名到底是不是指针」「p[i]和*(pi)到底什么关系」这些问题绕得头晕。这篇文章就把这块硬骨头拆开用最直白的方式讲清楚最后再配一个能直接跑起来的实战案例帮你彻底打通「指针 数组」这条主线。2. 数组名与指针的关系先记住一句话数组名在大多数表达式中会「退化」为指向首元素的指针。intarr[5]{10,20,30,40,50};int*parr;// 等价于 int *p arr[0];这里arr作为右值时它的值就是首元素arr[0]的地址。所以p和arr指向同一个位置。但要注意数组名不是普通的指针变量arr是常量地址不能arrp是指针变量可以p。一句话总结数组名是「地址常量」指针是「地址变量」。这个区别是后面很多坑的根源先记牢。3. 指针访问数组的三种等价写法假设p已经指向arr[0]下面三种写法完全等价arr[i]// 下标法*(arri)// 指针法数组名退化*(pi)// 指针法指针变量也就是说p[i]本质上就是*(p i)。编译器看到下标[]内部就是按指针加法来计算的。4. 指针遍历数组的经典写法用指针遍历数组最常见的两种写法// 写法一用下标for(inti0;i5;i){printf(%d ,arr[i]);}// 写法二用指针移动for(int*parr;parr5;p){printf(%d ,*p);}第二种写法里p让指针每次向后移动一个int的大小而不是一个字节。这是指针运算的核心指针加 1跳过的是它指向类型的大小。 小提示写法二里p arr 5用到了「指针比较」它比较的是地址的大小。只要p还在数组范围内循环就继续一旦p越过arr 5循环立即停止。这正是指针遍历数组的安全边界。5. 最容易踩的坑这一节集中讲三个初学者最容易犯的错误每一个都配了错误示例和正确理解建议对照着敲一遍。5.1 数组名不能自增// 错误arr;// 数组名是常量地址不能修改数组名是常量地址编译器不允许对它做自增操作。如果你确实想「移动」指针请先把它赋给一个指针变量再对指针变量做p。5.2 指针越界intarr[5]{1,2,3,4,5};int*parr;*(p5)100;// 越界arr 只有 5 个元素p5 已经超出数组指针越界不会在运行时自动报错但会破坏内存是 C 语言里非常危险的隐患。它可能悄悄改写相邻变量的值也可能在程序退出时触发段错误Segmentation Fault而且这类 bug 极难排查。5.3 混淆arr和arrintarr[5];int*p1arr;// 指向 intp11 跳 4 字节int(*p2)[5]arr;// 指向整个数组p21 跳 20 字节arr是「指向 int 的指针」arr是「指向 int[5] 数组的指针」两者类型完全不同。p1 1跳到下一个元素p2 1跳到整个数组之后——差一个字节都不行类型决定了指针步长。6. 实战案例用指针实现数组反转理论讲了不少来一个能直接跑起来的完整例子。下面这段代码用指针把数组原地反转#includestdio.hvoidreverse(int*arr,intn){int*leftarr;// 指向首元素int*rightarrn-1;// 指向末元素while(leftright){// 交换 left 和 right 指向的值inttmp*left;*left*right;*righttmp;left;// 左指针右移right--;// 右指针左移}}intmain(){intarr[]{1,2,3,4,5};intnsizeof(arr)/sizeof(arr[0]);printf(反转前);for(inti0;in;i){printf(%d ,arr[i]);}printf(\n);reverse(arr,n);printf(反转后);for(inti0;in;i){printf(%d ,arr[i]);}printf(\n);return0;}运行结果反转前1 2 3 4 5 反转后5 4 3 2 1这个例子把前面讲的知识点都用上了arr作为实参传入函数时退化为首元素地址所以形参int *arr接收的就是数组首地址left和right两个指针分别从两端向中间移动left、right--每次跳过的是一个int的大小循环条件是left right当两个指针相遇或交错时停止正好完成全部交换。你可以试着把reverse里的while (left right)改成while (left right)看看结果有什么不同——这也是理解指针比较的一个好练习。7. 二维数组与指针二维数组用指针访问时要理解「行指针」的概念intmatrix[3][4]{0};int(*row)[4]matrix;// row 指向一行4 个 int// 访问第 i 行第 j 列matrix[i][j]// 下标法*(*(rowi)j)// 指针法row i跳到第 i 行*(row i)得到该行首元素的地址再加j就是第 j 列元素的地址。8. 总结指针访问数组核心就三句话数组名在表达式中退化为首元素地址p[i]等价于*(p i)指针加 1 跳过的是「指向类型」的大小。把这三点吃透指针和数组这块最难的部分就通了。剩下的就是多写代码、多调试遇到段错误先检查是不是指针越界了。建议你把第 6 节的数组反转案例自己默写一遍再试着改成「用指针遍历二维数组」练得越多理解越深。