如果以下分配有效:
int a[2] = {1,2};
int* b = a;
那么这样做有什么问题:
int a[2][2]={1,2,3,4};
int** b = a;
C++给出了一个错误,它无法将int[][]
转换为int**
。如果int[]
与int*
相同,那么这两种类型之间有什么区别
发布于 2011-12-06 12:40:36
这是经常出现的事情,所以我将尽可能清楚地解释它。
当您创建数组时,它将元素连续地存储在内存中,因此:
int arr[2] = { 1, 2 };
翻译为:
arr:
+---+---+
| 1 | 2 |
+---+---+
指针指向内存中的一个对象,当被解除引用时,它通过一元*
或[]
访问那个连续的内存。所以在
int *ptr = arr;
ptr
(如果您喜欢,也可以称为&ptr[0]
)指向1
所在的框,而ptr + 1
(或&ptr[1]
)指向2
所在的框。这是有道理的。
但是如果数组在内存中是连续的,那么数组的数组在内存中也是连续的。所以:
int arr[2][2] = {{ 1, 2 }, { 3, 4 }};
内存中的内容如下所示:
arr:
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
它看起来很像我们的平面阵列。
现在,让我们考虑一下指向int
的指针在内存中是如何布局的:
ptr:
+-------+-------+
| &sub1 | &sub2 |
+-------+-------+
sub1:
+---+---+
| 1 | 2 |
+---+---+
sub2:
+---+---+
| 3 | 4 |
+---+---+
ptr
(或&ptr[0]
)指向sub1
,ptr + 1
(或&ptr[1]
)指向sub2
。sub1
和sub2
彼此没有实际关系,可以在内存中的任何位置,但因为它是指向指针的指针,所以保留了2D数组的双重引用,即使内存结构不兼容。
类型为T
的数组衰减为指向类型T
的指针,但类型为T
的数组不衰减为指向类型T
的指针,它们衰减为指向类型为T
的数组的指针。因此,当我们的2D arr
衰减为指针时,它不是指向int
的指针,而是指向int [2]
的指针。这种类型的全名是int (*)[2]
,要使您的代码行正常工作,您需要使用
int (*ptr)[2] = arr;
哪一个是正确的类型。ptr
希望指向一个连续的内存数组,就像arr
一样-- ptr
(或&ptr[0]
)指向arr
,ptr + 1
(或&ptr[1]
)指向&arr[1]
。ptr[0]
指向容纳1
的盒子,ptr[1]
指向容纳3
的盒子,因此ptr[0][0]
产生1,ptr[0][1]
产生2,依此类推。
为什么你需要知道这一点? 2D指针似乎比它们的价值更复杂-如果你使用malloc
,你必须在循环中重复调用malloc
,并对free
做同样的事情。或者,您可以使用一些邪恶的*技巧来使一个平面的一维内存分配行为类似于一个2D数组:
// x and y are the first and second dimensions of your array
// so it would be declared T arr[x][y] if x and y were static
int (*arr)[y] = malloc(x * y * sizeof(arr[0][0]));
if(!arr) /* error */;
现在,arr
指向大小为y
的int
对象数组的连续块。因为它指向的对象是一个数组,所以我们不需要int **
对象的双指针间接寻址,当您完成后,您可以通过一次调用释放它:
free(arr);
将其与使用int **
的版本进行比较
int **arr = malloc(x * sizeof(*arr));
if(!arr) /* error */;
for(size_t ii = 0; ii < x; ii++)
{
arr[ii] = malloc(y * sizeof(**arr));
if(!arr[ii])
{
free(arr[ii]);
free(arr);
}
}
// do work
for(size_t ii = 0; ii < x; ii++)
free(arr[ii]);
free(arr);
上面的代码有一个内存泄漏。看看你能不能找到。(或者只使用带有那些看似棘手的数组指针的版本。)
https://stackoverflow.com/questions/8395255
复制相似问题