[英]How to correct segmentation fault in my C program
我很難調試下面為knapSack編寫的程序
#include <stdio.h>
#include <stdlib.h>
#include "timer.h"
#define MAX(x,y) ((x)>(y) ? (x) : (y))
#define table(i,j) table[(i)*(C+1)+(j)]
int main(int argc, char **argv) {
FILE *fp;
long N, C, opt; // # of objects, capacity
int *weights, *profits, *table, *solution; // weights and profits
int verbose;
// Temp variables
long i, j, count, size, size1, ii, jj;
// Time
double time;
// Read input file:
// first line: # of objects, knapsack capacity,
// next lines: weight and profit of next object (1 object per line)
if ( argc > 1 ) {
fp = fopen(argv[1], "r");
if ( fp == NULL) {
printf("[ERROR] : Failed to read file named '%s'.\n", argv[1]);
exit(1);
}
} else {
printf("USAGE : %s [filename].\n", argv[0]);
exit(1);
}
if (argc > 2) verbose = 1; else verbose = 0;
fscanf(fp, "%ld %ld", &N, &C);
printf("The number of objects is %ld, and the capacity is %ld.\n", N, C);
size = N * sizeof(int);
size1 = C * sizeof(int);
weights = (int *)malloc(size);
profits = (int *)malloc(size);
table = (int *)malloc(size*size1);
solution= (int *)malloc(size);
if ( weights == NULL || profits == NULL ) {
printf("[ERROR] : Failed to allocate memory for weights/profits.\n");
exit(1);
}
for ( i=0 ; i < N ; i++ ) {
count = fscanf(fp, "%d %d", &(weights[i]), &(profits[i]));
if ( count != 2 ) {
printf("[ERROR] : Input file is not well formatted.\n");
exit(1);
}
}
fclose(fp);
initialize_timer ();
start_timer();
// Solve for the optimal profit (create the table)
for(j=0; j<=C; j++) {
table(0,j)=0;
}
for(ii=1;ii<=N;ii++) {
for(jj=0; jj<=C; jj++) {
if(weights[ii-1]>jj) {
table(ii,jj)=table(ii-1,jj);
}
else {
table(ii,jj)=MAX(table(ii-1,jj),(profits[ii-1]+table(ii-1,jj-weights[ii-1])));
}
}
}
opt=table(N,C);
// We only time the creation of the table
stop_timer();
time = elapsed_time ();
printf("The optimal profit is %ld Time taken : %lf.\n",opt,time);
// End of "Solve for the optimal profit"
// Find the solution (choice vector) by backtracking through the table
printf("Solution vector is: \n");
j=C;
for(i=N;i>0;i--) {
if(table(i,j)==table(i-1,j)) {
//printf("Object %d not picked", i);
solution[i-1]=0;
}
else {
//printf("Object %d picked", i);
j=j-weights[i-1];
solution[i-1]=1;
}
}
for(i=0; i<N; i++) {
printf("%d ",solution[i]);
}
if (verbose) {
// print the solution vector
}
return 0;
}
對於較小的輸入,代碼運行良好。 但是對於N = 1200和C = 38400000或C的任何其他大輸入,該代碼將顯示分段錯誤。 以下是Valgrind的輸出:
The number of objects is 1200, and the capacity is 38400000.
==2297== Invalid write of size 4
==2297== at 0x400A4E: main (knap1.c:73)
==2297== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==2297==
==2297==
==2297== Process terminating with default action of signal 11 (SIGSEGV)
==2297== Access not within mapped region at address 0x8
==2297== at 0x400A4E: main (knap1.c:73)
==2297== If you believe this happened as a result of a stack
==2297== overflow in your program's main thread (unlikely but
==2297== possible), you can try to increase the size of the
==2297== main thread stack using the --main-stacksize= flag.
==2297== The main thread stack size used in this run was 8388608.
==2297==
==2297== HEAP SUMMARY:
==2297== in use at exit: 14,400 bytes in 3 blocks
==2297== total heap usage: 4 allocs, 1 frees, 14,968 bytes allocated
==2297==
==2297== LEAK SUMMARY:
==2297== definitely lost: 0 bytes in 0 blocks
==2297== indirectly lost: 0 bytes in 0 blocks
==2297== possibly lost: 0 bytes in 0 blocks
==2297== still reachable: 14,400 bytes in 3 blocks
==2297== suppressed: 0 bytes in 0 blocks
==2297== Rerun with --leak-check=full to see details of leaked memory
==2297==
==2297== For counts of detected and suppressed errors, rerun with: -v
==2297== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
Segmentation fault
這是有關使用不同輸入文件(k10.txt至k1200.txt)運行時的本地值(從gdb獲取)的信息:
for files with which I got correct output until it exceeded that fix. no. of byte value
fp = 0x0 N = 4131212846 C = 140737488347792 opt = 4294967295 weights =
0x0 profits = 0x36dd221168 table = 0x7ffff7ffc6b8 solution =
0x36dd8101c0 verbose = 0 i = 0 j = 140737488348128 count = 2 size =
4198301 size1 = 1 ii = 4196160 jj = 4198224 time =
2.0728237613194911e-317
for k1200.txt
k1200.txt fp = 0x177b010 N = 1200 C = 38400000 opt = 4294967295
weights = 0x177b250 profits = 0x177c520 table = 0x8 solution =
0x7f3cd40008c0 verbose = 0 i = 1200 j = 0 count = 2 size = 4800 size1
= 153600000 ii = 4196160 jj = 4198224 time = 2.0728237613194911e-317
關於我的代碼有什么問題的任何輸入嗎? 以及如何糾正該程序,使其永遠不會顯示分段錯誤?
您在這里要求太多的內存:
table = (int *)malloc(size*size1);
正好為1200 * 38400000 * sizeof (int) * sizeof (int)
,這大約是74GB的內存(假設sizeof (int) == 4
)。 您的計算機無法徹底處理這么大的塊,因此分配失敗,並且失敗時,將返回NULL
指針。 您應該檢查以下情況:
if (table == NULL) {
fprintf(stderr, "Memory allocation failed :(");
exit(1);
}
您沒有使用NULL
指針,從而產生了分段錯誤。
不幸的是,這里不容易解決。 您應該重新考慮算法,看看是否真的需要一次如此大的塊,或者可以重用較小的塊。
一個較小的問題是,您需要的內存是您所需內存的4倍(仍然假設sizeof (int) == 4
)。 實際上,當您malloc
size * size1
字節時,您將sizeof (int)
考慮在內兩次,一次是size = N * sizeof (int)
,一次是size1 = D * sizeof (int)
,而您顯然想要一個N * C * sizeof(int)
矩陣。
74GB / 4意味着18.5GB的空間仍然太大:您的OS也許可以在虛擬內存中處理它,但是當啟動交換時,它將變得非常緩慢。當然,除非您安裝了18 + GB的RAM。
無論如何,我想您正在使用table
作為true / false布爾矩陣。 每個元素可能都是32位int
,而您只使用了1位。 如果使用按位運算將32個單元格打包為一個整數,則可以將分配的大小減少32倍。 它可能會影響性能,但是肯定會將內存占用空間減小到計算機可以處理的大小。
如注釋中所建議,您也可以使用char
或bool
代替int
,因為它們通常較小。
在N = 1200和C = 38400000時,N * C為46,080,000,000。 您使用的是32位還是64位操作系統? 在32位上,您的買單可能溢出。 此外,您可能沒有足夠的內存來進行此計算。
查看您的算法,我發現您可能不需要將表分配為N * C,而只需分配2 * C。
for循環僅使用第ii-1行更新第ii行。 因此,一旦計算完ii,就不再需要ii-1。 這意味着您可以重用第ii-1行中的內存來存儲ii + 1等。因此,您實際上只需要兩行。
像這樣:
table = malloc(2*size1);
...
for(ii=1;ii<=N;ii++) {
iiOut = ii%2;
iiIn = (ii-1)%2;
for(jj=0; jj<=C; jj++) {
if(weights[ii-1]>jj) {
table(iiOut,jj)=table(iiIn,jj);
}
else {
table(iiOut,jj)=MAX(table(iiIn,jj),(profits[ii-1]+table(iiIn,jj-weights[ii-1])));
}
}
}
opt=table(iiOut,C);
好的,除了dohashi的問題外,還有幾件事。
您應該添加檢查以查看以下內存分配是否失敗:
if ( table == NULL ) {
printf("[ERROR] : Failed to allocate memory for calculation table.\n");
exit(1);
}
if ( solution == NULL) {
printf("[ERROR] : Failed to allocate memory for solution.\n");
exit(1);
}
如果您沒有足夠的內存來分配這些,現在您將知道。
接下來,我注意到您用於在2d表中建立索引的宏會神秘地添加一個未分配的額外列:
#define table(i,j) table[(i)*(C+1)+(j)]
看到那里的“(C + 1)”嗎? 它說該表的大小實際上為N *(C + 1)。 接下來,您稍后在表中從1到N以及從1到C進行索引
for(ii=1;ii<=N;ii++) {
for(jj=0; jj<=C; jj++) {
if(weights[ii-1]>jj) {
table(ii,jj)=table(ii-1,jj);
}
else {
table(ii,jj)=MAX(table(ii-1,jj),(profits[ii-1]+table(ii-1,jj-weights[ii-1])));
}
}
}
opt=table(N,C);
宏將table
的大小設置為N *(C + 1),實際上這要求表的大小為(N + 1)*(C + 2)。
我認為這里至少有一個問題,就是有人從FORTRAN轉換了此代碼,而沒有考慮到C中的數組是基於零而不是基於一的事實。 例如參見這里 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.