Fgets () всегда завершает буфер символов с \ 0? - PullRequest
17 голосов
/ 02 ноября 2009

Всегда ли fgets () завершает буфер символов с \ 0, даже если EOF уже достигнут? Похоже, что так оно и есть (это, безусловно, так в реализации, представленной в книге 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);
}

Ответы [ 5 ]

11 голосов
/ 02 ноября 2009

fgets всегда добавляет '\ 0' в буфер чтения, из-за этого он читает не более size - 1 символов из потока (size - второй параметр).

Никогда не используйте gets, поскольку вы никогда не сможете гарантировать, что он не переполнит буфер, который вы ему предоставили, поэтому, хотя он технически всегда завершает строку чтения, это на самом деле не помогает.

8 голосов
/ 02 ноября 2009

Никогда не используйте, получает !!

    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, целевой массив может быть изменен и может не иметь нулевого символа. Никогда не полагайтесь на массив после получения NULL от fgets().


Редактировать пример добавления

$ 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:)

4 голосов
/ 02 ноября 2009

человек fgets:

fgets () считывает из потока самое большее на один символ меньше размера и сохраняет их в буфере, указанном s. Чтение останавливается после EOF или новой строки. Если читается новая строка, она сохраняется в буфере. '\ 0' сохраняется после последнего символа в буфере.

2 голосов
/ 15 августа 2015

Если вы открыли файл в двоичном режиме «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';
    }
}
0 голосов
/ 02 ноября 2009

Да, это так. От CPlusPlus.com

Считывает символы из потока и сохраняет их в виде строки C в str до тех пор, пока не будет прочитано (num-1) символов или не будет достигнута новая строка или конец файла, в зависимости от того, что произойдет раньше.

Символ новой строки заставляет fgets перестать читать, но он считается допустимым символом и поэтому включен в строку, скопированную в str.

Нулевой символ автоматически добавляется в строку после прочитанных символов, чтобы обозначить конец строки C.

...