【问题标题】:Why is this program not showing the first line again and again?为什么这个程序一次又一次不显示第一行?
【发布时间】:2011-01-03 10:23:26
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *readLine(FILE *inFile)  //Simply reads line in a text file till "\n"
{
    char *line = realloc(NULL, 1);
    char c;
    int i=0;
    while (!feof(inFile))
    {
        c = fgetc(inFile);
        if (ferror(inFile)) printf("Error reading");
        if (c == 10)
            {
                realloc(line,i+1);
                line[i]= 10;
                break;
            }
        realloc(line, i+1);
        line[i++] = c;
    }
    return line;
}

int main(int argc,char **argv)
{
    FILE *inFile;
    inFile = fopen("testFile","r");
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    return 0;
}

如果testFile的内容是:-

abc
def
ghi

三个 printf 语句应该显示“abc” 3 次。但是输出是:-

abc
def
ghi

我知道我在某个地方的概念是错误的。请帮忙。

【问题讨论】:

  • 你的标题和问题完全矛盾。你在问哪个问题?
  • 除了realloc 问题之外,您不应该调用feof 作为循环条件。你的循环结构应该是:int c; /* Note that this is int, not char */ while ((c = fgetc(inFile)) != EOF) { /* ... */ 参见c-faq.com/~scs/cclass/int/sx2h.html 以获得解释。此外,与其重新发明轮子,不如考虑使用fgets,或者如果您想要一个能够动态分配足够长的缓冲区以容纳整行的版本,请使用 Chuck Falconer 的公共域ggets 函数:cbfalconer.home.att.net/download/ggets.zip
  • 好的。我明白了。我读了c-faq ..thanx

标签: c gcc file-handling


【解决方案1】:

realloc() 的用法不正确。

realloc(line,i+1); // wrong

// OK
void *new_line = realloc(line,i+1);
if (!new_line)
{
    free(line);
    return NULL;
}
line = new_line;

因为line 是按值传递的,所以它没有改变。实际重新分配的内存在返回值中。 因此,line 一遍又一遍地保持不变,而您一遍又一遍地看到同一行。 编辑: 刚刚意识到即使这是一个错误,它也是不是什么会导致重复行。其他点仍然有效。

更糟糕的是:

  1. 每次丢失新分配的指针都会导致内存泄漏。
  2. 您可能正在访问已释放的内存,因为旧的 line 值在重新分配后可能会变得无效,如果它在堆的不同部分重新分配。
  3. 您正在为每个字符重新分配内存,这可能是一项昂贵的操作。

【讨论】:

  • 坏坏坏|!它应该是 void * tmp = realloc(line, i+1);如果 (tmp) { 行 = tmp; } else { /* 处理错误 */ }
  • 我会在这个 +1 答案中补充一点,你不应该为每个字符都 reallocing。这是一个相对昂贵的过程。调整缓冲区大小有两种常用方法。 1) 有一个初始分配(例如 1024 字节)和每次需要扩展缓冲区时添加的增量大小(512 字节)。并且 2) 具有默认大小(例如 64 字节),并且每次重新分配时都将大小加倍。哦,如果你想看到它们,你应该把 '\n' 放在你的字符串的末尾; printf 通常使用缓冲输出。
  • 你们说的都是对的,尽管我更愿意专注于手头的问题,而不是用太多信息压倒提问者。 :)
  • @asveikau 提供的代码中缺少错误处理,但在此函数的上下文中,实际上没有必要使用临时函数:您可以安全地分配给 line 并在失败时返回 NULL .
  • 其实是的,你是对的,realloc分配新指针失败时不会触及原来的指针。
【解决方案2】:

但我按值传递文件指针。所以我应该一次又一次地得到输出“abc”

啊,我理解你的困惑。

文件指针只指向实际的文件结构。当前偏移等状态不是指针的一部分,而是内部结构的一部分。

另一种思考方式是表示文件的实际对象是 FILE。要获得按引用传递的语义,您需要传递一个指向对象的指针。由于您是通过引用传递的,因此每一行都会从最后一行停止的地方开始。

【讨论】:

  • 是的..我得到了我真正想要的..非常感谢..也感谢其他人告诉了一些更重要的点...
【解决方案3】:

fgetc() 推进文件指针(即“要读取的下一个字符所在的位置”)。这就是您能够循环调用它并读取整行字符的方式。

经过换行符后,自然会移动到下一个字符,也就是下一行的开头。

您可以使用fseek() 函数修改文件指针。例如,调用 fseek(inFile, 0, SEEK_SET) 会将其重置为文件的开头,从而导致下一次 fgetc() 调用从文件的第一个字符重新开始。

【讨论】:

  • 但是我按值传递文件指针。所以我应该一次又一次地得到输出“abc”..
  • 您混淆了术语。指向文件的指针与也称为“文件位置指示器”的“文件指针”不同。您一次又一次地传递指向同一个文件的指针,但文件位置指示器随着每次调用 fgetc() 前进。正如 aib 所说,如果你想重新开始,你必须用 fseek() 重置它。
猜你喜欢
  • 2022-07-19
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多