IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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 :

Extraire des données


Sujet :

C

  1. #1
    Membre régulier
    Inscrit en
    Mai 2008
    Messages
    146
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 146
    Points : 81
    Points
    81
    Par défaut Extraire des données
    Bonjour à tous,

    Je ne tournerais pas autour du pot, alors voila, je dois extraire des données d'un fichier CSV et en me baladant sur le Net, je suis tombé sur un excellent tuto de Frank H. sur lequel je me suis appuyé malgré mon très faible niveau (en C).

    Seulement je dois avoir un problème au niveau de l'étude algorithmique car je pense m'etre trop appuyer sur le tuto alors que les objectifs sont sensiblement différent.

    (Pardon je tourne autour du pot...)

    Donc mon objectif est l'extraction des données d'un fichier CSV (recensement des pays par année), dans le but de manipuler ces données par la suite.

    Le programme compile mais plante à l'execution.

    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
     
     
    // Permet de copier une chaine de caracteres.
    //Grosse utilisation dans le cas de l emploi de strtok qui modifie la chaine passee en entrée
    static char * copie_chaine (const char * chaine)
    {
    char * copie = NULL;
    if (chaine != NULL)
    {
        size_t taille = strlen (chaine) + 1;
        copie = malloc (taille);
        if (copie != NULL)
        {
            memcpy (copie, chaine, taille);
        }
    }
    return copie;
    }
     
    //Permet de terminer la chaine de caracteres avec un zero de fin de chaine
    //ce qui n'est pas le cas avec les chaines extraites d'un fichier qui elles terminent avec un \n
    // Or les fonctions standards attendent des zeros de fin
     
    static void term_chaine(char * chaine){
        char * p = strchr(chaine, "\n");
        if(p != NULL){
            *p=0;
        }
    }
     
    //structure definissant un pays
    typedef struct
    {
    char *  nomPays;
    int     annee;
    int     popuTotale;
    int     nbH;
    int     nbF;
    char *  tranchAge;// exemple : 35-36
    }
    infos_pays;
     
     
    //tres utile pour le switch
    typedef enum
    {
        NOM_PAYS,
        ANNEE,
        TRANCHAGE,
        NBTOTAL,
        NBH,
        NBF
     
    } infos_type;
     
     
     
     
     
     
     
     
    infos_pays * get_infos_8 (const char * file)
    {
        infos_pays * infos = NULL;//structure de retour
        FILE * fic = NULL;
        char * k = NULL;
        char *buff [1000];//tampon
        fic = fopen (file, "r");
        if (fic != NULL)
        {
            if ((fgets (buff, 1000, fic)) != NULL)//lit le fichier ligne par ligne
            {
                char * p = buff;
                int i = 0;
                infos = malloc (sizeof (* infos));
                if (infos != NULL)
                {
                    while ((k = strtok (p, ",")) != NULL)// tant qu'il y a des mots a extraire
                    {
                        if (i == 0)//premier retour de strtok donc pour le nom pays
                        p = NULL;
                        switch (i)
                        {
                            case NOM_PAYS:
                                infos->nomPays = copie_chaine (k);
                                break;
                            case ANNEE:
                                infos->annee = copie_chaine (k);
                                break;
                            case TRANCHAGE:
                                infos->tranchAge = copie_chaine (k);
                                break;
                            case NBTOTAL:
                                infos->popuTotale = copie_chaine (k);
                                break;
                            case NBH:
                                infos->nbH = copie_chaine (k);
                                break;
                            case NBF:
                                infos->nbF = copie_chaine (k);
                                break;
                        }
                        i++;//mot suivant
                    }
                }
            }
            fclose (fic);
        }
        printf("Pays : %s -> Check !", infos->nomPays);//surement ce qui provoque l erreur d exec
        return infos;
    }
    PS : Je précise que mon but est uniquement la compréhension et que je retirerais ce code si ça devait gêner Frank H.


    Merci beaucoup d'avance.

  2. #2
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par larchicha Voir le message
    Le programme compile mais plante à l'execution.
    où et avec quel diagnostic ??
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  3. #3
    Membre régulier
    Inscrit en
    Mai 2008
    Messages
    146
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 146
    Points : 81
    Points
    81
    Par défaut
    Je lance le build+run sous CodeBlocks

    La console se lance puis une fenetre Windows se lance : Extraction.exe has stopped working ... windows cherche une solution...

    Puis quand je quitte la fenetre Win, la console indique : Process returned -107374189 (code hexa) execution time : 3.085s
    Press any key to continue

  4. #4
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 508
    Points
    5 508
    Par défaut
    Tu trouveras mes commentaires directement dans le code. Il y a pas mal de petites erreurs. Notamment, dans ta fonction copie_chaine() (un clone de strdup() qui est une fonction POSIX.1 disponible sur de nombreux systèmes et présente dans la bibliothèque standard de MinGW et de gcc), tu oublies de mettre le dernier caractère de la chaine pointée par copie à '\0'. En effet, memcpy() ne le fait pas automatiquement, c'est pour cette raison que je préfère l'utilisation de strcat() ou strncat() pour toutes mes copies de chaines de caractères.

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    /* -tc- Dans la fonction get_infos_8(), tu traites tous les champs de la structure
       comme des chaines de caractere. Je modifie ta structure en fonction de
       get_infos_8(). Toutefois, c'est peut-etre get_infos_8() qui n'est pas en
       accord avec ta conception */
    typedef struct
    {
        char *  nomPays;
        char *  annee;
        char *  popuTotale;
        char *  nbH;
        char *  nbF;
        char *  tranchAge; // exemple : 35-36
    } infos_pays;
     
     
    //tres utile pour le switch
    typedef enum
    {
        NOM_PAYS,
        ANNEE,
        TRANCHAGE,
        NBTOTAL,
        NBH,
        NBF
     
    } infos_type;
     
    static char * copie_chaine(const char *chaine)
    {
        char * copie = NULL;
        if (chaine != NULL)
        {
            size_t taille = strlen (chaine) + 1;
            /* -tc- meme si un char fait un byte par definition en C, il est
               dangereux de ne pas se premunir contrer un changement du type a
               l'avenir: multiplie taille par sizeof *copie */
            copie = malloc (taille * sizeof *copie);
            if (copie != NULL)
            {
                /* -tc- memcpy() n'ajoute pas de caractere nul terminal a la fin
                   de la chaine et tu ne le fais pas manuellement. Pour copier des
                   chaines, je prefere la fonction strcat() qui ajoute le '\0'
                   terminal a la fin de la chaine
     
                memcpy (copie, chaine, taille);
                */
                *copie = '\0';
                strcat(copie, chaine);
            }
        }
        return copie;
    }
     
    static void term_chaine(char *chaine)
    {
        /* -tc- attention: strchr() prend un entier en deuxieme parametre, et non
           une chaine de caracteres */
        char * p = strchr(chaine, '\n');
        if(p != NULL)
        {
            *p = 0;
        }
    }
     
     
    infos_pays * get_infos_8(const char * file)
    {
        infos_pays * infos = NULL; //structure de retour
        FILE * fic = NULL;
        char * k = NULL;
        /* -tc- attention: buff a le type tableau de 1000 pointeurs sur chars, alors
           que tu veux declarer cette variable comme un tableau de 1000 chars.
           Au passage, c'est probablement une bonne idee d'initialiser ton tableau */
        char buff [1000] = "";
     
        fic = fopen(file, "r");
        if (fic != NULL)
        {
            if ((fgets (buff, sizeof buff, fic)) != NULL)
            {
                char * p = buff;
                int i = 0;
     
                term_chaine(buff);
     
                infos = malloc (sizeof (* infos));
                if (infos != NULL)
                {
                    /* -tc- Je deconseille l'utilisation de strtok() qui a le desavantage
                       d'utiliser un tampon statique pour stocker ta chaine entre
                       deux appels, ce qui la rend non réentrante et thread-unsafe.
                       prefere l'utilisation de strtok_r() (POSIX.1) */
                    while ((k = strtok(p, ",")) != NULL)
                    {
     
                        if (i == 0)
                        {
                            p = NULL;
                        }
     
                        switch (i)
                        {
                        case NOM_PAYS:
                            infos->nomPays = copie_chaine(k);
                            break;
                        case ANNEE:
                            /* -tc- Dans la definition initiale de ta structure, le
                               champ infos->annee et les suivants sont de type int
                               et non de type pointeur sur char */
                            infos->annee = copie_chaine(k);
                            break;
                        case TRANCHAGE:
                            infos->tranchAge = copie_chaine(k);
                            break;
                        case NBTOTAL:
                            infos->popuTotale = copie_chaine(k);
                            break;
                        case NBH:
                            infos->nbH = copie_chaine(k);
                            break;
                        case NBF:
                            infos->nbF = copie_chaine(k);
                            break;
                        }
                        i++; //mot suivant
                    }
                }
            }
            /* -tc- Une fois que fic est ferme, on reaffecte a fic une adresse
               invalide testable, a savoir NULL */
            fclose(fic), fic = NULL;
        }
        /* -tc- ATTENTION: si l'ouverture de ton fichier echoue, infos->nonPays
           dereference le pointeur infos dont l'adresse est invalide (NULL). Le
           comportement est indetermine ici.
        printf("Pays : %s -> Check !", infos->nomPays);
        */
        return infos;
    }
    Avec mes meilleures salutations

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  5. #5
    Membre régulier
    Inscrit en
    Mai 2008
    Messages
    146
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 146
    Points : 81
    Points
    81
    Par défaut
    Merci pour vos corrections très détaillées professeur Chappuis.
    Tout devient plus clair...

  6. #6
    Membre régulier
    Inscrit en
    Mai 2008
    Messages
    146
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 146
    Points : 81
    Points
    81
    Par défaut
    La fonction apparaît plus claire maintenant cependant lorsque j'applique la fonction sur mon fichier annee2000.csv , le programme compile et s'exécute sans accro mais comment saurais je si toutes les données ont bien été extraites si je ne peux pas printf le résultat ?

    Mon erreur d'exécution provenait de là en fait, et dans mon esprit,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%s \n", infos->nom_Pays);
    est censé m'afficher toutes les données qui ont été extraites vers la structure infos_pays. (Je sais pertinemment que ce n'est pas ça, j'expose simplement mes difficultés).

    Merci d'avance du temps que vous me consacrez.

  7. #7
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 508
    Points
    5 508
    Par défaut
    Tu peux placer ton appel() à printf juste avant ou juste après ton appel à fclose().

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  8. #8
    Membre régulier
    Inscrit en
    Mai 2008
    Messages
    146
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 146
    Points : 81
    Points
    81
    Par défaut
    Super ! Tout roule impec'
    Encore merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Système] Extraire des données d'une page web
    Par nazoreen dans le forum Langage
    Réponses: 17
    Dernier message: 22/03/2006, 22h38
  2. Extraire des donnés d'un fichier texte
    Par sadsad dans le forum Langage
    Réponses: 2
    Dernier message: 07/02/2006, 16h09
  3. Réponses: 7
    Dernier message: 29/09/2005, 11h19
  4. Réponses: 1
    Dernier message: 28/09/2005, 16h35
  5. extraire des données d'un code HTML
    Par blueice dans le forum Langage
    Réponses: 5
    Dernier message: 19/08/2004, 20h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo