0

我正在使用此函数逐字符读取文本文件或标准输入

void readLine(FILE *stream, char **string) {
    char c;
    int counter = 0;

    do {
        c = fgetc(stream);
        string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));
        string[0][counter++] = c;
    } while(c != ENTER && !feof(stream));

    string[counter-1] = '\0';
}

但是当我调用它时,我的程序崩溃了,我真的不知道为什么,因为我没有忘记 0 终止符,而且我确信我正确存储了 char 序列。我已经验证了字符串长度,但看起来没问题。

4

3 回答 3

2

这是一个错误:

do {
    c = fgetc(stream);
    // What happens here?!? 
} while(c != ENTER && !feof(stream));

“这里发生的事情”是您在检查 EOF 之前添加的,哎呀cstring

这是非常不好的:

    string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));

在一个循环中。 realloc是一个潜在的昂贵调用,你对每个输入字节都这样做!请求一个(显然)没有分配任何东西的指针参数也是一个愚蠢和令人困惑的接口——传递指针通常表明已经完成。如果string是静态数组呢?相反,分配块并返回一个指针:

char *readLine (FILE *stream) {
// A whole 4 kB!
    int chunksz = 4096;
    int counter = 0;
    char *buffer = malloc(chunksz);
    char *test;
    int c;
    if (!buffer) return NULL;

    while (c = fgetc(stream) && c != ENTER && c != EOF) {
        buffer[counter++] = (char)c;
        if (counter == chunksz) {
            chunksz *= 2;
            test = realloc(buffer, chunksz);
        // Abort on out-of-memory.
            if (!test) {
                free(buffer);
                return NULL;
            } else buffer = test;
        }
    }
// Now null terminate and resize.
    buffer[counter] = '\0';
    realloc(buffer, counter + 1);
    return buffer;
}

这是一个标准的“2 的幂”分配方案(它加倍)。如果你真的想提交一个指针,预先分配它并提交一个“最大长度”参数:

void *readLine (FILE *stream, char *buffer, int max) {
    int counter = 0;
    int c;

    while (
        c = fgetc(stream)
        && c != ENTER
        && c != EOF
        && counter < max - 1
    ) buffer[counter++] = (char)c;
// Now null terminate.
    buffer[counter] = '\0';
}       
于 2013-08-30T09:03:00.513 回答
1

这段代码有几个问题:

  1. fgetc()返回int
  2. 不要malloc()在 C 中转换 and friends的返回值。
  3. 避免使用sizeof (char),它只是一种非常笨拙的写法1,所以乘以它是非常多余的。
  4. 通常,缓冲区一次增长超过 1 个字符,realloc()可能会很昂贵。
  5. string[0]会更清楚地写为*string,因为它不是数组,而只是指向指针的指针。
  6. 您围绕文件结尾的逻辑意味着它将存储的截断版本EOF,不是很好。
于 2013-08-30T08:26:45.527 回答
1

更改此行

string[counter-1] = '\0';

string[0][counter-1] = '\0';

您想终止存储在string[0].

于 2013-08-30T08:19:47.773 回答