fgets естественно ставит завершающий ноль в C? - PullRequest
5 голосов
/ 13 октября 2010
struct DVDInfo  *ReadStruct( void ) {
    struct DVDInfo  *infoPtr;
    int             num;
    char            line[ kMaxLineLength ];
    char            *result;

    infoPtr = malloc( sizeof( struct DVDInfo ) );

    if ( NULL == infoPtr ) {
        printf( "Out of memory!!!  Goodbye!\n" );
        exit( 0 );
    }

    printf( "Enter DVD Title:  " );
    result = fgets( line, kMaxLineLength, stdin );
    line[ strlen( line ) - 1 ] = '\0';
    infoPtr->title = MallocAndCopy( line );

    printf( "Enter DVD comment:  " );
    result = fgets( line, kMaxLineLength, stdin );
    line[ strlen( line ) - 1 ] = '\0';
    infoPtr->comment = MallocAndCopy( line );

    do {
        printf( "Enter DVD Rating (1-10):  " );
        scanf( "%d", &num );
        Flush();
    }
    while ( ( num < 1 ) || ( num > 10 ) );

    infoPtr->rating = num;

    printf( "\n----------\n" );

    return( infoPtr );
}

Я задал другой вопрос об этом коде в другом потоке в stackoverflow, но не хотел удваивать этот - почему конечный ноль добавляется в конец этих файлов, считываемых fgets? В любом случае, fgets добавляет завершающий ноль, разве это не перебор?

Ответы [ 5 ]

3 голосов
/ 13 октября 2010

Обычно вы заменяете символ новой строки, который fgets добавляет в строку, символом NUL.Во всех случаях fgets завершается NUL.

См .: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html

2 голосов
/ 13 октября 2010

fgets записывает нулевой терминатор в предоставленный вами буфер (если вы указали размер буфера больше 0). В противном случае вы не могли бы вызвать strlen () для него, strlen () ожидает строку, и если она не завершена как nul, это не строка.

Вы спрашиваете о

line[ strlen( line ) - 1 ] = '\0';

Это удаляет последний символ в line. Если вы прочитали строку, он заменяет последний символ, предположительно \ n, на нулевой терминатор.

Учтите, что fgets просто читает строку, например, Ваш line буфер теперь содержит строку «Hello \ n» (здесь \ n это просто escape-последовательность, на самом деле это всего 1 символ, а не 2)

strlen ("Hello \ n") - 6, а 6-1 - 5, поэтому индекс 5. заменяется на 0

"Hello\n"
      ^
      |
      Add 0 terminator

Результат: "Привет"

Только будьте осторожны:

  • вы не хотите делать строку [strlen (line) - 1] = '\ 0'; в пустой строке, в этом случае вы закончите делать строку [-1].
  • Вы должны проверить, удалось ли fgets. Вы не хотите копаться в line, если fgets потерпела неудачу и ничего не записала в ваш буфер.
  • Возможно, вы захотите проверить, действительно ли прочитана вся строка. Если строка, которую вы читаете, больше, чем kMaxLineLength или, например, если последняя "строка" в файле не имеет завершающего \ n, strlen (строка) -1 не будет \ n (новая строка).
1 голос
/ 13 октября 2010

Да, это излишне.

Одно предложение сделать его более устойчивым к гниению кода ... изменить

result = fgets( line, kMaxLineLength, stdin );

на

result = fgets( line, sizeof(line), stdin );
1 голос
/ 13 октября 2010

line[ strlen( line ) - 1 ] = '\0'; не нужны (и небезопасны - strlen() не будет работать должным образом, если строка еще не завершена нулем).fgets() обнулит буфер.Кроме того, вы должны проверить это result != NULL, прежде чем пытаться скопировать line.fgets() возвращает NULL в конце файла или в случае ошибки.

1 голос
/ 13 октября 2010

Ваш

result = fgets( line, kMaxLineLength, stdin );

в порядке, так как размер строки kMaxLineLength.

fgets считывает не более одного * менее 1008 * символов из stream и сохраняет их в буфере ...

...