代码之家  ›  专栏  ›  技术社区  ›  Ree

fgets()是否总是用\0终止字符缓冲区?

  •  15
  • Ree  · 技术社区  · 15 年前

    fgets()是否总是用\0终止char缓冲区,即使已经达到eof?它看起来是这样的(在ANSIK&R书中介绍的实现中当然是这样),但我想我会要求确定。

    我想这个问题也适用于其他类似的函数,比如gets()。

    编辑:我知道在“正常”情况下附加了\0,我的问题针对的是EOF或错误情况。例如:

    FILE *fp;
    char b[128];
    /* ... */
    if (feof(fp)) {
        /* is \0 appended after EACH of these calls? */
        fgets(b, 128, fp);
        fgets(b, 128, fp);
        fgets(b, 128, fp);
    }
    
    5 回复  |  直到 9 年前
        1
  •  8
  •   pmg    15 年前

    永远不要使用GET!!

        7.19.7.2 The fgets function
        Synopsis
    1           #include <stdio.h>
                char *fgets(char * restrict s, int n,
                     FILE * restrict stream);
        Description
    2   The fgets function reads at most one less than the number of characters
        specified by n from the stream pointed to by stream into the array pointed
        to by s. No additional characters are read after a new-line character
        (which is retained) or after end-of-file. A null character is written
        immediately after the last character read into the array.
        Returns
    3   The fgets function returns s if successful. If end-of-file is encountered
        and no characters have been read into the array, the contents of the array
        remain unchanged and a null pointer is returned. If a read error occurs
        during the operation, the array contents are indeterminate and a null
        pointer is returned.
    

    所以, fgets() 不返回空。目标数组始终具有空字符。

    如果 FGSE() 返回空值,目标数组可能已更改,并且可能没有空字符。从中获取空值后决不依赖数组 FGSE() .


    编辑 示例添加

    $ cat fgets_error.c
    #include <stdio.h>
    
    void print_buf(char *buf, size_t len) {
      int k;
      printf("%02X", buf[0]);
      for (k=1; k<len; k++) printf(" %02X", buf[k]);
    }
    
    int main(void) {
      char buf[3] = {1, 1, 1};
      char *r;
    
      printf("Enter CTRL+D: ");
      fflush(stdout);
      r = fgets(buf, sizeof buf, stdin);
      printf("\nfgets returned %p, buf has [", (void*)r);
      print_buf(buf, sizeof buf);
      printf("]\n");
    
      return 0;
    }
    $ ./a.out
    Enter CTRL+D:
    fgets returned (nil), buf has [01 01 01]
    $
    

    看到了吗?buf中没有nul:)

        2
  •  9
  •   CB Bailey    15 年前

    fgets 总是向读取缓冲区添加'\0',它最多读取 size - 1 流中的字符( size 因为这是第二个参数)。

    从不使用 gets 因为你永远不能保证它不会溢出你给它的任何缓冲区,所以尽管它在技术上总是终止读取字符串,但实际上并没有帮助。

        3
  •  4
  •   eyalm    15 年前

    曼菲斯:

    fgets()从流中最多读取一个小于大小的字符,并将它们存储到s指向的缓冲区中。在eof或换行符之后,读取将停止。如果读取新的_行,则将其存储到缓冲区中。 在缓冲区中的最后一个字符之后存储了一个'\0'。

        4
  •  0
  •   Ólafur Waage    15 年前

    是的。从 CPlusPlus.com

    从流中读取字符并将其作为C字符串存储到str中,直到(num-1)个字符被读取,或者到达新行或文件结尾,以先到者为准。

    换行符使fgets停止读取,但它被视为有效字符,因此它包含在复制到str的字符串中。

    在读取字符后,一个空字符会自动附加到str中,以表示C字符串的结尾。

        5
  •  0
  •   user4907386    9 年前

    如果您确实以二进制模式“rb”打开了文件,并且如果您希望使用fgets逐行读取文本,则可以使用以下代码来保护您的软件不丢失文本,如果错误地文本包含一个\0'字节。 但最后就像其他人提到的,通常你不应该使用 fgets 如果流包含'\0'。


    size_t filepos=ftell(stream);
    fgets(buffer, buffersize, stream);
    len=strlen(buffer);
    /* now check for > len+1 since no problem if the 
       last byte is 0 */
    if(ftell(stream)-filepos > len+1) 
    {
        if(!len) filepos++;
        if(!fseek(stream, filepos, SEEK_SET) && len)
        {
            fread(buffer, 1, len, stream);
            buffer[len]='\0';
        }
    }