[英]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]
。 并输出第一个“行”的第一个元素的地址,即数组所占用内存范围的起始地址。
也就是说,整个数组的地址、其第一个“行”的地址和第一个“行”的第一个元素的地址彼此相等。 但是相应的表达式&a
、 a
、 *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]。
上面已经有两个有价值的答案,但我认为您仍然对这种情况感到困惑; 因为我在菜鸟时期也有同样的感觉(虽然我还不是专业人士)。
int a[4][5] = { ... };
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
指针”类型的表达式。
从上图中可以看出,表达式a
、 a[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
、 &a
、 a[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.