Почему несколько операторов fgets перезаписывают массивы символов? - PullRequest
0 голосов
/ 18 июня 2019

Следующий код работает, но если я ввожу более 10 символов (скажем, 10 a), результат будет выглядеть примерно так:

"Имя собаки? Порода aaaaaaaaaDog? Имя собаки: порода aaaaaaaaaDog:"

Почему это?И как я могу это исправить?

#include <stdio.h>
#include <stdlib.h>

typedef struct Dog {
    char name[10];
    char breed[10];
} Dog;

Dog makeDog() {
    Dog dog;

    printf("Dog's name? ");
    fgets(dog.name, 10, stdin);

    printf("Dog's breed? ");
    fgets(dog.breed, 10, stdin);

    return dog;
}

int main() {
    printf("\n");

    Dog dog = makeDog();

    printf("\n");

    printf("Dog's name: %s", dog.name);
    printf("Dog's breed: %s \n", dog.breed);
}

Ответы [ 2 ]

0 голосов
/ 18 июня 2019

Массив символов name объявляется с 10 элементами

char name[10];

Если вы используете следующий вызов fgets

fgets(dog.name, 10, stdin);

после ввода 10символов 'a', тогда вызов fgets читает только 9 символов из входного буфера и добавляет массив с завершающим нулевым символом '\0'.

Таким образом, массив будет содержать строку "aaaaaaaaa".Это то же самое, что инициализировать массив следующим образом

char name[10[ = { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0' };

После этого входной буфер будет содержать один символ 'a' и символ новой строки '\n'.Эти символы будут прочитаны при следующем вызове

fgets(dog.breed, 10, stdin);

В результате массив bread будет содержать строку "a\n".

Это то же самое, что инициализировать массив следующимway

char bread[10[ = { 'a', '\n', '\0' };

Если вы хотите хранить в массивах строки с большим количеством символов, вы должны увеличить массивы.

Например, если вы хотите ввести для имени массива строку 10 символы 'a' у вас есть tfo, чтобы объявить массив с 12 элементами.Почему 12?Поскольку кроме 10 символов 'a' и завершающего нулевого символа, функция fgets также попытается прочитать символ новой строки '\n' из входного буфера.В противном случае этот символ будет прочитан вторым вызовом fgets.

Чтобы удалить символ новой строки из массива, вы можете использовать следующий подход

#include <string.h>

//...

fgets( dog.name, 12, stdin );
dog.name[strcspn( dog.name, "\n" )] = '\0';
0 голосов
/ 18 июня 2019

следующий предложенный код:

  1. безупречная компиляция
  2. выполняет желаемую функциональность
  3. завершается, если имя собаки слишком длинное
  4. удаляет символ новой строки вконец имени собаки
  5. удаляет перевод строки в конце породы собаки
  6. не проверяет правильность длины породы собаки
  7. правильно очищается после использования динамической памяти
  8. избегает использования «магических» чисел
  9. , правильно распределяет динамическую память и проверяет / обрабатывает любые ошибки
  10. использует: «максимум 8 символов», чтобы освободить место для завершающего символа новой строки и завершающего символа NUL

и теперь предложенный код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NAME_LEN  10
#define MAX_BREED_LEN 10

typedef struct Dog 
{
    char name[ MAX_NAME_LEN ];
    char breed[ MAX_BREED_LEN ];
} Dog;

Dog * makeDog() 
{
    Dog *dog = malloc( sizeof( Dog ) );
    if( !dog )
    {
        perror( "malloc for struct Dog failed" );
        exit( EXIT_FAILURE );
    }

    printf("Dog's name? max 8 characters ");
    if( !fgets(dog->name, MAX_NAME_LEN, stdin) )
    {
        perror( "fgets for dog name failed" );
        exit( EXIT_FAILURE );
    }

    if( dog->name[ strlen( dog->name ) -1 ] != '\n' )
    {
        puts( "dog name too long, aborting" );
        exit( EXIT_FAILURE );
    }

    // remove trailing newline
    dog->name[ strcspn( dog->name, "\n" ) ] = '\0';

    printf("Dog's breed? max 8 characters");
    if( !fgets(dog->breed, MAX_BREED_LEN, stdin) )
    {
        perror( "fgets for dog breed failed" );
        exit( EXIT_FAILURE );
    }

    // remove trailing newline
    dog->breed[ strcspn( dog->name, "\n" ) ] = '\0';

    return dog;
}

int main() {
    printf("\n");

    Dog *dog = makeDog();

    printf("\n");

    printf("Dog's name: %s\n", dog->name);
    printf("Dog's breed: %s\n", dog->breed);

    free( dog );
}
...