【问题标题】:2-dimensional array name 1st element二维数组名称第一个元素
【发布时间】:2017-09-05 04:30:07
【问题描述】:

C Programming in One Hour a Day 有这样一句话:

与一维数组一样,多维数组的名称是指向第一个数组元素的指针。

#include <stdio.h>

int m[2][4];

int main() {
    printf("%p\n", m);        // 1
    printf("%p\n", &(m[0]));  // 2
    printf("%p\n", m[0]);     // 3
    printf("%p\n", &m[0][0]); // 4
}

这将为所有语句打印相同的值。根据引用,1 == 2 和 3 == 4 是有道理的。但我不明白 2 == 3。m[0] 的地址怎么可能与m[0] 相同?

【问题讨论】:

  • 因为,这就是它的实现方式,因此int *p = malloc(n * sizeof(int)) 起作用。尝试打印&amp;m,结果也会相同。因为对于数组的情况,所有这些都没有实际实现,不占用内存,但仍然可以作为指向数组(或地址)的指针使用和考虑
  • OT:转换说明符%p 仅针对void 指针定义,因此代码应类似于printf("%p\n", (void*) m);。对printf() 的其他三个调用也是如此。调用其他未定义的行为。
  • 亲爱的主,这个问题已经问了多少种方式了?
  • "与一维数组一样,多维数组的名称是指向第一个数组元素的指针。" --> 不。数组不是指针。在选择情况下,数组转换为第一个元素的指针,但 m 仍然是数组。

标签: c arrays multidimensional-array


【解决方案1】:

当分配一个二维(或任何维度)数组时,它只是为其元素占用内存(内存不会分配给数组名称或任何其他数组元素,如m[0]m[1] 在您的情况下,它的作用类似于 const 指针)。

因为不会为它们分配任何物理内存(实际上甚至不需要),所以在尝试打印它们时会得到相同的地址。在你的情况下, 因为它是一个二维数组,因为m 指向m[0],而m[0][0] 又指向m[0][0],所有这些的获取地址将给出相同的值(也适用于m[1]m[1][0])。

**为了更好地理解,请看这个(如果你打印它们会是这样)

      _____         _____         _____
     |0x100|  -->  |0x100|  -->  |value|
0x100|_____|  0x100|_____|  0x100|_____|
       m            m[0]         m[0][0]

*value是m[0][0]的值

这里, mm[0] 的作用类似于指针,但没有物理实现(不占用内存),编译器会处理如何处理它们。

*虽然我已经证明0x100 包含0x100 对应于mm[0],但0x100 实际上包含m[0][0] 的数据/值,但是如果您执行任何操作,那么编译器就是这样对待他们。

**正因为如此,int *p = malloc(n * sizeof(int)) 这是可能的,不同之处在于p 现在占用了指向数组起始地址的内存。如果将p 视为int const *p,则可以将其视为没有动态分配的普通数组。

【讨论】:

    【解决方案2】:

    数组包含数据,不包含任何其他内容。该数据有一个起始地址——即第一个元素的地址。

    “多维数组的名称是指向第一个数组元素的指针”过于简单化,并不真正正确。数组不是指针,指针也不是数组。

    但是,无论何时在表达式中使用数组(任意维度)的名称,都会产生一个指向数组第一个元素的临时指针。这通常被称为“数组衰减为指针”。

    现在,这些行之间唯一不同的是指针的类型:

    1. int[2][4] 类型的数组衰减为指向第一个元素的指针。二维数组中的第一个元素是int [4] 类型的一维数组。指向这样一个数组的指针是一个数组指针int (*)[4]

    2. &amp;m[0] 给出第一个元素的地址,即第一个一维数组的地址。所以这完全等价于1)。

    3. m[0] 给出第一个元素,仍然是一维数组。它衰减为指向其第一个元素的指针。 int [4] 的第一个元素是 int,所以我们得到一个指向它的指针 int*

    4. &amp;m[0][0] 提供指向第一个数组的第一个元素的指针,int*。相当于 3)。

    所有这些指针类型都将具有相同的地址,这仅仅是因为二维数组与其第一项(一维数组)的起始地址相同。依次从与其第一个项目(第一个整数)相同的地址开始。

    各种不同的指针类型只是高级语言语法。这些类型不是保留在机器代码中的东西,所有东西都只是原始地址。

    【讨论】:

      【解决方案3】:

      第一个维度将存储子数组(行)的地址。

      例如你有m[2][4],所以m[0] 计算为第一行的地址,其中包含从m[0][0]m[0][3] 的元素,m[1] 计算为第二行的地址,其中包含从m[1][0]m[1][3] 的元素。

      如果您尝试打印 m[0]m[1],您将看到地址差异是行的总大小相隔 m[0] 字节。

      【讨论】:

      • 好。现在对于另一个不准确之处:“m[0] 存储第一行的地址”它实际上 存储它。发生的事情称为m[0]“衰减到”第一行的地址。
      • 我同意 m[0] 的值不是从存储中读取的,而是在引用时计算出来的
      猜你喜欢
      • 2011-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 2013-03-03
      • 2012-06-12
      • 1970-01-01
      相关资源
      最近更新 更多