C 语言指针与数组的深层关系及实战
在 C 语言里,数组和指针的关系非常微妙,很多初学者容易混淆。其实只要理解了数组名的本质和指针算术运算,就能写出更高效的代码。这篇文章会带你从底层逻辑出发,掌握指针操作数组的核心技巧,并解决常见的越界问题。
数组名与指针的关系
数组名在大多数情况下会被编译器隐式转换为指向首元素的常量指针。这意味着 arr 和 &arr[0] 在地址上是相等的。
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
printf("数组首元素地址:%p\n", arr);
printf("数组首元素地址:%p\n", &arr[0]);
printf("数组首元素值:%d\n", *arr);
return 0;
}
运行结果会显示两个地址一致,且 *arr 能直接取值。不过得记住,数组名是常量指针,不能自增。像 arr++ 这种写法是非法的。
另外,下标访问 arr[i] 本质上就是 *(arr + i)。指针算术运算会根据类型自动计算偏移量,比如 int 占 4 字节,arr + 1 就会跳过 4 个字节。
指针操作数组的实战
理解了原理,我们来看看怎么用指针处理实际问题。
遍历求和
用指针遍历数组通常比下标更灵活。
#include <stdio.h>
int main() {
int arr[6] = {1, 2, 3, 4, 5, 6};
int sum = 0;
int *p = arr; // 指针 p 指向数组首元素
int len = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
for (int i = 0; i < len; i++) {
sum += *p;
p++; // 指针自增,指向下一个元素
}
printf("数组元素总和:%d\n", sum);
return 0;
}
这里用 sizeof 算长度是个好习惯,不管数组类型怎么变都适用。
原地逆序
有时候我们需要交换数据,但又不想开辟新空间。双指针法就很合适。
#include <stdio.h>
void reverseArray(int *arr, int len) {
int *left = arr; // 指向数组首元素
int *right = arr + len - 1; // 指向数组尾元素
int temp;
while (left < right) {
temp = *left;
*left = *right;
*right = temp;
left++; // 左指针右移
right--; // 右指针左移
}
}
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int len = sizeof(arr) / sizeof(arr[0]);
int *p = arr;
printf("原数组:");
for (int i = 0; i < len; i++) {
printf("%d ", *(p + i));
}
printf("\n");
reverseArray(arr, len);
printf("逆序数组:");
for (int i = 0; i < len; i++) {
printf("%d ", *(p + i));
}
printf("\n");
return 0;
}
注意,在函数内部传数组时,参数退化为指针,sizeof(arr) 拿到的只是指针大小,所以必须显式传递长度。
指针数组与数组指针的区别
这两个概念名字很像,但完全不一样。
指针数组
它是存放指针的数组。定义格式是 类型 *数组名 [长度]。比如存字符串列表就很方便。
#include <stdio.h>
int main() {
char *strArr[3] = {"C 语言", "指针", "数组"};
for (int i = 0; i < 3; i++) {
printf("%s\n", strArr[i]);
}
return 0;
}
数组指针
它是指向整个数组的指针。定义格式是 类型 (*指针名)[长度]。括号不能省,否则就变成指针数组了。这在处理二维数组时特别有用。
#include <stdio.h>
int main() {
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = arr; // 数组指针,指向包含 3 个 int 元素的数组
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
return 0;
}
常见问题与避坑
指针越界是最头疼的问题。循环次数千万别超过数组长度,否则读到随机值会很麻烦。还有,别搞混指针数组和数组指针的定义,少个括号意思全变了。
总结
数组名本质是常量指针,下标访问等价于指针解引用。指针算术运算能高效操作内存,但要注意边界检查。区分清楚指针数组和数组指针,能让你的代码更安全、更专业。


