对于字符串数组的malloc'ing的seg错误。如何摆脱它?在分配第二维时,我可以准确地发现它恰好发生

时间:2011-08-19 02:18:53

标签: c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

enum { buf = BUFSIZ };

char line[buf], **tab = NULL;

int cur_buf, count_lineMax = -1, count_line = -1,
    k, l;

int main (int argc, char **argv) {

    FILE *file1;
    file1 = fopen(argv[1], "r");

    cur_buf = buf;

    /*printf("%d\n", cur_buf);*/


    while(fgets(line, cur_buf, file1) != NULL) {
            count_lineMax++;
            /*printf("%c", line[j]);*/
    }
    /*printf("%d\n", count_lineMax);*/

    rewind(file1);

    tab = malloc(count_lineMax * sizeof(*tab));
    memset(tab, 0, count_lineMax * sizeof(*tab));

    /*printf("%d %ld %ld\n", count_lineMax, sizeof(*tab), count_lineMax * sizeof(*tab));*/

    if(tab == NULL) {
            printf("Mem_check\n");
            return EXIT_FAILURE;
    }

    for(k=0;k<=count_lineMax;k++) {
            tab[k] = malloc(cur_buf+1);
            memset(tab[k], 0, cur_buf+1);

            if(tab[k] == NULL) {
                    printf("Mem_check*\n");
                    return EXIT_FAILURE;
            }
    }

    printf("%d %ld %ld\n", cur_buf, sizeof(tab), cur_buf * sizeof(*tab));

    while(fgets(line, cur_buf, file1) != NULL) {

            count_line++;

            strcpy(tab[count_line], line);
            printf("%s", tab[count_line]);
    }
    for(l=0;l<count_lineMax;l++) {
            free(tab[l]);
    }
    free(tab);
    return 0;
    fclose(file1);
}

2 个答案:

答案 0 :(得分:3)

错误1:验证输入失败(潜在的段错误)

改变这个:

file1 = fopen(argv[1], "r");

对此:

if (argc != 2) {
    fputs("Usage: PROGNAME FILE\n", stderr);
    exit(1);
}
file1 = fopen(argv[1], "r");

错误2:逐个索引错误(潜在的段错误)

然后,按如下方式初始化变量:

count_lineMax = 0; // -1 is incorrect
count_line = 0; // -1 is incorrect

否则,你的数量太少了。我不知道你在哪里提出-1但是如果你有一个空文件,它应该有0行,对吧? (尝试将它送入一个空文件。它会崩溃。)

然后,将count_line++移到循环的底部:

while(fgets(line, cur_buf, file1) != NULL) {
        strcpy(tab[count_line], line);
        printf("%s", tab[count_line]);
        count_line++;
}

另外,将循环条件k<=count_lineMax更改为k < count_lineMax

错误3:错误检查逻辑错误

以下行是不可移植的,但它有效,例如在GNU系统上:

if (tab == NULL) {

将其更改为此,因此在malloc(0)返回NULL的系统上提供空文件时不会崩溃:

if (tab == NULL && count_lineMax) {

警告4:常数名称不佳,#5:任意/奇怪的常数值

最后,这很糟糕:

enum { buf = BUFSIZ };

问题是你不知道BUFSIZ是什么。它可能是任何东西(我认为至少512)。 512不是很大。只需选择一个数字,例如,

enum { BUFFER_SIZE = 1024 * 8 };

我建议不要使用名称buf来避免与局部变量混淆。使用编码样式有助于其他人阅读您的代码。更好的是,使变量名更有意义:

enum { MAX_LINE_LENGTH = 1024 * 8 };
// Or if that's too verbose,
enum { MAXLINELEN = 1024 * 8 };

错误#6:输出错误

请注意sizeof(tab)为您提供tab变量的大小 - 这是一个指针,或者是我系统上的8个字节。您无法使用sizeof获取tab中的元素数量。相反,count_lineMax会保留您要查找的号码。

<强>建议

两次循环输入是不必要的,也是有潜在危险的。恶意用户可以在您第一次阅读文件和第二次阅读文件时更改文件内容,从而导致程序崩溃。相反,我建议为tab使用动态大小的数组:只需在其中插入行,并在空间不足时增加大小。一种技术是每次填充时tab的大小加倍。这导致摊销的渐近运行时间相对于文件大小保持线性。

答案 1 :(得分:0)

这看起来有点怀疑:

tab = malloc(count_lineMax * sizeof(*tab));

您在初始化之前取消引用标签。