Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Problème de fscanf en C


Sujet :

C

  1. #1
    Futur Membre du Club
    Problème de fscanf en C
    Bonjour, en ce moment je dois faire un projet en C où je dois créer un programme qui gère les différents logements d'un Crous.

    J'ai un fichier Etudiant qui contient certaines caractéristiques à leur propos.

    Pour les manipuler, j'ai choisi de créer un tableau de structure avec une allocation dynamique.

    Mon problème est que j'utilise mal le flot de la fonction de lecture du fichier (Enfin je pense).

    : Voilà à quoi ressemble le fichier texte.

    : Voilà ce qu'affiche la console lorsque je mets un printf("%s", a.prenom); Dans la fonction LireEtudiant.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
     
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    typedef enum{Non, Oui} Booleen;
     
    typedef struct{
        int idEtudiant;
        char Civilite;
        char prenom[16];
        char nom[16];
        Booleen Boursier;
        int Echelon;
        Booleen Handicape;
    }Etudiant;
     
    Etudiant LireEtudiant(FILE *flot){
     
        Etudiant a;
     
        fscanf(flot, "%d%c%*c", &a.idEtudiant, &a.Civilite);
        fscanf(flot, "%s %s", a.prenom, a.nom);
        fscanf(flot, "%d\t%d\t%d", &a.Boursier, &a.Echelon, &a.Handicape);
        printf("%s\n", a.prenom);
        return a;
     
    }
     
     
    Etudiant * ChargeEtudiant(int *nb, int *max){
     
        Etudiant *tab, *aux, a;
        FILE *flot;
        flot= fopen("Etudiants.txt", "r");
        if(flot==NULL){
            printf("Erreur d'ouverture du fichier.\n");
            exit(1);
        }
     
        *nb=0;
        *max=100;
     
        tab=(Etudiant*) malloc((*max)*sizeof(Etudiant));
        if(tab==NULL){
            printf("Erreur malloc.\n");
            exit(1);
        }
     
        a= LireEtudiant(flot);
     
        while(!feof(flot)){
     
            if(*nb==*max){
     
                aux=(Etudiant*) realloc(tab, (*max+100)*sizeof(Etudiant));
                if(aux==NULL){
                    printf("Erreur Realloc.\n");
                    exit(1);
                }
     
                tab=aux;
                *max+=100;
     
            }
     
            tab[*nb]= a;
            *nb+=1;
            a= LireEtudiant(flot);
     
        }
     
        fclose(flot);
        free(aux);
        return tab;
     
    }
     
    void AfficherEtudiants(Etudiant *tab, int nb){
     
        int i=0;
     
        while(i<nb){
     
            printf("%d\t%c\t%s\t%s", tab[i].idEtudiant, tab[i].Civilite, tab[i].prenom, tab[i].nom);
            switch(tab[i].Boursier){
                case 1:
                    printf("\tNon");
                    break;
                case 0:
                    printf("\tOui");
                    break;
            }
     
            printf("\t%d", tab[i].Echelon);
     
            switch(tab[i].Handicape){
                case 1:
                    printf("\tNon\n");
                    break;
                case 0:
                    printf("\tOui\n");
                    break;
            }
     
            i+=1;
     
        }
     
    }


    Voilà le code. Désolé pour les éventuelles erreurs bêtes.

    Merci d'avance.

  2. #2
    Membre confirmé
    Bonsoir,

    Je vois des warnings:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    test.c: In function ‘LireEtudiant’:
    test.c:23:20: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘Booleen *’ {aka ‘enum <anonymous> *’} [-Wformat=]
       23 |     fscanf(flot, "%d\t%d\t%d", &a.Boursier, &a.Echelon, &a.Handicape);
          |                   ~^           ~~~~~~~~~~~
          |                    |           |
          |                    int *       Booleen * {aka enum <anonymous> *}
    test.c:23:28: warning: format ‘%d’ expects argument of type ‘int *’, but argument 5 has type ‘Booleen *’ {aka ‘enum <anonymous> *’} [-Wformat=]
       23 |     fscanf(flot, "%d\t%d\t%d", &a.Boursier, &a.Echelon, &a.Handicape);
          |                           ~^                            ~~~~~~~~~~~~
          |                            |                            |
          |                            int *                        Booleen * {aka enum <anonymous> *}


    Pourriez-vous les corriger s'il vous plait ?
    Si tu ne vis pas ce que tu penses alors tu penses ce que tu vis.

  3. #3
    Futur Membre du Club
    J'aimerais bien mais comment représenter une structure ou dans ce cas ci, une énumération dans scanf ?

    J'ai vu quelque part qu'il fallait utiliser un "cast" mais je n'en suis pas sûr.

  4. #4
    Membre du Club
    Je propose:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    char f_next_char(FILE* f) {
        int c;
     
        do
            c = fgetc(f);
        while (isspace(c));
     
        return ((char)c);
    }
     
    char* f_next_string(FILE* f, char* s) {
        int c;
        char* p = s;
     
        do
            c = fgetc(f);
        while (isspace(c));
     
        while (!isspace(c) && !feof(f) && !ferror(f)) {
            *p = (char)c;
            c = fgetc(f);
            ++p;
        }
     
        *p = '\0';
        return (s);
    }
     
    int f_next_int(FILE* f) {
        char s[16];
     
        f_next_string(f, s);
        for (char* p = s; *p; ++p)
            if (!isdigit(*p)) {
                fprintf(stderr, "Erreur E/S : N'est pas un nombre.\n");
                exit (1);
            }
        return (atoi(s));
    }
     
    Booleen f_next_bool(FILE* f) {
        char s[4];
     
        f_next_string(f, s);
        return (!strcmp(s, "Oui") ? Oui : Non);
    }
     
    Etudiant LireEtudiant(FILE *flot){
     
        Etudiant a;
     
        a.idEtudiant = f_next_int(flot);
        a.Civilite = f_next_char(flot);
        f_next_string(flot, a.prenom);
        f_next_string(flot, a.nom);
        a.Boursier = f_next_bool(flot);
        a.Echelon = f_next_int(flot);
        a.Handicape = f_next_bool(flot);
     
        printf("%d %c %s %s %s %d %s\n",  a.idEtudiant,
                                            a.Civilite,
                                            a.prenom,
                                            a.nom,
                                            a.Boursier == Oui ? "Oui" : "Non",
                                            a.Echelon,
                                            a.Handicape == Oui ? "Oui" : "Non");
        return a;
     
    }


    En espérant que le fichier contenant les données à lire soit parfait.

  5. #5
    Expert éminent
    Attention : en C, c'est de l'ASCII et donc tu n'as pas les accents ni les caractères spéciaux.
    Pour l'Unicode (UTF-8 ou UTF-16 ou UTF-32) ou du MBCS, c'est une autre histoire



    Voir mon message en dessous, j'ai mis à jour mon code avec des états

  6. #6
    Futur Membre du Club
    Bonsoir, je vous remercie pour vos réponses à mon problème.
    Je suis conscient que vous avez pris de votre temps pour m'aider et j'en suis désolé mais les solutions que vous m'avez proposé me paraissent au dessus du niveau que l'on attends de moi.

    N'y aurait t'il pas un moyen plus "simple" pour parvenir à un résultat convenable même s'il serait nécessaire de modifier le fichier texte.

    Désolé encore et merci d'avance.

  7. #7
    Expert éminent
    Citation Envoyé par jpagnol Voir le message
    J'aimerais bien mais comment représenter une structure ou dans ce cas ci, une énumération dans scanf ?
    Code fait à l'arrache , avec une machine à états à améliorer et du code à factoriser pour la découper en plusieurs morceaux
    Et peut-être utiliser une lecture caractère par caractère, au lieu ligne par ligne.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    /*****************************************************************************/
    /********************************  Constants  ********************************/
    /*****************************************************************************/
     
    // G_ == global
     
    #define G_LAST_NAME_LENGTH  60
    #define G_FIRST_NAME_LENGTH 60
     
    #define G_ONE_LINE_MIN_LENGTH  80
    #define G_ONE_LINE_LENGTH     512 // Fixed value be careful
     
     
    /*****************************************************************************/
    /**********************************  Utils  **********************************/
    /*****************************************************************************/
     
    typedef enum e_gender {
        GENDER_UNDEFINED = 0,
        GENDER_MASCULINE,
        GENDER_FEMININE
    } t_gender;
     
     
    #define G_DISPLAY_GENDER(G)  ((G == GENDER_MASCULINE)? "masculine": ((G == GENDER_FEMININE)? "feminine": "undefined"))
    #define G_DISPLAY_BOOLEAN(B) ((B)? "yes": "no")
     
     
    /*****************************************************************************/
    /*******************************  Parser Error  ******************************/
    /*****************************************************************************/
     
    typedef enum e_error {
        ERROR_NONE = 0,
        ERROR_EXPECTED_EOF,
        ERROR_EXPECTED_GENDER,
        ERROR_EXPECTED_LETTER,
        ERROR_EXPECTED_NUMERAL,
        ERROR_EXPECTED_RANK,
        ERROR_EXPECTED_YES_NO,
        ERROR_UNEXPECTED_EOF
    } t_error;
     
     
    typedef enum e_state {
        STATE_START   = 0,
    //  STATE_FIELDXX should be in ascending order
        STATE_FIELD01 = 1, // Force the value
        STATE_FIELD02,
        STATE_FIELD03,
        STATE_FIELD04,
        STATE_FIELD05,
        STATE_FIELD06,
        STATE_FIELD07,
    //  STATE_SPACEXX should be in ascending order and after all STATE_FIELDXX: see parser_error_to_string
        STATE_SPACE01, // field 1 <-> field 2
        STATE_SPACE02, // field 2 <-> field 3
        STATE_SPACE03, // field 3 <-> field 4
        STATE_SPACE04, // field 4 <-> field 5
        STATE_SPACE05, // field 5 <-> field 6
        STATE_SPACE06, // field 6 <-> field 7
        STATE_EOF
    } t_state;
     
     
    typedef struct s_parser_error {
        t_state state;
        t_error error;
     
        size_t pos;
        size_t col;
        unsigned char c;
     
        char str[100]; // maybe move this string outside, and add a parameter to function state_machine_to_string
    } t_parser_error;
     
     
    // Define func pointer
    typedef char* (*t_func_get_field_name) (size_t);
     
     
    void parser_error_set(t_parser_error* error, t_state state, t_error error_id,
            size_t pos, size_t col, unsigned char c) {
     
        if (error != NULL) {
            error->state = state; error->error = error_id; error->pos = pos; error->col = col; error->c = c;
        }
    }
     
     
    void parser_error_to_string(t_parser_error* error, t_func_get_field_name func_get_field_name) {
        if (error != NULL) {
            size_t limit;
            unsigned add_error;
     
            add_error = 1;
     
            switch(error->state) {
            case STATE_START:
                if (error->error ==  ERROR_UNEXPECTED_EOF) {
                    strcpy(error->str, "empty line");
     
                    add_error = 0;
                } else {
                    strcpy(error->str, "state: start, error: ");
                }
                break;
     
            case STATE_FIELD01: case STATE_FIELD02: case STATE_FIELD03: case STATE_FIELD04:
            case STATE_FIELD05: case STATE_FIELD06: case STATE_FIELD07:
                sprintf(error->str, "field: %s, error: ", func_get_field_name(error->state));
                break;
     
            case STATE_SPACE01: case STATE_SPACE02: case STATE_SPACE03:
            case STATE_SPACE04: case STATE_SPACE05: case STATE_SPACE06:
                limit = (error->state - STATE_SPACE01 + STATE_FIELD01);
     
                sprintf(error->str, "field: space [%s <-> %s], error: ",
                    func_get_field_name(limit), func_get_field_name(limit + 1));
                break;
     
            case STATE_EOF:
                if (error->error ==  ERROR_EXPECTED_EOF) {
                    sprintf(error->str, "expected eof (col %lu)", error->col);
     
                    add_error = 0;
                } else {
                    strcpy(error->str, "field: eof, error: ");
                }
                break;
     
            default:               strcpy(error->str, "field: ???, error: "); break;
            }
     
            if (add_error) {
                limit = strlen(error->str);
     
                switch(error->error) {
                case ERROR_NONE:             strcpy((error->str + limit), "no error"); break;
                case ERROR_EXPECTED_EOF:     sprintf((error->str + limit), "expected eof (col %lu)", error->col); break;
                case ERROR_EXPECTED_GENDER:  sprintf((error->str + limit), "gender is either 'h'/ 'H' or 'f'/ 'F' (col %lu)", error->col); break;
                case ERROR_EXPECTED_LETTER:  sprintf((error->str + limit), "expected letter at %lu (col %lu) [%c]", error->pos, error->col, error->c); break;
                case ERROR_EXPECTED_NUMERAL: sprintf((error->str + limit), "expected literal at %lu (col %lu) [%c]", error->pos, error->col, error->c); break;
                case ERROR_EXPECTED_RANK:    sprintf((error->str + limit), "rank is a literal (0 <= rank <= 9) (col %lu) [%c]", error->col, error->c); break;
                case ERROR_EXPECTED_YES_NO:  sprintf((error->str + limit), "expected \"oui\" or \"non\" - case insensitive (pos %lu, col %lu)", error->pos, error->col); break;
                case ERROR_UNEXPECTED_EOF:   sprintf((error->str + limit), "unexpected eof (col %lu)", error->col); break;
                default:                     strcpy((error->str + limit), "???"); break;
                }
            }
        }
    }
     
     
    /*****************************************************************************/
    /********************************  One Person  *******************************/
    /*****************************************************************************/
     
    typedef struct s_one_person {
        size_t   id;
        t_gender gender;
        char     last_name[G_LAST_NAME_LENGTH];
        char     first_name[G_FIRST_NAME_LENGTH];
        size_t   rank;
        unsigned char is_handicapped;
        unsigned char has_schorlarship;
    } t_one_person;
     
     
    void one_person_display(t_one_person* one_person, char* begin_str) {
        if (one_person != NULL) {
            printf("%s\n" \
                " - id:         %lu\n" \
                " - gender:     %s\n" \
                " - last name:  %s\n" \
                " - first name: %s\n" \
                " - rank:       %lu\n" \
                " - is handicapped:   %s\n" \
                " - has schorlarship: %s\n\n", begin_str, one_person->id,
                    G_DISPLAY_GENDER(one_person->gender), one_person->last_name,
                    one_person->first_name, one_person->rank,
                    G_DISPLAY_BOOLEAN(one_person->is_handicapped),
                    G_DISPLAY_BOOLEAN(one_person->has_schorlarship));
        }
    }
     
     
    // XXX: Ugly - multiple return paths with fixed strings
    char* one_person_get_field_name(size_t field) {
        switch(field) {
        case 1: return "id"; break;
        case 2: return "gender"; break;
        case 3: return "last name"; break;
        case 4: return "first name"; break;
        case 5: return "has schorlarship"; break;
        case 6: return "rank"; break;
        case 7: return "is handicapped"; break;
        default: return "???"; break;
        }
    }
     
     
    #define G_PARSING_GET_NEXT_CHAR(STATE, IS_NOT_EOF) \
        ++count; \
        if (count < length) { \
            c = one_line[count]; \
            if (IS_NOT_EOF && ((c == '\n') || (c == '\r'))) { \
                ret = 0; \
                parser_error_set(error, STATE, ERROR_UNEXPECTED_EOF, 0, (count + 1), c); \
            } \
        } else { \
            ret = 0; \
            parser_error_set(error, STATE, ERROR_UNEXPECTED_EOF, 0, (count + 1), c); \
        }
     
     
    // Here maybe eat spaces
    #define G_PARSING_MANAGE_SPACE(STATE, ERROR, STATE_SPACE) \
        if (ret) { \
            if (c == ' ') { \
                G_PARSING_GET_NEXT_CHAR(STATE_SPACE, 1) \
            } else { \
                ret = 0; \
                if ((c != '\n') && (c != '\r')) { \
                    parser_error_set(error, STATE, ERROR, (str_count + 1), (count + 1), c); \
                } else { \
                    parser_error_set(error, STATE, ERROR_UNEXPECTED_EOF, (str_count + 1), (count + 1), c); \
                } \
            } \
        }
     
     
    unsigned char one_person_parse_one_line(t_one_person* one_person, char* one_line, size_t length, t_parser_error* error) {
        unsigned char ret;
     
        if ((one_person != NULL) && (one_line != NULL) && (length >= G_ONE_LINE_MIN_LENGTH)) {
            size_t count, str_count;
            char c;
     
            ret = 1;
     
    //      G_PARSING_GET_NEXT_CHAR(STATE_START, 1) with initialization and without the test
            count = 0;
            c = one_line[count];
            if ((c == '\n') || (c == '\r')) {
                ret = 0;
                parser_error_set(error, STATE_START, ERROR_UNEXPECTED_EOF, 0, (count + 1), c);
            }
     
            if (ret) {
    //          parse field 01: get id
     
                one_person->id = 1;
                str_count      = 0;
     
    //          Test the first number in order to set properly the variable ret if an error occurs
                if ((c < '0') || (c > '9')) {
                    ret = 0;
                    parser_error_set(error, STATE_FIELD01, ERROR_EXPECTED_NUMERAL, 1, (count + 1), c);
                }
            }
     
            if (ret) {
                do {
                    one_person->id = ((one_person->id * 10) + (c - '0'));
     
                    ++str_count;
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD01, 1)
                } while(ret && ((c >= '0') && (c <= '9')));
            }
     
            G_PARSING_MANAGE_SPACE(STATE_FIELD01, ERROR_EXPECTED_NUMERAL, STATE_SPACE01)
     
            if (ret) {
    //          parse field 02: get gender
     
                if ((c == 'H') || (c == 'h')) {
                    one_person->gender = GENDER_MASCULINE;
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD02, 1)
                } else if ((c == 'F') || (c == 'f')) {
                    one_person->gender = GENDER_FEMININE;
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD02, 1)
                } else {
                    ret = 0;
                    parser_error_set(error, STATE_FIELD02, ERROR_EXPECTED_GENDER, 0, (count + 1), c);
                }
            }
     
            G_PARSING_MANAGE_SPACE(STATE_FIELD02, ERROR_EXPECTED_GENDER, STATE_SPACE02)
     
            if (ret) {
    //          parse field 03: get last name
     
                str_count = 0;
     
    //          Test the first character in order to set properly the variable ret if an error occurs
                if (((c < 'a') || (c > 'z')) && ((c < 'A') || (c > 'Z'))) {
                    ret = 0;
                    parser_error_set(error, STATE_FIELD03, ERROR_EXPECTED_LETTER, 1, (count + 1), c);
                }
            }
     
            if (ret) {
                do {
                    one_person->last_name[str_count] = c;
     
                    ++str_count;
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD03, 1)
                } while(ret && (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))));
     
                if (ret) { one_person->last_name[str_count] = '\0'; }
            }
     
            G_PARSING_MANAGE_SPACE(STATE_FIELD03, ERROR_EXPECTED_LETTER, STATE_SPACE03)
     
            if (ret) {
    //          parse field 04: get first name
     
                str_count = 0;
     
    //          Test the first character in order to set properly the variable ret if an error occurs
                if (((c < 'a') || (c > 'z')) && ((c < 'A') || (c > 'Z'))) {
                    ret = 0;
                    parser_error_set(error, STATE_FIELD04, ERROR_EXPECTED_LETTER, 1, (count + 1), c);
                }
            }
     
            if (ret) {
                do {
                    one_person->first_name[str_count] = c;
     
                    ++str_count;
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD04, 1)
                } while(ret && (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))));
     
                if (ret) { one_person->first_name[str_count] = '\0'; }
            }
     
            G_PARSING_MANAGE_SPACE(STATE_FIELD04, ERROR_EXPECTED_LETTER, STATE_SPACE04)
     
            if (ret) {
    //          parse field 05: get has schorlarship
     
                if ((c == 'N') || (c == 'n')) {
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                    if ((c == 'O') || (c == 'o')) {
                        G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                        if ((c == 'N') || (c == 'n')) {
                            one_person->has_schorlarship = 0;
                            G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                        } else { ret = 0; parser_error_set(error, STATE_FIELD05, ERROR_EXPECTED_YES_NO, 3, (count + 1), c); }
                    } else { ret = 0; parser_error_set(error, STATE_FIELD05, ERROR_EXPECTED_YES_NO, 2, (count + 1), c); }
                } else if ((c == 'O') || (c == 'o')) {
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                    if ((c == 'U') || (c == 'u')) {
                        G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                        if ((c == 'I') || (c == 'i')) {
                            one_person->has_schorlarship = 1;
                            G_PARSING_GET_NEXT_CHAR(STATE_FIELD05, 1)
                        } else { ret = 0; parser_error_set(error, STATE_FIELD05, ERROR_EXPECTED_YES_NO, 3, (count + 1), c); }
                    } else { ret = 0; parser_error_set(error, STATE_FIELD05, ERROR_EXPECTED_YES_NO, 2, (count + 1), c); }
                } else { ret = 0; parser_error_set(error, STATE_FIELD05, ERROR_EXPECTED_YES_NO, 1, (count + 1), c); }
            }
     
            str_count = 3; // if an error occurs, at pos 4
            G_PARSING_MANAGE_SPACE(STATE_FIELD05, ERROR_EXPECTED_YES_NO, STATE_SPACE05)
     
            if (ret) {
    //          parse field 06: get rank
     
                if ((c >= '0') && (c <= '9')) {
                    one_person->rank = (c - '0');
     
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD06, 1)
                } else { ret = 0; parser_error_set(error, STATE_FIELD06, ERROR_EXPECTED_RANK, 0, (count + 1), c); }
            }
     
            G_PARSING_MANAGE_SPACE(STATE_FIELD06, ERROR_EXPECTED_RANK, STATE_SPACE06)
     
            if (ret) {
    //          parse field 07: get is handicapped
     
                if ((c == 'N') || (c == 'n')) {
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 1)
                    if ((c == 'O') || (c == 'o')) {
                        G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 1)
                        if ((c == 'N') || (c == 'n')) {
                            one_person->is_handicapped = 0;
                            G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 0)
                        } else { ret = 0; parser_error_set(error, STATE_FIELD07, ERROR_EXPECTED_YES_NO, 3, (count + 1), c); }
                    } else { ret = 0; parser_error_set(error, STATE_FIELD07, ERROR_EXPECTED_YES_NO, 2, (count + 1), c); }
                } else if ((c == 'O') || (c == 'o')) {
                    G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 1)
                    if ((c == 'U') || (c == 'u')) {
                        G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 1)
                        if ((c == 'I') || (c == 'i')) {
                            one_person->is_handicapped = 1;
                            G_PARSING_GET_NEXT_CHAR(STATE_FIELD07, 0)
                        } else { ret = 0; parser_error_set(error, STATE_FIELD07, ERROR_EXPECTED_YES_NO, 3, (count + 1), c); }
                    } else { ret = 0; parser_error_set(error, STATE_FIELD07, ERROR_EXPECTED_YES_NO, 2, (count + 1), c); }
                } else { ret = 0; parser_error_set(error, STATE_FIELD07, ERROR_EXPECTED_YES_NO, 1, (count + 1), c); }
            }
     
            if (ret) {
    //          Manage the end of line
                if ((c != '\n') && (c != '\r') && (c != '\0')) {
                    ret = 0;
                    parser_error_set(error, STATE_EOF, ERROR_EXPECTED_EOF, 0, (count + 1), c);
                }
            }
        } else {
            ret = 0;
        }
     
        return ret;
    }
     
     
    void one_person_reset(t_one_person* one_person) {
        if (one_person != NULL) {
            one_person->id               = 0;
            one_person->gender           = GENDER_UNDEFINED;
            one_person->last_name[0]     = '\0';
            one_person->first_name[0]    = '\0';
            one_person->rank             = 0;
            one_person->is_handicapped   = 0;
            one_person->has_schorlarship = 0;
        }
    }
     
     
    /*****************************************************************************/
    /***********************************  Main  **********************************/
    /*****************************************************************************/
     
    int main(int argc, char** argv)
    {
        FILE* file;
     
        file = fopen("test.txt", "r");
     
        if (file != NULL) {
            char one_line[G_ONE_LINE_LENGTH];
            t_one_person one_person;
            t_parser_error parser_error;
            size_t line;
     
            line = 0;
     
            while(fgets(one_line , G_ONE_LINE_LENGTH, file) != NULL) {
    //          printf("main - debug : %s\n", one_line);
     
                one_person_reset(&one_person);
                ++line;
     
                if ( one_person_parse_one_line(&one_person, one_line, G_ONE_LINE_LENGTH, &parser_error) ) {
                    sprintf(one_line, "One person at line %lu:", line);
     
                    one_person_display(&one_person, one_line);
                } else {
                    parser_error_to_string(&parser_error, one_person_get_field_name);
     
                    printf("main - debug : line %lu, %s\n\n", line, parser_error.str);
                }
            }
     
            fclose (file);
        } else {
            printf("main - debug : cannot open the file\n");
        }
     
     
        return EXIT_SUCCESS;
    }



    Et mon fichier test.txt
    100001 H Georges Guillaume Non 0 Non
    100002 H Alban Auch Non 9 Oui
    100003 H Desiret Duret Oui 7 Non
    100004 F Giselle Menetrie Oui 6 Oui

    Édit : La machine à états est tellement minimaliste (c'est une chaîne d'états et 1 état erreur) que la gestion des états, des erreurs, ... est vraiment très succinct.
    Quand bien même, on peut avoir des erreurs très précises et un parser très personnalisable.
    Et même si j'ai réussi à dissocier les erreurs d'une personne (les états et les erreurs sont utilisables à l'envi), il faudrait
    • casser le parser (qui est 1 grosse fonction) en plusieurs parsers, 1 pour un type précis (une chaîne de caractères, un booléen, ...) comme l'a fait @baragouine
    • peut-être refaire la gestion des espaces ... voire faire un mangeur d'espaces. Parce qu'on est toujours obligé de tester le premier caractère à part après un espace (c'est l'état espace qui le donne sans le tester)

  8. #8
    Expert éminent
    Citation Envoyé par jpagnol Voir le message
    J'aimerais bien mais comment représenter une structure [...] dans scanf ?
    Pour une structure, il faut prendre les membres 1 par 1.
    même avec un langage objet comme le C++, tu as toujours une méthode "en sous marin" qui récupère les champs 1 par 1 (par exemple, surcharge de l'opérateur >>)


    Citation Envoyé par jpagnol Voir le message
    J'aimerais bien mais comment représenter[...] une énumération dans scanf ?
    En C, une valeur de l'énumération est juste un entier (**)
    Et à partir de là, cela va dépendre de ton flux (fichier)
    • Soit dans ton flux, tu as un entier qui correspond à la valeur de l'énumération. C'est simple, tu récupères seulement un entier (peut-être avec un cast [entier vers ton énumération]). Mais si l'énumération change alors ton parser est aux fraises (***). Et dans ton flux, tu vas voir passer des entiers que tu ne vas pas comprendre à quoi cela correspond (Oui/ Non, Lundi/ Mardi/ ..., Janvier/ Fevrier/ ..., ...). Sans parler du fait qu'il ne faut pas se tromper lorsqu'on prend la valeur entière que vaut la valeur de l'énumération (***, à moins de spécifier dans l'énumération la valeur entière de chaque valeur )
    • Soit dans ton flux, tu as une chaîne de caractères ... comme tu l'as fait ("oui" - "non"). Il faut alors récupérer la chaîne de caractères, tester si elle est valide (*) et si c'est le cas, récupérer la valeur de l'énumération associée.


    Et je rajouterai que dans un fichier tout est caractère (ASCII par défaut). Mais si tu veux récupérer un entier "à la main", tu ne vas pas avoir des chiffres (0, 1, ..., 9) mais leurs caractères ASCII ('0', '1', ..., '9') (<- avec les calculs pour convertir un entier en caractère et réciproquement)
    La fonction scanf est quand même pratique pour cela ... et on l'oublie


    * : En C, tu ne peux pas comparer les chaînes de caractères avec l'opérateur ==. Il faut faire une comparaison CARACTÈRES par CARACTÈRES.
    Tu peux utiliser les fonctions strcmp ou strncmp (<- liens cplusplus.com en anglais)

    ** : Il a aussi un type (avec un typedef pour le rendre plus simple/ lisible), mais ce dernier sert pour le passage de paramètres et créer des variables. Dans un flux (fichier), ce sont les différentes valeurs de l'énumération qu'il est question.

  9. #9
    Futur Membre du Club
    Merci pour l'explication, j'apprécie ENORMEMENT (Sans rire je sais pas si je suis idiot mais j'ai souvent beaucoup de mal à me documenter sur des sujets comme cela) .

    Au final, j'ai trouvé une alternative.
    J'ai remplacé les Non du fichier par des 0 et les Oui par des 1.
    Et quand je dois afficher un profil d'étudiant, j'utilise un switch.

    Mais ...
    Le fait de charger tout ces 0 et 1 puis de les traduire en Non ou Oui (à l'affichage) ne représente t-il pas une augmentation trop grande du point de vue des opérations exécutées ?
    Ici on parle d'une cinquantaine de profils mais à plus grande échelle, ce pour quoi j'ai opté est insensé non ?

  10. #10
    Rédacteur/Modérateur

    Non et c'est la bonne façon de faire.
    L'affichage n'a rien à voir avec la valeur réelle. On peut vouloir afficher non/false/exit/0 quand on rencontre un 0.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

###raw>template_hook.ano_emploi###