多维数组寻址 C
Multidimensional array addressing C
在下面的代码中,我得到的地址的前两个值相同(称之为 x)。我在 ubuntu v18.04.4 LTS 的 gcc 编译器上有 运行 它。
int a[2][2] = {0};
printf("%p %p %d\n", a, *a, **a);
这意味着:
- a 包含地址 x。
- a 指向位置 x(因为它是一个存储 x 的指针)。
- 这意味着 *a 存储在位置 x 并且它还包含值 x(如上述代码的输出)。
- 现在,在取消引用 *a 即 **a 时,我得到的输出为 0,这意味着 *a(其值为 x)指向存储 0 的某个位置。
现在,从1.开始,*a的地址是x(因为a指向*a并且正在存储x)并且数字0的地址也是x(因为*a指向a[0][0 ] 是 0,*a 存储 x)。
所以我的问题是位置 x 到底存储了什么?
还是我的结论有误?
没看懂什么是魔法'x'
.;)
你声明了一个二维数组
int a[2][2] = {0};
表达式中使用的数组指示符(除了极少数例外,例如在 sizeof 运算符中使用它们)被隐式转换为指向其第一个元素的指针。
所以这个调用中使用的表达式a
printf("%p %p %d\n", a, *a, **a);
转换为 int ( * )[2]
类型的指针指向数组的第一个元素。也就是数组占用内存区的地址。
使用间接运算符 * 表达式 *a
生成原始数组 a
.
类型 int[2]
的第一个元素
再次调用 printf 时,此数组指示符 *a
被隐式转换为 int *
类型的指针,指向其第一个 int
类型的元素。该指针将包含与原始数组占用的内存范围相同的地址。
在此表达式 **a
中应用了两个间接运算符。第一个间接运算符生成二维数组的第一个元素,即生成 int[2]
类型的数组。这个用作第二个间接运算符的操作数的数组立即被隐式转换为指向其第一个类型为 int *
的元素的指针。第二个间接运算符产生指针指向的对象,该指针是上面显示的 printf 调用输出的原始数组 a[0][0]
的对象。由于此元素由 0 显式初始化,因此输出 0 作为元素的值。
为了更清楚地说明第一个间接运算符 *a
等同于使用下标运算符 a[0]。应用于此表达式 *a[0]
的第二个间接运算符等同于表达式 a[0][0]
.
您关于 a
包含地址的断言似乎表明您认为 a
是一个指针。它不是指针而是数组。它们是相关的,但它们不是一回事。
一个数组,在大多数情况下,衰减指向其第一个成员的指针。在这种情况下,这意味着在表达式中 a
与 &a[0]
相同,*a
与 a[0]
相同,而 a[0]
与 &a[0][0]
相同。这也意味着数组的地址与其第一个成员的地址相同,这就是您在打印 a
和 *a
.
时看到的内容
用图表可能会更好地说明这一点:
----- ------- ---- ---
0x100 | 0 | a[0][0] a[0] a
----- -------
0x104 | 0 | a[0][1]
----- ------- ----
0x108 | 0 | a[1][0] a[1]
----- -------
0x10c | 0 | a[1][1]
----- ------- ---- ---
从这里,您可以看到 a
从地址 0x100 开始(在您的示例中为 x
),总共包含 4 个 int
值。另请注意,子数组 a[0]
与 a
具有相同的地址,初始 int
元素 a[0][0]
.
也是如此
概括地说,数组的地址和它的第一个元素的地址,即使类型不同,也是相同的。所以:
a
是地址为0x100的数组。它包含 int[2]
. 类型的元素
a[0]
是地址为0x100的数组。它包含 int
. 类型的元素
a[0][0]
是一个地址为0x100的int
。
在下面的代码中,我得到的地址的前两个值相同(称之为 x)。我在 ubuntu v18.04.4 LTS 的 gcc 编译器上有 运行 它。
int a[2][2] = {0};
printf("%p %p %d\n", a, *a, **a);
这意味着:
- a 包含地址 x。
- a 指向位置 x(因为它是一个存储 x 的指针)。
- 这意味着 *a 存储在位置 x 并且它还包含值 x(如上述代码的输出)。
- 现在,在取消引用 *a 即 **a 时,我得到的输出为 0,这意味着 *a(其值为 x)指向存储 0 的某个位置。
现在,从1.开始,*a的地址是x(因为a指向*a并且正在存储x)并且数字0的地址也是x(因为*a指向a[0][0 ] 是 0,*a 存储 x)。 所以我的问题是位置 x 到底存储了什么? 还是我的结论有误?
没看懂什么是魔法'x'
.;)
你声明了一个二维数组
int a[2][2] = {0};
表达式中使用的数组指示符(除了极少数例外,例如在 sizeof 运算符中使用它们)被隐式转换为指向其第一个元素的指针。
所以这个调用中使用的表达式a
printf("%p %p %d\n", a, *a, **a);
转换为 int ( * )[2]
类型的指针指向数组的第一个元素。也就是数组占用内存区的地址。
使用间接运算符 * 表达式 *a
生成原始数组 a
.
int[2]
的第一个元素
再次调用 printf 时,此数组指示符 *a
被隐式转换为 int *
类型的指针,指向其第一个 int
类型的元素。该指针将包含与原始数组占用的内存范围相同的地址。
在此表达式 **a
中应用了两个间接运算符。第一个间接运算符生成二维数组的第一个元素,即生成 int[2]
类型的数组。这个用作第二个间接运算符的操作数的数组立即被隐式转换为指向其第一个类型为 int *
的元素的指针。第二个间接运算符产生指针指向的对象,该指针是上面显示的 printf 调用输出的原始数组 a[0][0]
的对象。由于此元素由 0 显式初始化,因此输出 0 作为元素的值。
为了更清楚地说明第一个间接运算符 *a
等同于使用下标运算符 a[0]。应用于此表达式 *a[0]
的第二个间接运算符等同于表达式 a[0][0]
.
您关于 a
包含地址的断言似乎表明您认为 a
是一个指针。它不是指针而是数组。它们是相关的,但它们不是一回事。
一个数组,在大多数情况下,衰减指向其第一个成员的指针。在这种情况下,这意味着在表达式中 a
与 &a[0]
相同,*a
与 a[0]
相同,而 a[0]
与 &a[0][0]
相同。这也意味着数组的地址与其第一个成员的地址相同,这就是您在打印 a
和 *a
.
用图表可能会更好地说明这一点:
----- ------- ---- ---
0x100 | 0 | a[0][0] a[0] a
----- -------
0x104 | 0 | a[0][1]
----- ------- ----
0x108 | 0 | a[1][0] a[1]
----- -------
0x10c | 0 | a[1][1]
----- ------- ---- ---
从这里,您可以看到 a
从地址 0x100 开始(在您的示例中为 x
),总共包含 4 个 int
值。另请注意,子数组 a[0]
与 a
具有相同的地址,初始 int
元素 a[0][0]
.
概括地说,数组的地址和它的第一个元素的地址,即使类型不同,也是相同的。所以:
a
是地址为0x100的数组。它包含int[2]
. 类型的元素
a[0]
是地址为0x100的数组。它包含int
. 类型的元素
a[0][0]
是一个地址为0x100的int
。