繁体   English   中英

二维数组指针

[英]2D array pointer

我知道二维数组基本上是指向数组的指针,所以在下面的代码中,a 是指向第 0 个索引的指针,该索引本身就是一个数组,而不是 *a 应该返回第 0 个索引元素的地址 a 和 *a 如何都返回相同的值

#include <stdio.h>
#include <stdio.h>
      int main () {
          int a[4] [5] = {{1, 2, 3, 4, 5},
                          {6, 7,8, 9, 10},
                          {11, 12, 13, 14, 15},
                          {16, 17,18, 19, 20}};
     
      
         printf("%d\n",a);
         printf("%d\n",*a);
    
    }

对于初学者输出指针值,您应该使用转换说明符%p而不是%d

     printf( "%p\n", ( void * )a );
     printf( "%p\n", ( void * )*a) ;

用作参数表达式的数组指示符a被隐式转换为指向其第一个元素的指针。 由于数组声明为二维数组,如

      int a[4] [5] = {{1, 2, 3, 4, 5},
                      {6, 7,8, 9, 10},
                      {11, 12, 13, 14, 15},
                      {16, 17,18, 19, 20}};

那么它的元素具有int [5]类型,并且数组隐式转换为的指针(具有int ( * )[5] )将具有作为初始地址的数组的第一个“行”的地址数组占用的内存范围。

取消引用指针,您将获得第一个“行”,即int [5]类型的数组a[0] int [5] 再次用作参数表达式,它被隐式转换为int *类型的指针,指向其第一个元素a[0][0] 并输出第一个“行”的第一个元素的地址,即数组所占用内存范围的起始地址。

也就是说,整个数组的地址、其第一个“行”的地址和第一个“行”的第一个元素的地址彼此相等。 但是相应的表达式&aa*a (隐式转换为指针后)具有不同的类型。 表达式&a的类型为int ( * )[4][5] ,表达式a (隐式转换之后)的类型为int ( * )[5] ,表达式*a (也在隐式转换之后)的类型为输入int * 但他们的价值观是平等的。

我知道二维数组基本上是指向数组的指针

不它不是。 大多数表达式中使用的数组“衰减”到指向第一个元素的指针,但这不会使数组成为指针。

所以在下面的代码中 a 是指向第 0 个索引的指针

仅在表达式printf("%d\\n",a); 其中a衰减为指向其第一个元素的指针。 的第一个元素a是类型的数组int [5]因此,在此的printf表达, a衰减到一个指针这样的元件中, int (*)[5]的类型。

使用%d打印指针不是明确定义的行为,因此代码是错误的,您应该使用%p并将参数printf("%p\\n", (void*)a);void*printf("%p\\n", (void*)a);

a 和 *a 如何返回相同的值

对于任何数组,数组本身和它的第一个元素自然位于相同的地址,否则数组的概念没有任何意义。 数组的定义是在连续地址分配的具有相同类型的连续项目块。

当您取消引用*a ,您取消引用int(*)[5]类型的衰减数组a并获得类型int [5] 但是由于数组不能在大多数表达式中使用,因此这也可以说是衰减为指向int [5]的第一个元素的指针,这意味着类型int* ,指向第一个数组中的项 [0]。

上面已经有两个有价值的答案,但我认为您仍然对这种情况感到困惑; 因为我在菜鸟时期也有同样的感觉(虽然我还不是专业人士)。

  1. 下面的行不返回指针 实际上,它返回一个内存地址,第一个地址保存数组的第一个元素作为数据; 但是由于它在堆栈上,C 将其视为指针。
int a[4][5] = { ... };
  1. 下面的几行再次返回堆栈上的内存地址,但它们保存其他内存地址,这一次,它们实际上是指针 它们指向不同的内存地址——很可能在堆上。
int** b = malloc(4 * sizeof(int*));
int*  c = malloc(5 * sizeof(int));

不要保持双手清洁并调试下面的代码并检查输出,同时注意内存转储:

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

int** copyArray(int row, int col, int pSrc[row][col]) {
    int** pDst = malloc(row * sizeof(int*));

    for (int i = 0; i < row; i++) {
        pDst[i] = malloc(col * sizeof(int));

        for (int j = 0; j < col; j++) {
            pDst[i][j] = pSrc[i][j];
        }
    }

    return pDst;
}

int main() {
    int a[4][5] = { {  1,  2,  3,  4,  5 },
                    {  6,  7,  8,  9, 10 },
                    { 11, 12, 13, 14, 15 },
                    { 16, 17, 18, 19, 20 } };

    int** b = copyArray(4, 5, a);

    printf("%2d %2d %2d %2d %2d\n", a[0][0], a[0][1], a[0][2], a[0][3], a[0][4]);
    printf("%p\n", &a);
    printf("%p\n", a);
    printf("%p\n", *a);
    printf("%p\n", a[0]);
    printf("%p\n", &a[0]);
    printf("\n");
    printf("%2d %2d %2d %2d %2d\n", b[0][0], b[0][1], b[0][2], b[0][3], b[0][4]);
    printf("%p\n", &b);
    printf("%p\n", b);
    printf("%p\n", *b);
    printf("%p\n", b[0]);
    printf("%p\n", &b[0]);

    for (int i = 0; i < 4; i++) {
        free(b[i]);
    }

    free(b);
    return 0;
}

我知道二维数组基本上是指向数组的指针

不。二维数组是数组的数组 - 不涉及指针。 它将在内存中布置为

   +––––+
a: |  1 | a[0][0]
   +––––+
   |  2 | a[0][1]
   +––––+
   |  3 | a[0][2]
   +––––+
   |  4 | a[0][3]
   +––––+
   |  5 | a[0][4]
   +—–––+
   |  6 | a[1][0]
   +––––+
   |  7 | a[1][1]
   +—–––+
   |  8 | a[1][2]
   +––—–+
   |  9 | a[1][3]
   +––––+
   | 10 | a[1][4]
   +––––+
   | 11 | a[2][0]
   +––––+
   | 12 | a[2][1]
   +–——–+
     ...

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组内容的字符串文字,否则类型为“ T N 元素”的表达式将被转换,或“衰减", 到“指向T指针”类型的表达式。

从上图中可以看出,表达式aa[0]a[0][0]都具有相同的起始地址。

表达式a具有类型“ int的 5 元素数组的 4 元素数组” - 除非它是sizeof或一元&运算符的操作数,否则它“衰减”为“指向int 5 元素数组的指针”类型的表达式" ( int (*)[5] ) 其值是a[0]的地址。

表达式*a与表达式a[0]相同,并且具有“ int 5 元素数组”类型 - 同样,除非它是sizeof或一元&运算符的操作数,否则它“衰减”为类型为“的表达式”指向int " 的指针,其值是(*a)[0]的地址(与a[0][0]的地址相同)。

表达式a*a&aa[0]&a[0][0]都产生相同的地址值(以类型之间的任何表示差异为模),但它们具有不同的类型:

Expression    Type            "Decays" to        Equivalent expression
----------    ----            -----------        ---------------------
         a    int [4][5]      int (*)[5]         &a[0]
        *a    int [5]         int *              &(*a)[0] or &a[0][0]
        &a    int (*)[4][5]   n/a                n/a
      a[i]    int [5]         int *              &a[i][0]
     &a[i]    int (*)[5]      n/a                n/a
   a[i][j]    int             n/a                n/a
  &a[i][j]    int *           n/a                n/a

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM