(另一个)关于C循环和数据结构的问题

时间:2011-01-22 03:43:38

标签: c segmentation-fault

我有一个程序(底部有可用的代码),它按照我想要的方式生成一个数字列表。该程序工作正常,并完全符合我的要求。我只是不喜欢我写它的方式。如果我改变一件事,它会返回“分段错误”,我也会在底部说。这是代码:

#include "stdio.h"
#include "stdlib.h"
#define NCH 81

// Generate swap-mode data for bonds for input.conf file

int main() 
{
    int i,j,k;
    int **dat2, *dat;
    //double *dat;

    int ns = 500;

    int nrow = NCH*(ns-1);

    dat = (int*) calloc(nrow, sizeof(int));
    dat2 = (int**) calloc(nrow,sizeof(int*));

    for (i=0; i<nrow; i++) {
        dat2[i] = (int*) calloc(2, sizeof(int));
        for (j=0; j<2; j++)
            dat2[i][j] = 0;
    }

    // Generates the bonds
    k=2;
    for (i=0; i<nrow; i++) {
        k--;
        for (j=0; j<2; j++) {
            dat2[i][j] = k++;
            if ( ((k%501) == 0) ) { 
                k--;
                dat2[i][j] = k++;
                k++;
            }
        }
    }

    FILE *inp2;
    inp2 = fopen("bonds.out", "w");

    for (i=1; i<=nrow; i++)
        fprintf(inp2, "%d %d\n", dat2[i-1][0], dat2[i-1][1]);

    fclose(inp2);

    // Generates the bond ID in the pattern 1 2 3 3 2 1 ... (appropriate for Bond swap!)
    k=1;
    while ( k < nrow ) {
        for (j=0; j<250; j++) {
            dat[k] = (j+1);
            k++;
        }
        for (j=250; j>0; j--) {
            dat[k] = j;
            k++;
        }
    }

    // Scans bonds.out (because just reporting dat2[][] returns segmentation error, not sure why.
    // scans the bonds.out file and stores both values into dm1 and dm2, then reports into 'results.out' file
    int dm1, dm2;

    FILE *inp;
    inp = fopen("input.out", "w");
    inp2 = fopen("bonds.out", "r");

    for (i=1; i<=nrow; i++) {
        fscanf(inp2, "%d %d", &dm1, &dm2);
        fprintf(inp, "%d  %d  %d  %d\n", i, dat[i], dm1, dm2);
    }



    printf("\nDone. All data has been written to \"input.out\"\n");

    fclose(inp2);
    fclose(inp);

    return 0;
}

现在,我不喜欢它首先将dat2[][]写入文件,然后扫描该文件以获取值。相反,为什么我不能将dat2[][]合并到写入"results.out"文件的主循环中?如果我这样做,我会得到分段错误。为了澄清,我的意思是在代码中更改这些行:

for (i=1; i<=nrow; i++) {
    fscanf(inp2, "%d %d", &dm1, &dm2);
    fprintf(inp, "%d  %d  %d  %d\n", i, dat[i], dm1, dm2);
}

对于这些:

for (i=1; i<=nrow; i++) {
    fprintf(inp, "%d  %d  %d  %d\n", i, dat[i], dat2[i-1][0], dat2[i-1][1]);
}

我喜欢解释,因为我对C仍然很新。

非常感谢! 阿米特

2 个答案:

答案 0 :(得分:4)

我认为您忘记从dat的数组索引中减去1,如下所示:

for (i=1; i<=nrow; i++) {
  fscanf(inp2, "%d %d", &dm1, &dm2);
  fprintf(inp, "%d  %d  %d  %d\n", i, dat[i-1], dm1, dm2);
}

导致段错误的原因是因为你循环到i <= nrow,这将在最后的循环迭代中超出dat的范围。

答案 1 :(得分:2)

我认为除了Relkin(正确)指出的内容之外,您的代码还有其他内容。

int nrow = NCH*(ns-1);
dat = (int*) calloc(nrow, sizeof(int));

如果我的计算是正确的,nrow == 81*(500-1)(== 40419),那么dat[40419]

关于以下爆炸性算法:

k=1;
while ( k < nrow ) {
    for (j=0; j<250; j++) {
        dat[k] = (j+1);
        k++;
    }
    for (j=250; j>0; j--) {
        dat[k] = j;
        k++;
    }
}

每个内部for循环将k增加250(因此每个while循环都会增加500),而k < 40419。这意味着有一个点k达到40001,条件得到满足,循环又多了一个。此时,在第二个for循环中,您超过40419并在内存中写入您不应该。看看那个并再次检查我的数学。

一旦进入while循环,并且条件失败,这并不意味着循环将自动退出。