动态初始化大型数组时出现段错误 11
Segfault 11 when initializing large arrays dynamically
您好,我正在使用 C 来完成一项学校作业。我必须道歉,我对像 C 这样的低级语言很生疏。当我尝试动态初始化一些数组时,当 n>100 时,我的代码给出了段错误 11。我试图启动 Valgrind 以了解发生了什么,但我不太了解调试日志,因为它报告的内存块比我打算分配的 n 值大得多。任何人都可以帮忙看看有什么问题吗?谢谢!
我的代码(当我将二维矩阵的每个条目都设置为1时发生错误):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int n;
typedef struct{
float x;
float y;
} Point2D;
float rand_float(){
return (float)rand()/RAND_MAX;
}
int main(void) {
srand(time(NULL));
scanf("%d", &n);
int (*adjm)[n][n] = malloc( sizeof(float[n][n])+1 );
Point2D (*vcoord)[n] = malloc( sizeof(Point2D[n])+1 );
// initialize coords
for (int i = 0; i < n; i++){
(*vcoord[i]).x = rand_float();
(*vcoord[i]).y = rand_float();
printf("%d %f %f \n", i, (*vcoord[i]).x, (*vcoord[i]).y);
}
for (int x = 0; x < n; x++){
for (int y = 0; y < n; y++){
*adjm[x][y] = 1;
}
}
// free up memory
free(*adjm);
free(*vcoord);
return 0;
}
当我让 n=200 时,Valgrind 日志的前几行:
==18832== Memcheck, a memory error detector
==18832== Copyright (C) 2002-2017, and GNU GPLd, by Julian Seward et al.
==18832== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18832== Command: ./out
==18832== Parent PID: 1670
==18832==
==18832== Invalid write of size 4
==18832== at 0x1089F4: main (in /home/usrname/valgrindtest/out)
==18832== Address 0x5257050 is 1,600 bytes inside a block of size 1,601 alloc'd
==18832== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18832== by 0x1089B8: main (in /home/usrname/valgrindtest/out)
==18832==
==18832== Invalid write of size 4
==18832== at 0x108A23: main (in /home/usrname/valgrindtest/out)
==18832== Address 0x5257054 is 3 bytes after a block of size 1,601 alloc'd
==18832== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
在(*vcoord[i]).x = rand_float();
中:[]
运算符比解引用*
具有更高的precedence,所以这里需要的是(*vcoord)[i].x
。否则,您会将 vcoord
视为大小为 n
的数组数组,并使用该数组的第 i
个元素,该元素超出范围。同样,对于 vcoord
和 adjm
的所有其他用途,需要 (*adjm)[i][j]
.
这解释了 1600:Point2D
在您的平台上很可能是 8 个字节,所以 Point2D[200]
是 1600 个字节。因此 vcoord[1]
指的是这些 1600 字节数组的数组元素 1,它位于距基地址 vcoord
的偏移量 1600 处 - 就在末尾。
其他危害较小的错误:
int (*adjm)[n][n] = malloc( sizeof(float[n][n])+1 );
: float
应该是 int
这里, +1
没有用。 (可能不是导致崩溃的原因,因为 float
和 int
在大多数常见平台上具有相同的大小。)许多人更喜欢通过编写 malloc(sizeof(*adjm))
来避免这种不匹配的可能性.
free(*adjm);
:malloc
分配的指针在变量adjm
中,不在其指向的数组中。在下一行创建 free(adjm);
和 free(vcoord);
。但是,它实际上不应该有任何影响,因为 *adjm
是 adjm
指向的数组,并且它会衰减回指向同一地址的指针。
请注意,您在这里选择了一种复杂的代码编写方式。分配像 vcoord
这样的一维数组的正常方法是使用,不是指向数组的指针,而是指向相关对象类型的指针,然后使用 malloc
创建数组以指向它进入。所以更典型的写法是
Point2D *vcoord = malloc(n * sizeof(Point2D)); // or (n * sizeof *vcoord)
vcoord[i].x = rand_float();
free(vcoord);
同样,对于二维数组 adjm
,不要使用指向二维数组的指针,而是指向一维数组的数组的指针。所以
int (*adjm)[n] = malloc(n * sizeof(int[n]));
// or: (n * sizeof *adjm)
// or even: (n * n * sizeof(int))
adjm[x][y] = 1;
free(adjm);
这避免了对 2D 数组指针进行棘手的取消引用的需要,并使语法更加简单。
您好,我正在使用 C 来完成一项学校作业。我必须道歉,我对像 C 这样的低级语言很生疏。当我尝试动态初始化一些数组时,当 n>100 时,我的代码给出了段错误 11。我试图启动 Valgrind 以了解发生了什么,但我不太了解调试日志,因为它报告的内存块比我打算分配的 n 值大得多。任何人都可以帮忙看看有什么问题吗?谢谢!
我的代码(当我将二维矩阵的每个条目都设置为1时发生错误):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int n;
typedef struct{
float x;
float y;
} Point2D;
float rand_float(){
return (float)rand()/RAND_MAX;
}
int main(void) {
srand(time(NULL));
scanf("%d", &n);
int (*adjm)[n][n] = malloc( sizeof(float[n][n])+1 );
Point2D (*vcoord)[n] = malloc( sizeof(Point2D[n])+1 );
// initialize coords
for (int i = 0; i < n; i++){
(*vcoord[i]).x = rand_float();
(*vcoord[i]).y = rand_float();
printf("%d %f %f \n", i, (*vcoord[i]).x, (*vcoord[i]).y);
}
for (int x = 0; x < n; x++){
for (int y = 0; y < n; y++){
*adjm[x][y] = 1;
}
}
// free up memory
free(*adjm);
free(*vcoord);
return 0;
}
当我让 n=200 时,Valgrind 日志的前几行:
==18832== Memcheck, a memory error detector
==18832== Copyright (C) 2002-2017, and GNU GPLd, by Julian Seward et al.
==18832== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18832== Command: ./out
==18832== Parent PID: 1670
==18832==
==18832== Invalid write of size 4
==18832== at 0x1089F4: main (in /home/usrname/valgrindtest/out)
==18832== Address 0x5257050 is 1,600 bytes inside a block of size 1,601 alloc'd
==18832== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18832== by 0x1089B8: main (in /home/usrname/valgrindtest/out)
==18832==
==18832== Invalid write of size 4
==18832== at 0x108A23: main (in /home/usrname/valgrindtest/out)
==18832== Address 0x5257054 is 3 bytes after a block of size 1,601 alloc'd
==18832== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
在(*vcoord[i]).x = rand_float();
中:[]
运算符比解引用*
具有更高的precedence,所以这里需要的是(*vcoord)[i].x
。否则,您会将 vcoord
视为大小为 n
的数组数组,并使用该数组的第 i
个元素,该元素超出范围。同样,对于 vcoord
和 adjm
的所有其他用途,需要 (*adjm)[i][j]
.
这解释了 1600:Point2D
在您的平台上很可能是 8 个字节,所以 Point2D[200]
是 1600 个字节。因此 vcoord[1]
指的是这些 1600 字节数组的数组元素 1,它位于距基地址 vcoord
的偏移量 1600 处 - 就在末尾。
其他危害较小的错误:
int (*adjm)[n][n] = malloc( sizeof(float[n][n])+1 );
:float
应该是int
这里,+1
没有用。 (可能不是导致崩溃的原因,因为float
和int
在大多数常见平台上具有相同的大小。)许多人更喜欢通过编写malloc(sizeof(*adjm))
来避免这种不匹配的可能性.free(*adjm);
:malloc
分配的指针在变量adjm
中,不在其指向的数组中。在下一行创建free(adjm);
和free(vcoord);
。但是,它实际上不应该有任何影响,因为*adjm
是adjm
指向的数组,并且它会衰减回指向同一地址的指针。
请注意,您在这里选择了一种复杂的代码编写方式。分配像 vcoord
这样的一维数组的正常方法是使用,不是指向数组的指针,而是指向相关对象类型的指针,然后使用 malloc
创建数组以指向它进入。所以更典型的写法是
Point2D *vcoord = malloc(n * sizeof(Point2D)); // or (n * sizeof *vcoord)
vcoord[i].x = rand_float();
free(vcoord);
同样,对于二维数组 adjm
,不要使用指向二维数组的指针,而是指向一维数组的数组的指针。所以
int (*adjm)[n] = malloc(n * sizeof(int[n]));
// or: (n * sizeof *adjm)
// or even: (n * n * sizeof(int))
adjm[x][y] = 1;
free(adjm);
这避免了对 2D 数组指针进行棘手的取消引用的需要,并使语法更加简单。