【问题标题】:Difference between "pointer to int" and "pointer to array of ints"“指向 int 的指针”和“指向 int 数组的指针”之间的区别
【发布时间】:2010-03-07 20:18:04
【问题描述】:
int main()
{
    int (*x)[5];                 //pointer to an array of integers
    int y[6] = {1,2,3,4,5,6};    //array of integers
    int *z;                      //pointer to integer

    z = y;
    for(int i=0;i<6;i++)
        printf("%d ",z[i]);

    x = y;
    for(int i=0;i<6;i++)
        printf("%d ",(*x)[i]);

    return 0;
}

以上 printfs 都打印数字 1 到 6。
如果“指向整数数组的指针”和“指向整数的指针”都可以做同样的事情,那么它们的内部表示是否相同?
编辑:此代码在编译时确实会发出警告,如下面的答案所指出的那样,但是它确实在我的 x86_64 机器上使用 gcc 正确打印值

【问题讨论】:

  • 这个问题让我大吃一惊。我想我会永远避免 int (*x)[] 样式声明。
  • @Sandip:代码编译是因为在默认模式下 GCC 错误检测过于松散。它将违反约束报告为警告。您的x = y 分配确实是一个错误。

标签: c


【解决方案1】:

首先,您的代码将无法编译。数组的类型为int[6](6 个元素),而指针的类型为int (*)[5]。你不能让这个指针指向那个数组,因为类型不同。

其次,当您初始化(分配给)这样一个指针时,您必须在数组上使用&amp;x = &amp;y,而不仅仅是代码中的普通x = y

我假设您只是输入代码,而不是复制粘贴真实代码。

第三,关于内部表示。通常,在实践中,您应该期望所有数据指针使用相同的内部表示。此外,在上述赋值之后(如果编写正确),指针将具有相同的数值。 int (*)[5]int * 之间的区别仅存在于概念层面,即语言层面:类型不同。它有一些后果。例如,如果你增加z,它将跳转到数组的下一个成员,但如果你增加y,它将跳过整个数组等等。所以,这些指针并没有真正“做同样的事情” ”。

【讨论】:

  • int (*)[5]int * 之间的区别可能存在于符号表中......并不是说这种区别会改变你的观点。
  • @dmckee:我不知道你到底是什么意思。这是一道C题。在 C 中,名称通常不会被破坏,这意味着符号表中不会有任何区别(如果我理解正确的话)。
  • 符号表是编译器保存与每个变量相关的类型信息的地方;也就是说,编译器将在此处查看指针的增量。
【解决方案2】:

简短的回答:有区别,但你的例子有缺陷。

长答案:

区别在于int*指向一个int类型,而int (*x)[6]指向一个6个int的数组。实际上在你的例子中,

x = y;

是未定义的** 行为,你知道这是两种不同的类型,但在 C 中你可以做你想做的事。我将只使用一个指向六个整数数组的指针。

以这个修改后的例子为例:

int (*x)[6];                 //pointer to an array of integers
int y[6] = {1,2,3,4,5,6};    //array of integers
int *z;                      //pointer to integer
int i;

z = y;
for(i = 0;i<6;i++)
    printf("%d ",z[i]);

x = y; // should be x = &y but leave it for now!

for(i = 0;i<6;i++)
    printf("%d ",x[i]); // note: x[i] not (*x)[i]

首先,

1 2 3 4 5 6

将被打印。然后,我们到达x[0]。 x[0] 只不过是一个 6 个整数的数组。 C 中的数组是第一个元素的地址。因此,y 的地址将被打印,然后在下一次迭代中next 数组的地址。例如,在我的机器上:

1 2 3 4 5 6 109247792 109247816 109247840 109247864 109247888 109247912

如您所见,连续地址之间的区别无非是:

sizeof(int[6]) // 24 on my machine!

总之,这是两种不同的指针类型。

** 我认为这是未定义的行为,如果有错误,请随时纠正我的帖子。

