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

发布于 2024-08-09 20:54:48 字数 380 浏览 1 评论 0原文

即使已经达到 EOF,fgets() 是否总是以 \0 终止字符缓冲区?看起来确实如此(在 ANSI K&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);
}

Does fgets() always terminate the char buffer with \0 even if EOF is already reached? It looks like it does (it certainly does in the implementation presented in the ANSI K&R book), but I thought I would ask to be sure.

I guess this question applies to other similar functions such as gets().

EDIT: I know that \0 is appended during "normal" circumstances, my question is targeted at EOF or error conditions. For example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

も星光 2024-08-16 20:54:48

fgets 总是向读取缓冲区添加一个“\0”,它最多从流中读取 size - 1 个字符(size 是第二个参数)因此。

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

fgets does always add a '\0' to the read buffer, it reads at most size - 1 characters from the stream (size being the second parameter) because of this.

Never use gets as you can never guarantee that it won't overflow any buffer that you give it, so while it technically does always terminate the read string this doesn't actually help.

不再让梦枯萎 2024-08-16 20:54:48

永远不要使用 gets!!

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

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

Never use gets!!

    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.

So, yes, when fgets() does not return NULL the destination array always has a null character.

If fgets() returns NULL, the destination array may have been changed and may not have a null character. Never rely on the array after getting NULL from fgets().


Edit example added

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

See? no NUL in buf :)

迷途知返 2024-08-16 20:54:48

man fgets:

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

man fgets:

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a new‐line is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer.

偏爱自由 2024-08-16 20:54:48

如果您确实以二进制模式“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';
    }
}

If you did open the file in binary mode "rb", and if you want to read Text line by line by using fgets you can use the following code to protect your software of loosing text, if by a mistake the text contained a '\0' byte.
But finally like the others mentioned, normally you should not use fgets if the stream contains '\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';
    }
}
苍白女子 2024-08-16 20:54:48

是的,确实如此。来自 CPlusPlus.com

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

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

复制到 str 的字符后会自动附加终止空字符。

Yes it does. From CPlusPlus.com

Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the End-of-File is reached, whichever comes first.

A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str.

A terminating null character is automatically appended after the characters copied to str.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文