Всегда ли fgets() завершает буфер char с помощью ?


Всегда ли fgets() завершает буфер char с , даже если EOF уже достигнут? Похоже, что это так (это, безусловно, так в реализации, представленной в книге ANSI K&R), но я подумал, что хотел бы спросить, чтобы быть уверенным.

Я думаю, что этот вопрос относится и к другим подобным функциям, таким как Get().

EDIT: я знаю, что добавляется во время "нормальных" обстоятельств, мой вопрос нацелен на EOF или условия ошибки. Например:

FILE *fp;
char b[128];
/* ... */
if (feof(fp)) {
    /* is  appended after EACH of these calls? */
    fgets(b, 128, fp);
    fgets(b, 128, fp);
    fgets(b, 128, fp);
}
5 13

5 ответов:

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


Edit пример добавлен

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

Видите? no NUL in buf:)

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

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

Man fgets:

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

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

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

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

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

Если вы открыли файл в двоичном режиме "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';
    }
}