【问题标题】:How does C retrieve the address of a row for a 2d arrayC如何检索二维数组的行地址
【发布时间】:2012-08-24 15:25:59
【问题描述】:

当您只使用一个下标访问二维数组时,有人可以向我解释 C 如何检索一行的正确内存地址吗?

示例 -

int array2D[2][2] = {1,2,3,4};
printf ( "starting address of row2 = %p" , array2D[1]);

我知道,当在 C 中下标时,实际发生的是指针添加,因此对于一维数组,数组名称指向元素 0。在这种情况下,如果我想要元素 1,编译器将采用起始地址(比如4000) 并在其上加 4(假设为 4 位 int),这样返回的是内存地址 4004 处的项目。

我的理解是当你填充一个二维数组时,就像我的例子一样,它们是按顺序分配的,所以我会有

1 2
3 4
地址

4000 4004

4008 4012

那么 C 如何计算出在这种情况下 array2D[1] 应该指向 4008 而不是 4004?它运行 sizeof() 运算符还是我在这里误解了基本原理?

提前致谢

【问题讨论】:

  • 你的例子是一维数组。
  • 不,你没有:请参阅 Keith Randall 的正确语法答案
  • @Useless,是的,他做到了。如果您指定完整的数组类型,则内括号是可选的。
  • 有趣,我从来不知道!我不认为它具有可读性,但仍然很高兴知道。

标签: c pointers multidimensional-array pointer-arithmetic


【解决方案1】:

C 知道每行有多长,因此它会通过乘法来找到该行。

int x[][3] = {{1,2,3},{4,5,6}};

那么&x[1][0] 就是&x[0][0] 加上3 * sizeof(int)

这就是为什么在多维 C 数组声明中,必须指定除第一个维度之外的所有维度。

【讨论】:

  • 啊,太好了,感谢 Keith。当它被解释时,非常明显:)
  • @Keith Randall:有趣的答案,但是 C 如何知道每行的长度?在这种情况下,x 不只是一个指向整数指针的指针吗? “行大小”信息存储在哪里?
  • @curvature:C 从声明中知道每一行的长度。试着不要把3 放在那里看看会发生什么(提示:编译器错误)。行大小在运行时不存储在任何地方(在生成的代码中编码除外)。 x 不是指向整数指针的指针,而是指向整数数组的指针(在我的示例中为 6 个)。数组中没有指针(不像 Java,所以你不能做x[0]=...)。
  • 我明白了,我现在明白了。现在,为什么需要显式定义行的大小是有道理的。谢谢。
【解决方案2】:

指针算法取决于被指向元素的类型。给定一个指向T 类型的指针pp + 1 指向T 类型的下一个元素,不一定是p 之后的下一个字节。如果Tchar,那么p + 1指向char之后的下一个char对象,它从p之后的字节开始;如果Tchar [10],则p + 1 指向char 之后的下一个10 元素数组p,它从p 之后的第10 个字节开始。

表达式 array2d 中的类型是“int 的 2 元素数组的 2 元素数组”,它“衰减”为“指向 2 元素数组的指针” int" 或 int (*)[2]1。因此表达式array2d[1] 被解释为*(array2d + 1)。由于array2d 指向int [2] 类型的对象,array2d + 1 指向array2d 之后的int 的下一个2 元素数组,它与2 * sizeof int 相距array2d 字节。


1。除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则将转换类型为“T 的 N 元素数组”的表达式类型为“指向T”的表达式,其值将是数组中第一个元素的地址。

【讨论】:

    【解决方案3】:

    这会有点啰嗦,但请耐心等待。

    数组订阅只是一个简写:(p[N]) 在所有指针类型的上下文中都等于 (*(p + N))(不过,对于 void*,两者都是无效的表达式)。

    现在,如果p 是一个数组类型,它会衰减为像(*(p + N)) 这样的表达式中的指针类型; int[2][2] 将衰减为 (*)[2] 类型的指针(即指向 int[2] 的指针)。

    指针算术将类型考虑在内;我们需要将事物转换为char* 以可视化编译器对我们所做的事情:

    T *p;
    p[N] equals *(p + N) equals *(T*)((unsigned char*)p + N * sizeof *p)
    

    现在,如果Tint[2](与我们上面描述的情况相同),那么sizeof *p 将是sizeof(int[2]),即2 * sizeof(int)

    这就是订阅在所谓的多维数组中的工作方式。

    【讨论】:

      【解决方案4】:

      sizeof(array2D[1]) == 8;
      如果 array2D 地址为 4000;
      所以 array2D[1] 地址是 4000+sizeof(array2D[1]) == 4000+8;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-19
        相关资源
        最近更新 更多