[英]Getting segmentation fault using malloc for 2D array
我已經使用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)
這是怎么了,請幫助...
問題一定來自內存分配。 在經典計算機上, 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!
由於您不檢查malloc()
返回值,我的猜測是在此循環的某個時刻:
for(i=0;i<MAX;++i)
adj[i] = (int *)malloc(sizeof(int)*MAX);
malloc
始終返回NULL
。 讓M表示這樣的索引。 在您的情況下,我可以猜測M≥4591。
稍后,當從文件中讀取數據時,如果a.node1
,則嘗試訪問NULL
指針。
順便說一下,您可以像這樣分配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]
指向的數據塊是連續的。
注意:
大圖的鄰接矩陣
盡管鄰接矩陣是將圖形存儲在內存中的一種完全有效的方法,但是當圖形往往很大時,您應該使用鄰接列表。
50000 * 50000
整數是很多。 即,它是4字節整數的9Gb內存。 您確定要分配所有內存嗎?
添加支票:
if (!adj[i])
return 2;
請注意,您必須為x64編譯並在x64機器上運行才能運行。 最有可能您不需要那么多數據。
在您的特定情況下,無需分配指向整數數組的指針數組。 只需分配一個整數數組,其大小為MAX * MAX。
首先,在錯誤之前添加一個調試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;
}
征求意見。 使用一維位圖,但一維可以用作二維空間,對圖形很有用
#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可以長時間工作
要分別設置XY位,您需要調用setbit(unsigned char *map, int Y, int X, int LenOfRow);
清除位XY unsetbit(unsigned char *map, int Y, int X, int LenOfRow);
並獲取XY校驗位的值checkbit(unsigned char *map, int Y, int X, int LenOfRow);
再次提醒您, LenOfRow
的值不應在一個數組中更改
正如其他人指出的那樣,您的問題很可能是2D陣列的絕對大小。 因此,您有三種選擇:
優化鄰接矩陣的大小。 使用int8_t
而不是int
可以將內存消耗減少四倍(在大多數系統上)。 您可以使用構成矩陣的整數的各個位將其減少八分之一。 這是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)); }
利用您的鄰接矩陣稀疏這一事實。 對於每個節點,存儲其相鄰的所有其他節點的列表。
購買更多RAM。
您也可以像這樣使用真正的2D數組:
int32_t (*matrix)[MAX] = malloc(MAX*sizeof(*matrix));
這避免了為每行分配數組的麻煩,並且避免了一個指針間接的開銷。 您只需要相應地更改訪問器的簽名,它們的內容就不會改變。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.