fgetc пропускает первый символ в файле

В цикле while команда fgetc пропускает первый символ, и я не могу понять, почему.

void generate_people(FILE *p, struct person *a){
    int c;

    while((c = getc(p)) != EOF){
        fscanf(p, "%s %[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ], 
          %[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ] %d, %d %s.", 
            a->fornavn, a->efternavn, a->vejnavn, 
            &a->vejnummer, &a->postnummer, a->bynavn);
        a++; 
    }    
}

person Lasse Harde    schedule 24.11.2018    source источник
comment
Добро пожаловать в Stack Overflow. Пожалуйста, прочитайте О и Как спросить страниц в ближайшее время. Срочно прочтите о том, как создать MCVE (минимально воспроизводимый пример). Вы не показали свои входные данные или фактический или ожидаемый результат. Однако вы вызываете fgetc() в цикле, который считывает первый символ в c, а затем вы используете fscanf(). Теперь fscanf() никогда не увидит символ, прочитанный в c. Также обратите внимание, что наборы сканирования поддерживают обозначение диапазона, такое как %[a-zA-Z ], что делает вашу строку формата более понятной. Скорее всего, вам следует использовать while (fscanf(p, "…", …) == 6) и игнорировать fgetc().   -  person Jonathan Leffler    schedule 24.11.2018


Ответы (1)


Первый символ находится в c. Используйте результат fscanf() вместо (c = getc(p)) != EOF для обнаружения ошибки или EOF:

void generate_people(FILE *p, struct person *a)
{
    while (fscanf(p, "%s %[a-zA-Z], %[a-zA-Z] %d, %d %s.",
                     a->fornavn, a->efternavn, a->vejnavn, 
                     &a->vejnummer, &a->postnummer, a->bynavn) == 6)
    {
        ++a; 
    }    
}

Полный пример:

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

struct person {
    char fornavn[30];
    char efternavn[30];
    char vejnavn[30];
    int  vejnummer;
    int  postnummer;
    char bynavn[30];
};

struct person* generate_people(FILE *p, struct person *a)
{
    while (fscanf(p, "%29s %29[a-zA-Z], %29[a-zA-Z] %d, %d %29s",  // ****)
           a->fornavn, a->efternavn, a->vejnavn,
           &a->vejnummer, &a->postnummer, a->bynavn) == 6)
    {
        ++a;
    }
    return a;
}

void person_print(struct person *a)
{
    printf("\"%s\" \"%s\", \"%s\" %d, %d \"%s\"\n",
           a->fornavn, a->efternavn, a->vejnavn,
           a->vejnummer, a->postnummer, a->bynavn);
}

int main(void)
{
    char const *filename = "test.txt";
    FILE *input = fopen(filename, "r");

    if (!input) {
        fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
        return EXIT_FAILURE;
    }

    struct person people[10];
    struct person *end = generate_people(input, people);

    for (struct person *i = people; i != end; ++i)
        person_print(i);

    fclose(input);
}

Входной файл:

Lars Jensen, Engtoften 23, 7182 Bredsten
Bo Olsen, Vestergade 56, 4261 Dalmose
Kurt Jensen, Haderslevvej 15, 8370 Hadsten
Birte Madsen, Universitetsvej 899, 9000 Aalborg
Kaj Moberg, Halevindingevej 2, 2670 Greve
Bo Rise, Hadsund Landvej 56, 8900 Randers

Выход:

"Lars" "Jensen", "Engtoften" 23, 7182 "Bredsten"
"Lars" "Jensen", "Engtoften" 23, 7182 "Bredsten"
"Bo" "Olsen", "Vestergade" 56, 4261 "Dalmose"
"Kurt" "Jensen", "Haderslevvej" 15, 8370 "Hadsten"
"Birte" "Madsen", "Universitetsvej" 899, 9000 "Aalborg"
"Kaj" "Moberg", "Halevindingevej" 2, 2670 "Greve"

****) Обратите внимание, что вы НИКОГДА не должны использовать "%s" с *scanf() без указания ширины поля для чтения: "%NNNs", где NNN — количество символов. Для массива размером 30: "%29" ... 29 + 1 для завершающего 0.

person Swordfish    schedule 24.11.2018
comment
@LasseHarde Вы проходите этот курс: people.cs.aau.dk/~normark /импр-с ? - person Swordfish; 24.11.2018