2009-11-02 21 views
11

即使EOF已经达到,fgets()是否总是用\ 0终止char缓冲区?它看起来像它(它确实在ANSI K & R书中提供的实现中),但我想我会要求确定。fgets()总是以 0结束char缓冲区吗?

我想这个问题适用于其他类似的函数,如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); 
} 
+1

经常检查'与fgets的返回值()':'如果(与fgets(...)== NULL)/ *不确定的数组* /;' – pmg 2009-11-02 10:15:43

+0

你可能是正确的,但是,我发现还有其他答案指出总是附加'\ 0',即使'fgets()'返回NULL。 – Ree 2009-11-02 10:26:06

回答

6

永远不要使用获取!

 
    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()不返回NULL目标数组总是有一个空字符。

如果fgets()返回NULL,则目标数组可能已被更改并且可能没有空字符。在从fgets()获得NULL之后,千万不要依赖数组。


编辑例如添加

 
$ 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] 
$ 

看到了吗?没有NUL buf :)

+0

You win:D .... – Ree 2009-11-02 11:13:58

+0

@pmg re“永远不要使用gets !!”,你有替代文件阅读吗? – atlex2 2015-10-19 17:07:11

+1

@ atlex2:是的,替代方法是'fgets()'。 – pmg 2015-10-19 17:42:51

0

是的。从CPlusPlus.com

从流中读取字符和将它们存储为C字符串到STR直到已经读取或达到任一换行或所述档案结尾(NUM-1)的字符,以先到者为准。

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

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

7

fgets并不总是一个“\ 0”添加到读缓冲器,它从流读取最多size - 1字符(size是第二参数)因为这个原因。

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

2

人与fgets:

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

0

如果你打开了二进制模式“rb”的文件,并且如果你想通过使用fgets逐行读取文本,你可以使用下面的代码来保护你的软件丢失文本,如果错误,文本包含'\ 0'字节。 但终于像其他人提到的那样,如果流包含'\ 0',通常不应该使用fgets


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'; 
    } 
}