Search code examples
cfgetc

fgetc skips first character in file


In the while loop, the fgetc command is skipping the first character, and I can't seem to figure out why.

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++; 
    }    
}

Solution

  • The first character is in c. Use the result of fscanf() instead of (c = getc(p)) != EOF to detect error or 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; 
        }    
    }
    

    Full example:

    #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);
    }
    

    Input file:

    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
    

    Output:

    "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"
    

    ****) Please not that you should NEVER use "%s" with *scanf() without specifying a width for the field to read: "%NNNs" where NNN is the number of characters. For an array of size 30: "%29" ... 29 + 1 for the terminating 0.