【讨论】:

    【解决方案3】:

    希望这段代码有帮助:

    int main() {
    
        int arr[5] = {4,5,6,7,8};        
        int (*pa)[5] = &arr;
        int *pi = arr;
    
        for(int i = 0; i< 5; i++) {
            printf("\n%d %d", arr[i], (*pa)[i]);    
        }
    
        printf("\n0x%x -- 0x%x", pi, pa);
        pi++;
        pa++;
        printf("\n0x%x -- 0x%x", pi, pa);
    }
    

    打印以下内容:

    4 4
    5 5
    6 6
    7 7
    8 8
    0x5fb0be70 -- 0x5fb0be70
    0x5fb0be74 -- 0x5fb0be84 
    

    更新: 您会注意到指向整数的指针增加了 4 个字节(32 位整数的大小),而指向整数数组的指针增加了 20 个字节(int arr[5] 的大小,即每个 32 位的 5 个 int 的大小)。这证明了差异。

    【讨论】:

      【解决方案4】:

      从标题中回答您的问题,来自 comp.lang.c 常见问题解答:Since array references decay into pointers, if arr is an array, what's the difference between arr and &arr?

      但是,您发布的代码还有其他问题(您将 y 分配给 x,而不是 &amp;yy 是一个 6 元素数组,但 *x 是 5 -element 数组;这两个都应该生成编译警告)。

      【讨论】:

        【解决方案5】:

        谁知道——这段代码表现出未定义的行为:

        printf("%d ",(*x)[i]);
        

        【讨论】:

          【解决方案6】:

          希望此代码有所帮助。


          #include <stdio.h>
          #include <stdlib.h>
          #define MAXCOL 4
          #define MAXROW 3
          
          int main()
          {      
                int i,j,k=1;
                int (*q)[MAXCOL];      //pointer to an array of integers
          
                /* As malloc is type casted to "int(*)[MAXCOL]" and every 
                   element (as in *q) is 16 bytes long (I assume 4 bytes int), 
                   in all 3*16=48 bytes will be allocated */
          
                q=(int(*)[MAXCOL])malloc(MAXROW*sizeof(*q)); 
          
                for(i=0; i<MAXROW; i++)
                  for(j=0;j<MAXCOL;j++)
                    q[i][j]=k++;
          
          
                for(i=0;i<MAXROW;i++){
                  for(j=0;j<MAXCOL;j++)
                    printf(" %2d ", q[i][j]);
                  printf("\n");         
                } 
          }
          

          【讨论】:

            【解决方案7】:
            #include<stdio.h>
            
            int main(void)
            {
                int (*x)[6];                 //pointer to an array of integers
                int y[6] = {11,22,33,44,55,66};    //array of integers
                int *z;                      //pointer to integer
                int i;
            
                z = y;
                for(i = 0;i<6;i++)
                    printf("%d ",z[i]);
                printf("\n");
            
                x = &y;
            
                for(int j = 0;j<6;j++)
                    printf("%d ",*(x[0]+j));
            
                return 0;
            }
            

            //输出::

            11 22 33 44 55 66

            11 22 33 44 55 66

            指向数组的指针最适合多维数组。但在上面的例子中,我们使用了一维数组。因此,在第二个 for 循环中,我们应该使用 (x[0]+j) 和 * 来打印值。这里,x[0] 表示第 0 个数组。 当我们尝试使用 printf("%d ",x[i]); 打印值时 你会得到第一个值是 11,然后是一些垃圾值,因为试图访问数组的第一行等等。

            【讨论】:

              【解决方案8】:

              应该了解(*x)[i] 的内部表示。在内部,它表示为 *((*x)+i),它只是 x 指向的数组的第 i 个元素。这也是一种让指针指向二维数组的方法。二维数组中的行数无关紧要。

              例如:

              int arr[][2]={{1,2},{3,4}};
              int (*x)(2);
              x=arr; /* Now x is a pointer to the 2d array arr.*/
              

              这里x 指向一个二维数组,所有列中都有2个整数值,数组元素是连续存储的。所以(*x)[0] 将打印arr[0][0](即1),(*x)[1] 将打印arr[0][1] 的值(即2)等等。 (*x+1)[0] 将打印 arr[1][0] 的值(在这种情况下为 3)(*x+1)[1] 将打印在 arr[1][1] 的值(在这种情况下为 4)等等。

              现在,一维数组可以被视为只有一行和一样多列的二维数组。

              int y[6] = {1,2,3,4,5,6};
              int (*x)[6];
              x =y;
              

              这意味着x 是一个指向具有 6 个整数的数组的指针。所以(*x)[i]相当于*((*x)+i)将打印y的索引值。

              【讨论】:

                猜你喜欢
                • 2017-09-03
                • 2021-02-07
                • 2017-06-19
                • 1970-01-01
                • 1970-01-01
                • 2016-12-02
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多