为什么解引用指向整数数组的指针(在2d数组中)返回(或衰减到)指向第一个元素的指针?

时间:2014-06-09 13:08:12

标签: c pointers multidimensional-array

我已经阅读了许多指针和二维数组关系的帖子,但我似乎无法理解概念。 假设有一个2d数组int a[3][2]和一个数组int b[2] now a返回一个指向大小为3的整数数组的指针。它的类型为int (*)[2]

正如我对这个概念的理解所解释它(*a)会给我数组本身而这会衰减到指向1d数组的第一个元素并且类型为(int *)的指针。现在大胆的部分是怀疑。

  为什么如何这种衰变发生在数组本身(完整的1d数组a [0])衰变到1d数组的第一个元素? / strong>
(似乎不知道为什么以及如何部分)并且似乎也无法在其他链接上找到它。

作为a[0]*a&a[0][0]代表相同的指针。这里作为[0]是第一个1d数组。那么b(在上面声明)和a[0]表示相同的事情(两者都是1d数组然后衰减到指向第一个元素的数组(int *)中的第一个元素?

5 个答案:

答案 0 :(得分:2)

  

为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?

C11:6.3.2.1 p(3):

  

除非它是sizeof运算符的操作数,_Alignof运算符 1 ,一元&运算符,或者是一个字符串文字用于初始化一个数组,一个类型为''array of type''的表达式被转换为一个类型为''指向类型'的指针的表达式   到数组对象的初始元素,而不是左值。

简单;数组名称可以转换为指向其第一个元素的指针。

由于a是一个数组名称,它会衰减到指向其第一个元素的指针,该元素是一维数组。它的类型是int(*)[2]。由于a(在衰减之后)是指向2 int数组的指针,*a2 int的数组。由于这是一个数组类型,即*a是第一个1D数组的数组名称,它会衰减到指向数组对象的第一个元素(a[0][0])的指针。所以,它的类型是int *

  

这是真的,b(在上面声明)和a[0]表示相同的事情(都是1d数组然后衰减到指向类型数组(int*的第一个元素的指针) )?

ba[0]都属于int *类型(在衰退后)。


<子> 1。通过Keith Thompson阅读commat。另请阅读此answer,其中指出: C11标准的草案说数组有另一个例外,即当数组是新_Alignof运算符的操作数时。这是草案中的错误,在最终公布的C11标准中得到纠正; _Alignof只能应用于带括号的类型名称,而不能应用于表达式。

答案 1 :(得分:2)

你&#34;为什么&#34;问题是:因为语言规范是这样说的。数组始终衰减到指向其第一个元素的指针(除了许多特定的上下文之外)。因此,正确地指出*a的类型为int [2]。这是一个数组。由于它是一个数组,语言需要衰减到指向int *的{​​{1}}类型的指针(同样,除少数特定的上下文外) )。您的原始(*a)[0]a类型的数组,它会衰减为int [3][2]指针。同时int (*)[2]是一个*a类型的数组,它会衰减为int [2]指针。这就是原因。

至于&#34;如何&#34;,目前尚不清楚你究竟在问什么。 &#34;衰变&#34;在这种情况下意味着在表达式中,数组类型的值被指针类型的值隐式替换。这就是它的全部内容。

是的,您示例中的int *a[0]都是b类型的数组,它们与int [2]类型的指针相同地衰减。即他们是同样的事情&#34;关于腐朽的行为。

答案 2 :(得分:1)

指定此转换的规则隐藏在C11章6.3.2:

  

...具有类型“数组类型”的表达式将转换为   带有“指向类型的指针”类型的表达式,指向初始值   数组对象的元素,而不是左值。

这意味着如果你有一个表达式,其中使用了b的数组名int b[3],它将转换为指向int的指针int*

此规则是通用的。如果你有一个数组int a[3][2],那么正式你有一个“大小为3的数组大小为2的int数组”。这将转换为一个指向type的指针,它是“指向int类型为2的数组的指针”,int(*)[2]

请注意,“衰减”只会“向下”一个级别,因此通过使用二维数组名称a,您将始终获得一个数组指针而不是指向第一个元素的指针。数组指针和普通int指针之间的区别主要是风格,以保持语言的一致性。如果将指针的实际地址打印为整数,则无论指针类型如何都是相同的。

  

因此,我对这个概念的理解是去除它(*a)会给我数组本身,这会衰减到指向1d数组的第一个元素的指针,类型为(int*)

它将为您提供数组本身,它将衰减为数组指针。它不会再从那里腐烂,只有一个层次。所以*a不会给你一个指向第一个元素的指针。

  

为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?

每当在表达式中使用数组名称时,它将从“数组到类型”变为“指向类型的指针”。如果“type”碰巧是一个数组,那么你会得到一个指向数组的指针。

  

还有一个人怀疑。作为a[0]*a&a[0][0]表示相同的指针。这里的[0]是第一个1d数组。

a[0]*a是等价的,两者都给出一个数组指针。 &a[0][0]是指向int的指针。它们有不同的类型,但在实践中指向相同的记忆。

答案 3 :(得分:1)

请尝试以下代码:

int x[3][10];
printf("%d\n", x[0]);
printf("%d\n", x[1]);
printf("%d\n", x[2]);

请查看以下表达式

if(&x[0][9] + 1 == &x[1][0])
    printf("I've entered here");

这个值为true ...当你向指针添加1时,它的地址增加4(或者你的机器具有的任何int大小),显示在内存中,元素x [1] [0]紧随其后元素x [0] [9]

一个大小为4的整数,你会看到这些版画之间的差异是40(4 * 10)个元素......

这个数组是在编译时分配的,因此它已经知道它需要多少空间,它为3 * 10个整数连续分配空间,就像它被声明为

时一样。
 int x[30];

当你单独使用名字x时,得到的是它指向的第一个元素的地址......

第二个维度仅供我们程序员使用......但是编译器的成本很低......当你访问

 x[1][8];

它必须计算添加到起始地址以访问该元素的程度,

这将是(1 * 10 + 8)* SIZE_OF_ARRAY_TYPE(这里是int)......

在上面的表达式中,1 =第一个维度上的数字,乘以10(第二个维度中第一行中的元素数量)加到第二个维度中的元素数量[]

如果你有1维数组:

 x[23]

唯一的帐户是23 * SIZE_OF_ARRAY_TYPE(这里是int)

你也可以在这里尝试这个IF语句:

 if(&x[0][10] == &x[1][0])
    printf("I've entered here");

甚至是

等作业
x[1][4] = 20;

printf("%d\n", x[0][14]);

指针给你很大的力量,但强大的力量带来了很大的责任;)

答案 4 :(得分:1)

数组int a[3][2]作为1d数组存储在内存中row major order,所以这个数组:

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

将存储为:

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

例如:

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
  size_t i;

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

  for(i = 0 ; i < sizeof(a) / sizeof(int) ; i++)
  {
    printf("%d\n", ((int *) a)[i]);
  }

  return 0;
}