【问题标题】:Using fgets to read strings from file in C使用 fgets 从 C 中的文件中读取字符串
【发布时间】:2010-03-28 01:56:04
【问题描述】:

我正在尝试从一个文件中读取字符串,该文件的每个字符串都在一个新行上,但我认为它读取一个换行符而不是一个字符串,我不知道为什么。如果我要以错误的方式读取字符串,请纠正我。

    i=0;
F1 = fopen("alg.txt", "r"); 
F2 = fopen("tul.txt", "w"); 
     if(!feof(F1)) {
     do{ //start scanning file
     fgets(inimene[i].Enimi, 20, F1);
     fgets(inimene[i].Pnimi, 20, F1);
     fgets(inimene[i].Kood, 12, F1);
     printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s",i,inimene[i].Enimi,inimene[i].Pnimi,inimene[i].Kood);
     i++;}
     while(!feof(F1));};
/*finish getting structs*/

printf 可以让我看到读入了什么,这是结果

i=0
Enimi=peter

Pnimi=pupkin

Kood=223456iatb i=1
Enimi=

Pnimi=masha

Kaad=gubkina
i=2
Enimi=234567iasb

Pnimi=sasha

Kood=dudkina

正如您在读取第一个结构后看到的那样,有一个空白(换行符?)onct,然后一切都被转移了。我想我可以读取一个虚拟字符串来吸收多余的空白,然后什么都不会改变,但这无助于我理解问题并在将来避免。

编辑 1:我知道它在换行符处停止,但仍会读取它。我想知道为什么它在第三个字符串期间不读取它并转移到第四个字符串而不是给第四个字符串提供源的第四行但它只发生一次。 顺便说一下文件格式是这样的

peter 
pupkin 
223456iatb 
masha 
gubkina 
234567iasb 
sasha 
dudkina 
123456iasb 

【问题讨论】:

    标签: c string file-io


    【解决方案1】:

    fgets 在读取换行符时停止读取,但换行符被视为有效字符并包含在返回的字符串中。

    如果你想删除它,你需要自己修剪它:

    length = strlen(str);
    if (str[length - 1] == '\n') 
        str[length - 1] = '\0';
    

    其中str 是您从文件中读取数据的字符串,lengthsize_t 类型。

    回答问题的编辑:在第三次读取期间未读取换行符的原因是因为您没有读取足够的字符。你给 fgets 一个 12 个字符的限制,这意味着它实际上最多可以读取 11 个字符,因为它必须在末尾添加空终止符。

    您阅读的行在换行符之前有 11 个字符。请注意,输出时该行的末尾有一个空格:

    Kood=223456iatb i=1
                   ^
    

    【讨论】:

      【解决方案2】:

      如前所述,如果缓冲区中有足够的空间,则fgets() 将包括换行符在内的数据读取到缓冲区中,并且 null 终止该行。如果在遇到换行符之前缓冲区中没有足够的空间,fgets() 会复制它可以复制的内容(缓冲区的长度减去一个字节)并且 null 终止字符串。库在下一次迭代中从 fgets() 停止的位置继续读取。

      不要弄乱长度小于 2 字节的缓冲区。

      请注意,gets() 删除了换行符(但不能保护您免受缓冲区溢出,所以不要使用它)。如果事情按目前的计划进行,gets() 将从 C 标准的下一个版本中删除;从 C 库中删除它还需要很长时间(它只会成为一个非标准或非标准的附加功能,可被滥用)。

      您的代码应该检查每个fgets() 函数调用:

      while (fgets(inimene[i].Enimi, 20, F1) != 0 &&
             fgets(inimene[i].Pnimi, 20, F1) != 0 &&
             fgets(inimene[i].Kood,  12, F1) != 0)
      {
          printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi, inimene[i].Kood);
          i++;
      }
      

      do/while 循环有一些地方;不过,它们并不经常使用。

      【讨论】:

      • 哇,感谢第二部分,它解决了我的第二个问题:一个空的额外结构。很难找到一个从文件中获取字符串的循环示例(或者我可能看起来不正确,尽管我一直在尝试很长时间)。
      【解决方案3】:

      fgets 函数读取换行符作为读取字符串的一部分。

      来自description of fgets

      fgets() 函数应从流中读取字节到 s 指向的数组中,直到读取 n-1 个字节,或读取换行符并传输到 s,或结束-遇到文件外条件。然后字符串以空字节终止。

      【讨论】:

        【解决方案4】:

        如果 Enimi/Pnimi/Kood 是数组而不是指针:

        while( fgets(inimene[i].Enimi,sizeof inimene[i].Enimi,F1) &&
               fgets(inimene[i].Pnimi,sizeof inimene[i].Pnimi,F1) &&
               fgets(inimene[i].Kood,sizeof inimene[i].Kood,F1) )
        {
        if( strchr(inimene[i].Enimi,'\n') ) *strchr(inimene[i].Enimi,'\n')=0;
        if( strchr(inimene[i].Pnimi,'\n') ) *strchr(inimene[i].Pnimi,'\n')=0;
        if( strchr(inimene[i].Kood,'\n') ) *strchr(inimene[i].Kood,'\n')=0;
        printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi,inimene[i].Kood);
            i++;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-17
          • 2015-09-06
          • 1970-01-01
          • 2019-05-15
          • 2015-06-23
          • 2021-11-09
          • 2019-05-29
          相关资源
          最近更新 更多