我使用malloc初始化了一个2D数组,用于大图的邻接矩阵,然后根据边缘列表初始化每个索引为0或1。但是我得到了一个分段错误。这是我的代码。
#include <stdio.h>
#include <stdlib.h>
int MAX = 50000;
void clustering(int **adj);
int main()
{
int i, j, k;
FILE *ptr_file1;
int **adj;
adj = (int **)malloc(sizeof(int *)*MAX);
for(i=0;i<MAX;++i)
adj[i] = (int *)malloc(sizeof(int)*MAX);
struct adjacency
{
int node1;
int node2;
};
struct adjacency a;
ptr_file1 = fopen("Email-Enron.txt","r"); //Opening file containing edgelist of approx 37000 nodes.
if (!ptr_file1)
return 1;
while(fscanf(ptr_file1,"%d %d",&a.node1, &a.node2)!=EOF)
{
adj[a.node1][a.node2] = 1; //Getting segmentation fault here
adj[a.node2][a.node1] = 1;
printf("adj[%d][%d] = %d adj[%d][%d] = %d\n",a.node1,a.node2,adj[a.node1][a.node2],a.node2,a.node1,adj[a.node2][a.node1]);
}
clustering(adj);
return (0);
}
这是我的输出
......
......
adj[85][119] = 1 adj[119][85] = 1
adj[85][154] = 1 adj[154][85] = 1
adj[85][200] = 1 adj[200][85] = 1
adj[85][528] = 1 adj[528][85] = 1
adj[85][604] = 1 adj[604][85] = 1
adj[85][661] = 1 adj[661][85] = 1
adj[85][662] = 1 adj[662][85] = 1
adj[85][686] = 1 adj[686][85] = 1
adj[85][727] = 1 adj[727][85] = 1
adj[85][1486] = 1 adj[1486][85] = 1
adj[85][1615] = 1 adj[1615][85] = 1
adj[85][2148] = 1 adj[2148][85] = 1
adj[85][2184] = 1 adj[2184][85] = 1
adj[85][2189] = 1 adj[2189][85] = 1
adj[85][2190] = 1 adj[2190][85] = 1
adj[85][2211] = 1 adj[2211][85] = 1
adj[85][3215] = 1 adj[3215][85] = 1
adj[85][4583] = 1 adj[4583][85] = 1
adj[85][4585] = 1 adj[4585][85] = 1
adj[85][4586] = 1 adj[4586][85] = 1
adj[85][4589] = 1 adj[4589][85] = 1
adj[85][4590] = 1 adj[4590][85] = 1
Segmentation fault (core dumped)
这里有什么问题。请帮忙......
答案 0 :(得分:2)
问题必须来自内存分配。在经典计算机上,sizeof(int)
为4,sizeof(int*)
可以是4(32位OS)或8(64位OS)。
在那里,你首先为50000个指针分配空间,因此至少50000 * 4 = 200000个字节。
然后,循环执行此操作以分配50.000 * 50.000 * 4 = 10.000.000.000字节= 10 GB!
由于您 NOT 检查malloc()
返回值,我的猜测是在此循环的某个时刻:
for(i=0;i<MAX;++i)
adj[i] = (int *)malloc(sizeof(int)*MAX);
malloc
始终返回NULL
。设表示M这样的指数。在你的情况下,我可以猜测M≥4591。
稍后,当您从文件中读取数据时,如果M≤NULL
,则会尝试访问a.node1
指针。
顺便说一句,您可以像这样分配2D数组:
int **array, i;
if(NULL == (array = malloc(sizeof(int*)*MAX))) {
printf("Oops, not enough memory ...\n");
return EXIT_FAILURE;
}
if(NULL == (array[0] = malloc(sizeof(int)*MAX*MAX))) {
printf("Oops, not enough memory ...\n");
free(array);
return EXIT_FAILURE;
}
for(i = 1; i < MAX; i++)
array[i] = array[0]+i;
// At this point, array is ready to use.
do_stuff();
// When you are done, freeing the memory is not tiresome :
free(array[0]);
free(array);
(请注意,在C中,您永远不会转换malloc的返回。)
这个分配和你的分配有什么区别?在你的,每个adj[i]
指向一个动态分配的数据块。因此,这些数据块几乎不可能在内存中连续存在。在我提议的那个中,只有2个内存分配,最后adj[i]
和adj[i+1]
指向的数据块是连续的。
注意:
大图的邻接矩阵
虽然邻接矩阵是一种在内存中存储图形的完全有效的方法,但是当图形往往很大时,你应该使用邻接列表。
答案 1 :(得分:1)
50000 * 50000
整数非常多。即,4字节整数是9Gb内存。你确定你分配了所有的内存吗?
添加支票:
if (!adj[i])
return 2;
请注意,您有为x64编译并在x64计算机上运行以使其正常工作。很可能你不需要那么多数据。
答案 2 :(得分:0)
在您的特定情况下,不需要分配指向int数组的指针数组。只需分配一个大小为MAX * MAX的单个数组。
答案 3 :(得分:0)
首先,在错误之前添加调试printf :
while(fscanf(ptr_file1,"%d %d",&a.node1, &a.node2)!=EOF)
{
printf("%d %d\n", a.node1, a.node2);
adj[a.node1][a.node2] = 1; //Getting segmentation fault here
adj[a.node2][a.node1] = 1;
}
这样,您可以在程序崩溃之前查看数组索引是否超出范围。
这只是用于调试目的的快速修复 - 实际上你应该进行适当的错误检查:
while(fscanf(ptr_file1,"%d %d",&a.node1, &a.node2)!=EOF)
{
if (a.node1 >= MAX || a.node2 >= MAX)
{
fprintf(stderr, "range error: a.node1 = %d, a.node2 = %d\n", a.node1, a.node2);
exit(1);
}
adj[a.node1][a.node2] = 1; //Getting segmentation fault here
adj[a.node2][a.node1] = 1;
}
答案 4 :(得分:0)
发表评论。使用一个维度位图,但一个维度可以用作二维,可用于图形
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define MAX 4000000
unsigned char *bitmapinit(int n);
unsigned char chkbit(unsigned char *map, int n);
void setbit(unsigned char *map, int n);
void unsetbit(unsigned char *map, int n);
int main(int argc, char *argv[])
{
unsigned int i;
unsigned char *bitmap = bitmapinit(MAX);
if (!bitmap) {
perror("malloc: ");
exit(EXIT_FAILURE);
}
for (i = 0; i < MAX; i++) {
setbit(bitmap, i);
}
for (i = 0; i < MAX; i += 5) {
unsetbit(bitmap, i);
}
for (i = 0; i < MAX; i++) {
printf("bit #%d = %d\n", i, (chkbit(bitmap, i))?1:0);
}
return 0;
}
unsigned char *bitmapinit(int n)
{
return calloc(sizeof(unsigned char), n / 8 + 1);
}
unsigned char chkbit(unsigned char *map, int n)
{
return (unsigned char)map[n / 8] & (1 << (n % 8));
}
void setbit(unsigned char *map, int n)
{
map[n / 8] = map[n / 8] | (1 << (n % 8));
}
void unsetbit(unsigned char *map, int n)
{
map[n / 8] = map[n / 8] & ~(1 << (n % 8));
}
如果需要,我可以解释它是如何用于图表的。
节省空间8倍。对于50000 x 50000的矩阵,你需要~300MB,图形可以是方向的,但不是多重链接的
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#define ROW 50
#define COL 55
unsigned int *bitmapinit(int, int);
bool chkbit(unsigned int *, int, int, int);
void setbit(unsigned int *, int, int, int);
void unsetbit(unsigned int *, int, int, int);
int main(int argc, char *argv[])
{
unsigned int i, j;
unsigned int *bitmap = bitmapinit(ROW, COL);
if (!bitmap) {
perror("malloc: ");
exit(EXIT_FAILURE);
}
for (i = 0; i < ROW; i+=2)
for (j = 0; j < COL; j+=2)
setbit(bitmap, i, j, COL);
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
printf("%d ",(chkbit(bitmap, i, j, COL)) ? 1 : 0);
}
printf("\n");
}
printf("\n");
for (i = 0; i < ROW; i++)
for (j = 0; j < COL; j++)
setbit(bitmap, i, j, COL);
for (i = 0; i < ROW; i += 3)
for (j = 0; j < COL; j += 3)
unsetbit(bitmap, i, j, COL);
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
printf("%d ",(chkbit(bitmap, i, j, COL)) ? 1 : 0);
}
printf("\n");
}
return 0;
}
unsigned int *bitmapinit(int row, int col) //n it is ROWS, m it is COLUMNS
{
return calloc(sizeof(unsigned int), (row * col) / 32 + 1);
}
bool chkbit(unsigned int *map, int row, int col, int n)
{
return map[(row * n + col) / 32] & (1 << (row * n + col) % 32);
}
void setbit(unsigned int *map, int row, int col, int n)
{
map[(row * n + col) / 32] = map[(row * n + col) / 32] | (1 << (row * n + col) % 32);
}
void unsetbit(unsigned int *map, int row, int col, int n)
{
map[(row * n + col) / 32] = map[(row * n + col) / 32] & ~(1 << (row * n + col) % 32);
}
程序并不复杂,实际上它是一个二维数组,但是数组的每个元素都可以设置为只有0或1
但值50000 * 50000可以使用很长时间
分别设置需要调用setbit(unsigned char *map, int Y, int X, int LenOfRow);
的XY位
清除XY unsetbit(unsigned char *map, int Y, int X, int LenOfRow);
位
并获得位XY checkbit(unsigned char *map, int Y, int X, int LenOfRow);
再次提醒您LenOfRow
的值不应在一个数组中更改
答案 5 :(得分:0)
正如其他人所说,你的问题很可能是你的2D阵列的庞大规模。所以你有三个选择:
优化邻接矩阵的大小。您可以使用int8_t
而不是int
将内存消耗减少四分之一(在大多数系统上)。您可以使用构成矩阵的整数的各个位将其减去另一个因子8。这是32的因素,足以让您的矩阵降低到可管理的大小。
您可以使用以下访问器:
void setAdjacent(int32_t** matrix, int x, int y) {
matrix[x][y/32] |= (1 << (y & 31));
}
int isAdjacent(int32_t** matrix, int x, int y) {
return matrix[x][y/32] & (1 << (y & 31));
}
利用邻接矩阵稀疏的事实。对于每个节点,存储与其相邻的所有其他节点的列表。
购买更多内存。
你也可以像这样使用真正的2D数组:
int32_t (*matrix)[MAX] = malloc(MAX*sizeof(*matrix));
这避免了为每一行分配数组的麻烦,并避免了一个指针间接的开销。您只需要相应地更改访问者的签名,其内容根本不会改变。