【问题标题】:getting string from file从文件中获取字符串
【发布时间】:2013-06-24 23:07:59
【问题描述】:

为什么这段代码的输出是内存中的一些随机单词?

void conc()
{
    FILE *source = fopen("c.txt", "r+");
    if(!source)
    {
        printf("Ficheiro não encontrado");
        return;
    }

    short i = 0;
    while(fgetc(source) != EOF)
        i++;

    char tmp_str[i];
    fgets(tmp_str, i, source);
    fclose(source);
    printf("%s", tmp_str);
}

我想这应该给我文件的内容。

【问题讨论】:

  • 你的应用编译了吗?
  • 您的while 循环是否符合预期?

标签: c string file get


【解决方案1】:

因为在您使用fgetc() 浏览文件后,位置指示器位于文件末尾。 fgets() 没有什么可读的。您需要重置它,使其使用rewind(source); 指向开头。

顺便说一句,不要使用fgetc() 遍历文件,这是一个非常丑陋的解决方案。使用fseek() 和ftell() 或lseek() 来获取文件的大小:

fseek(source, SEEK_END, 0);
long size = ftell(source);
fseek(source, SEEK_SET, 0); // or rewind(source);

替代方案:

off_t size = lseek(source, SEEK_END, 0);
rewind(source);

【讨论】:

  • @TelmoVaz 不客气。顺便说一句,不要循环文件两次,请改用ftell()。
【解决方案2】:

在fgets(tmp_str, i, source);之前使用rewind(source);

【讨论】:

    【解决方案3】:

    在您的 fgetc() - 循环之后,您已经到达 EOF,如果您不 fseek( source, 0l, SEEK_SET ) 回到开头,您将不会获得更多数据。 无论如何,您应该避免两次读取文件。请改用fstat( fileno(source), ... ) 来确定文件大小。

    【讨论】:

      【解决方案4】:

      fgetc 从流中读取一个字符。 fgets 从流中读取一个字符串。

      现在在您的代码中,您正在遍历文件末尾。因此,对流上的 fgets 的调用将简单地返回 NULL 并保持缓冲区内容不变。在您的情况下,您的缓冲区未初始化。这解释了您看到的随机值。

      我建议不要使用 fgetc 读取完整的文件内容来获取字符数,而是使用 fseek / ftell(请参阅此thread 的答案)

      【讨论】:

        【解决方案5】:

        您的代码错误。如前所述:

        1. 你不应该读两次文件
        2. 要动态分配数组,必须使用 operator new(在 c++ 中) 或函数 malloc(在 c 中)

        如果您需要代码来读取文件的内容,请尝试下一步(抱歉,我没有编译它。无论如何它应该可以正常工作):

        FILE* source = fopen("c.txt", "r+b");
        if(!source){return;}
        fseek(source, 0, SEEK_END);
        size_t filesize = ftell(source);
        fseek(source, 0, SEEK_SET);
        char* buf = new char[filesize+1]; // +1 is for '/0'
        fread(buf, sizeof(char), filesize, source);
        fclose(source);
        buf[filesize]=0;
        printf("%s", buf);
        delete buf;
        

        【讨论】:

          【解决方案6】:

          每次调用 fgetc() 时,都会将内部文件指针前进一个字符。在您的 while() 循环结束时,文件指针将位于文件末尾。意图读取文件句柄的后续调用将因 EOF 条件而失败。

          fgets 手册说:

          如果在尝试读取字符时遇到文件结尾,则设置 eof 指示符 (feof)。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(str 的内容保持不变)。

          结果是 tmp_str 保持不变。调用 printf 时返回的垃圾实际上是 conc() 函数堆栈的一部分。

          解决问题的方法是在调用 fgets() 之前使用 fseek() 倒回文件指针。

          fseek(source, 0, SEEK_SET);
          

          那么获取文件大小的更好方法是 fseek 到文件末尾,并使用 ftell 获取当前位置:

          long size;
          fseek(source, 0, SEEK_END);
          size = ftell(source);
          

          话虽如此,您的代码仍然存在问题。当您在堆栈上分配(函数本地的变量)时,您必须在编译时告诉变量的大小。在这里,您的编译器分配了一个长度为 0 的 char 数组。如果您使用 C++ 编码,我建议您使用关键字 new 的 malloc 调查动态分配。

          正确的分配应该是这样的:

          char *tmp_str = malloc(size);
          // Here you read the file
          free(tmp_str);
          

          一个更简单的解决方案可能是预先分配一个足够大的字符串来保存您的文件。

          char tmp_str[1024 * 100]; // 100Kb
          

          然后使用我们之前得到的 size 变量在读取之前检查文件是否适合 tmp_str。

          【讨论】:

            猜你喜欢
            • 2015-08-06
            • 2012-09-20
            • 2013-04-10
            • 2015-03-26
            • 2016-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多