
int arr[5] = {1, 2, 3, 4, 5};
这是C语言中的一维数组。
核心问题:数组名arr所代表的地址和对数组名取地址后的地址是否等价?
答案是:不是。
今天我带着大家一起来弄懂数组名代表的地址和对数组名取地址后的地址的具体含义。
在C语言中数组名表示第一个元素的地址,而对数组名取地址则表示整个数组的地址。虽然他们的值一样,但是他们的语义逻辑却完全不同。
一维数组的地址含义
我们假设有一个这样的包含5个INT类型元素的一维数组
int arr[5] = {1, 2, 3, 4, 5};
那么数组名arr就表示第一个元素也就是arr[0]的地址&arr[0]。
因此如果你要把arr赋值给一个指针就可以这样写:
int * p = arr;
这里的p表示指向 int 类型数据的指针。
而取数组名的地址&arr则表示整个数组的地址,如果你想把它赋值给一个指针,你需要这样写:
int (*q)[5] = &arr;
指针声明的详细解析
我们来详细理解一下这个指针的写法。
int表示数组元素的数据类型是整型,*q 表示 q 是一个 指针变量,紧跟在 (*q) 后面的 [5],表示 q 指向的不是单个 int 元素,而是一个包含 5 个 int 元素的数组。
虽然p和q都是指向首地址,在这个数组中,它两指向的值其实是一样的,然而它们的语义却是不同的。
p在语义逻辑上是指向的首个元素的地址,对p进行++操作,它将指向下一个元素的地址。
而q则指向的是整个数组的起始地址,你对q进行++操作,它是以整个数组为单位,因此它将跳过整个数组,从而指向数组结束后的地址。
代码验证:指针自增行为的差异
#include <iostream>
using namespace std;
int main() {
int arr[5] = { 1, 2, 3, 4, 5 };
// 指向数组第一个元素的指针
int* p1 = arr;
// 指向整个数组的指针
int(*p2)[5] = &arr;
// 打印初始地址
cout << "Initial addresses:" << endl;
cout << "p1 (arr): " << p1 << endl;
cout << "p2 (&arr): " << p2 << endl;
// 指针自增
p1++; // 移动到下一个元素
p2++; // 移动到下一个“数组”(假设存在下一个数组)
// 打印自增后的地址
cout << "\nAfter p++:" << endl;
cout << "p1 + 1: " << p1 << " (points to arr[1])" << endl;
cout << "p2 + 1: " << p2 << " (skips entire array)" << endl;
return 0;
}
在这份示例代码中p1指向arr的地址,而p2指向arr取地址后的地址。然后对它进行自增操作,最后打印出它们的地址。
我们运行这份代码,可以看到在开始时P1的地址其实和P2的地址是一样的。在p1在自增操作后,它只移动了4个字节,而P2在自增操作后移动了20个字节。
扩展到二维数组
同样的理论也可以扩展到二维数组。在开始理解二维数组相关知识之前,你首先得明白二维数组虽然在内存中是连续存储的,但它的逻辑结构是一维数组的数组,也就是由多行构成的矩阵。
例如,我们有这样一个2行3列的二维数组
int arr[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
你可以简单的把它理解成是由2个一维数组组成。因此它的第一个元素也就是 arr[0]其实就是第一行,而它arr[0][0]才是第一行的第一列。
我们前边讲过,数组名代表数组首元素的地址,那么在二维数组中 arr代表的第一个元素就是第一行,也就是第一行的开始地址。
那如果我们要把它赋值给一个数组指针,因为它是第一行的地址,你就可以这样写:
int (*p)[3] = arr;
而此时我们对p进行++操作,它会跳过一行元素,进入到下一行。
细心的你一定发现,此时它和我们之前对一维数组中取数组首地址的指针类型是一样的。那么新的问题来了,如果此时对p进行解引用指向哪里呢?此时对*p解引用,它会指向这一行中第一个元素的地址。如果你想再解出指向内存的值,只需要再解引用一次就可以了**p。
对二维数组名取地址
结合视频前边所讲知识,如果对这个二维数组名取地址,那么它代表整个数组。它的指针类型又会是怎么写呢?
我们一起来写一下。首先它指向的元素类型是Int类, 其次它是一个指针,然后它指向的是包含2行3列的二维数组。再把arr取地址赋值 给它就可以了。
int (*p)[2][3] = &arr;
同样,如果我们对它进行++自增操作,它会跳过整个二维数组,我们这里是会跳过24个字节的长度。
三维数组及其他高维数组
以上这些知识同样可以扩展到三维数组中。其实你明白了二维数组,那么三维数组也就好理解了。
好了关于C语言中的数组名的用法你现在明白了吗?


