在使用memset初始化二维数组后打印二维数组时出现异常。如果我初始化每个元素然后访问它,那么就没有错误。 请帮助找出代码中的错误。
#include "stdafx.h"
#include "stdlib.h"
int r = 0;
int c = 0;
int **twoDArray() {
int *arr[5];
for (r = 0; r < 5; r++) {
arr[r] = (int*)malloc(2 * sizeof(int));
}
//
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 1;
printf("%d \n", arr[r][c]);
}
}
memset(arr, 0, 2 * 5 * sizeof(arr[0][0]));
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
printf("%d \n", arr[r][c]); //getting exception here.
}
}
return arr;
}
int main()
{
int **arr;
arr = twoDArray();
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 0;
printf("%d \n", arr[r][c]);
}
}
return 0;
}
答案 0 :(得分:4)
您没有2D阵列。你有一维指向一维数组的指针数组;这些数组中的每一个都可以(并且99.9%可能是)存储器中的不同地址。因此,您不能将它们视为一个连续的块,如memset
所做的那样。
最好的(也是最适合缓存的)选项是动态分配整个数组:
int *arr = malloc(2 * 5 * sizeof(int));
这将要求您进行手动索引:
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r * 2 + c] = 1;
printf("%d \n", arr[r * 2 + c]);
}
}
如果你知道编译时的数组大小(如果2
和5
是实际常量),你也可以使arr
指向一个实际的数组,允许语法2D索引:
typedef int Array[2];
Array *arr = malloc(5 * sizeof(Array));
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 1;
printf("%d \n", arr[r][c]);
}
}
请注意,在原始代码中,还有一个问题是您将指针返回到arr
,这是一个局部变量,使指针立即悬空。
答案 1 :(得分:3)
这是一个指针数组。你可以肯定两件事
arr[0]
与arr[4]
是连续的。但是谁告诉你每个指针指向的每个malloc分配的内存块也是连续的?没有人这样做。你认为它错了。
你的情况 肯定并非如此。这就是为什么你通过访问超出范围的内存来调用未定义的行为。 (在memset
)。
这样做 - 它会起作用
int (*arr)[2];
arr = malloc(sizeof *arr * 5);
// do memset - it's fine.
不要转换malloc
的返回值。这是多余的。
在早先的案例中有类似的事情: -
+-------------+
+-------+ +------>+ arr[0][0] |
arr[0] | | | | | arr[0][1]
| +-------------+ +------+------+
+-------+
| | +------+------+
arr[1] | +------->+ | |
+-------+ | | |
| | +-------------+ +------+------+
arr[2] | +-------------------------------------+ | |
+-------+ | | |
| | | +------+------+ +------+------+
arr[3] | +------------------>+ | |
+-------+ | | |
| | +------+------+
arr[4] | + |
+-------+
| +------+------+
+----------------------->+ | |
| | |
+------+------+