【问题标题】:Why is fgets getting stuck on carriage return \r?为什么 fgets 卡在回车符 \r 上?
【发布时间】:2015-12-13 17:07:53
【问题描述】:

我是论坛和 c 的新手,所以请多多包涵。我正在尝试编写一个 c 程序,该程序接受一个文本文件并解析所有单词和字符,然后将它们保存到输出文本文件中。我正在使用 C99、Windows 7-64bit、MinGW、notepad、notepad++ 和 ASNI 格式的 txt 文件。我读过 fgets() 比 fscanf 更好地用于读取输入,因为它具有缓冲区溢出保护,所以我决定尝试使用它,但它在测试文件中存在一些标点符号问题(我认为这是回车\r)。我尝试使用 fscanf,除了它跳过所有的空白(我可以稍后添加,不关心)之外,它似乎可以很好地接收所有文本并将其打印到输出文件中。

这是我的测试代码:

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

void main(int argc, char* argv[])
{
    int limit=100, flimit=0, flimitmax=1900000000; //I stopped flimitmax short of the 2GB mark 
    char name[limit], copyname[limit];
    FILE *data, *output;

//Gets the value of a specified data file for reading   
    printf("\nPlease specify a file to format for data input.  NOTE: CHARACTERS LIMITIED TO %d\n", limit);
    fgets(name, limit, stdin); //takes input of size 'limit' and assigns it to 'name'
    size_t ln = strlen(name);   //gets the size of name[]
    if(name[ln-1]=='\n') name[ln-1]='\0'; //gets rid of newline character read in by fget
    strncpy(copyname, name, limit); //stores the value of the specified file name for use making the input and output files 
    strcat(name, ".txt"); //appends .txt file extension to the file name
    printf("\nYou chose file %s\n", name);

    data = fopen(name, "r"); //Checks to see if the specified data file exists and if it can be read
    if(data==NULL)
    {
        fprintf(stderr, "\nCan't open file %s!!!\n", name);
        exit(1);
    }

//Gets the size of the data file being worked.  Used later when the file is copied into the program using fgets.    
    fseek(data, 0, SEEK_END); // seek to end of file
    flimit = ftell(data)+1; // get current file pointer
    fseek(data, 0, SEEK_SET); // seek back to beginning of file
    if((flimit > flimitmax) || (flimit < 0))//Checks to see if flimit falls between 0 and 1.9GB.  If not, the file is larger than 1.9GB
    {
        printf("Error, max file size exceeded.  Program terminating\n");
        exit(1);
    }
    printf("File size is %d bytes\n", flimit);

//Creates a name for the output file
    strncpy(name, copyname, limit); //reassigns original value to name to make output file name
    strcat(name, "OUT.txt"); //appends OUT.txt file extension to the file name
    printf("\nOutput file is %s\n", name);

    output = fopen(name, "w"); //checks to see if the Input file exists and if it can be read
    if(output==NULL)
    {
        fprintf(stderr, "\nCan't open file %s!!!\n", name);
        exit(1);
    }

//Reads the data file and assigns values to the input and output files  

    char filein[flimit]; //I created this variable here to avoid issues of array resizing.
    //fgets attempt
    fgets(filein, flimit, data); //scans the whole datafile and stores it in the char array.

    printf("\n%s\n", filein);
    fprintf(output, filein);

    memset(&filein[0], 0, sizeof(filein)); //clears the filein array

    fseek(data, 0, SEEK_SET); // seek back to beginning of file 
    //fscanf attempt
    while(fscanf(data, "%s", &filein)!=EOF)
    {
        printf("\n%s\n", filein);
        fprintf(output, filein);
    }

//Closes the files and ends the program
    printf("\nDONE!!!\n");
    fclose(data);
    fclose(output);
}

这是我在数据文件中使用的文本:

Things/Words and punctuation:  The Test

This is a test (mostly to see if this program is working).

这是我从输出文件中得到的输出:

Things/Words and punctuation:  The Test
Things/Wordsandpunctuation:TheTestThisisatest(mostlytoseeifthisprogramisworking).

为什么 fgets() 会挂起?它得到第一行就好了,然后就卡住了。

提前感谢您抽出宝贵时间查看此内容。如果您对我的代码有任何其他建议,请随时告诉我。

【问题讨论】:

  • 我总是想知道将!!!放在某个地方的原因是什么......
  • 不清楚您为什么认为它“卡住”了。该程序太混乱了,无法推理。编写一个非常短的程序,逐行读取带有fgets 的文件并将其打印回来,然后什么也不做。这是可以分析的。
  • fscanf 可以是安全的——您只需要在解析字符串时指定最大宽度(例如,“%10s”格式说明符)。见stackoverflow.com/questions/1621394/…
  • 也许你想的是 fread,而不是 fgets,因为 fgets 在第一个换行符处停止。使用 fread OTOH,只要您分配了空间,您就可以读取整个文件。您在 fgets 之后的评论表明您想阅读整个文件,所以 fread 会更好,只需用 \0 终止字符串
  • 我发现你的问题有点难以理解,但现在在我看来,你认为fgets 会以一大块读取文件的全部内容?这是不正确的,因为它只读取一行。

标签: c c99 fgets scanf carriage-return


【解决方案1】:

"fgets 函数将在读取 flimit 个字符时停止读取,在 filein 中遇到第一个换行符,或者在文件末尾,以先到者为准。"

您的 fgets() 遇到换行符并停止。这就是为什么您需要使用 while 循环来保持代码运行,直到到达文件末尾。成功完成后, fgets() 返回一个流。如果此流位于文件末尾,则 fgets() 返回一个空指针。

下面的代码块解决了你的问题,

...

    while(fgets(filein,flimit,data) != NULL)
    {
        printf("%s\n",filein);
        fprintf(output,filein);
    }

...

以下链接通过示例解释了 fgets 函数的正确用法。

参考:http://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html

希望对你有帮助,

【讨论】:

  • 使用feof 检测文件结尾几乎总是在C 中读取文件的错误方法。在这种情况下,您可以简单地摆脱您的if 语句,只需使用while 循环。
  • 您的引文来源是什么?您还应该解释此代码块解决问题的原因和方式。
  • 感谢 Berk Soysal。我尝试了while循环,它起作用了。想一想,它有一定的意义,因为 fscanf 也有一个 while 循环。我没有注意到这一点。再次感谢!
猜你喜欢
  • 2016-10-18
  • 2020-08-19
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
相关资源
最近更新 更多