多维数组寻址 C



在下面的代码中,我得到了地址相同的前两个值(称之为x(。我已经在 ubuntu v18.04.4 LTS 的 gcc 编译器上运行了它。

int a[2][2] = {0};
printf("%p %p %dn", a, *a, **a);

这意味着:

  1. a 包含地址 x。
  2. a 指向位置 x(因为它是存储 x 的指针(。
  3. 这意味着 *a 存储在位置 X 中,它还包含值 X(如上述代码的输出所示(。
  4. 现在,在取消引用 *a 即 **a 时,我得到的输出为 0,这意味着 *a(其值为 x(指向存储 0 的某个位置。

现在,从 1. 开始,*a 的地址是 x(因为 a 指向 *a 并存储 x(,数字 0 的地址也是 x(因为 *a 指向 a[0][0],即 0,*a 存储 x(。 所以我的问题是位置 x 到底存储了什么? 还是我在得出结论时弄错了什么?

您断言a包含地址似乎表明您认为a是一个指针。 它不是一个指针,而是一个数组。 它们是相关的,但它们不是一回事。

在大多数情况下,数组衰减到指向其第一个成员的指针。 在这种情况下,这意味着在表达式中a&a[0]相同,*aa[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'.;)

您声明了一个二维数组

int a[2][2] = {0};

表达式中使用的数组指示符(极少数例外,例如在 sizeof 运算符中使用它们(隐式转换为指向其第一个元素的指针。

所以表达式a在此调用中使用

printf("%p %p %dn", a, *a, **a);

转换为类型int ( * )[2]数组第一个元素的指针。也就是说,它是数组占用的内存范围的地址。

使用间接寻址运算符 * 表达式*a生成原始数组a的类型int[2]的第一个元素。

同样,在 printf 调用中*a的这个数组指示符被隐式转换为类型int *指向其第一个类型为int的元素的指针。此指针将包含原始数组占用的内存扩展数据的相同地址。

在此表达式**a中应用了两个间接寻址运算符。第一个间接寻址运算符生成二维数组的第一个元素,即它生成类型为int[2]的数组。此数组一次用作第二个间接寻址运算符的操作数,将隐式转换为指向其类型为int *的第一个元素的指针。第二个间接寻址运算符生成指针指向的对象,该指针是原始数组的对象,a[0][0]由上面所示的 printf 调用输出。由于此元素由 0 显式初始化,因此 0 作为元素的值输出。

为了更清楚起见,第一个间接寻址运算符*a等效于使用下标运算符 a[0]。而应用于此表达式*a[0]的第二个间接寻址运算符等效于表达式a[0][0]

最新更新