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 :

Lire un fichier de données : combinaison chaînes de caractères et nombres


Sujet :

C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 122
    Points : 66
    Points
    66
    Par défaut Lire un fichier de données : combinaison chaînes de caractères et nombres
    Bonsoir,

    Je souhaite au tout début de mon programme principal, lire un fichier contenant des données qui seront utilisées plus loin dans le programme. J'aimerai que le contenu de ce fichier donnees.txt soit organisé de la manière suivante :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    rayon=0.25
    gravite=9.81
    densite=1200
    rayon, gravite, densite : sont des variables qui seront utilisées dans le code avec donc les affectations correspondantes.

    il s'agit bien évidemment d'une simplification, en réalité je dispose au jour d'aujourd'hui d'un peu plus de 50 paramètres d'entrée.

    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
     
     
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #define TAILLE_MAX 1000
     
     
    main()
    {
        FILE* fichier = NULL;
        char chaine[TAILLE_MAX] = "";
        double pi,rayon,densite,poids;
     
        poids=0.0;
        fichier = fopen("donnees.txt", "r");
     
        if (fichier != NULL)
        {
            while (fgets(chaine, TAILLE_MAX, fichier) != NULL) 
            {
                printf("%s", chaine); 
            }
     
           /* ici je souhaiterai par exemple calculer le poids (pour une sphere par exemple) */
     
            poids=(4.0/3.0)*pi*(rayon*rayon*rayon)*densite ;
    		printf("poids=%e \n",poids);
            fclose(fichier);
        }
     
        return 0;
    }
    Le programme m'affiche bien à l'écran le contenu de mon fichier donnees.txt, mais le calcul de ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     poids=(4.0/3.0)*pi*(rayon*rayon*rayon)*densite ;
    donne n'importe quoi, autrement dit il ne lit pas les bonnes données. Je suis conscient que le programme me renvoi simplement ce que je lui demande.

    Pouvez-vous me venir en aide?

    En revanche, quand je mets mes données dans un fichier donnees.h que j'inclue dans le préambule de mon code, ça marche parfaitement bien, le problème est que si je modifie simplement une donnée, je dois recompiler...mais c'est une solution qui marche.

    Troisièmement, Si j'écris mon fichier de données de la manière suivante :

    et que dans le main je demande à rentrer successivement ces paramètres au clavier (enfin à l'aide d'un fichier de commande.bat contenant la ligne de commande suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    main.exe < donnees.txt
    et en utilisant scanf ça marche aussi très bien, l'inconvénient c'est que si j'ai une longue liste des paramètres, on se perd un peu en l'absence du libellé.

    C'est pour cette raison que je tiens à utiliser la première méthode mais qui ne marche pas.

    Merci d'avance pour votre aide.

  2. #2
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Tu as raison, la première méthode est la meilleure. Essaie dans un premier temps de faire un programme fonctionnant avec les 3 paramètres d'entrée (rayon, densité, gravité) que tu as choisis pour l'expérimentation. N'utilise même pas, à ce stade, de boucle while.

    Quand tu fais fgets sur la première ligne, tu obtiens dans chaine : "rayon=0.25\n". Tu veux extraire la valeur 0.25. Utilise alors sscanf :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    double r;
    sscanf(chaine, "rayon=%lf\n", &r);
    Maintenant, on a bien 0.25 dans r.

    strtok + atof peut également être une alternative à sscanf. Après, il faudra penser à simplifier (en introduisant une boucle) et à sécuriser (notamment en examinant le retour de sscanf avant de continuer ou en remplaçant atof par strtod, selon le cas) ton programme.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 122
    Points : 66
    Points
    66
    Par défaut
    Merci Melem pour tpn aide, j'ai adapté mon code par rapport à tes explications.
    Voici le nouveau code :

    fichier à lire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    rayon=0.5
    gravite=9.81
    densite=2500
    le code devient :

    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
     
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #define TAILLE_MAX 1000
    #define pi 3.14
     
    main()
    {
        FILE* fichier = NULL;
        char chaine[TAILLE_MAX] = "";
        double rayon,densite,poids,gravite;
     
        poids=0.0;
        fichier = fopen("parametres.txt", "r");
     
        if (fichier != NULL)
        {
            while (fgets(chaine, TAILLE_MAX, fichier) != NULL) 
            {
                printf("%s", chaine); 
    			sscanf(chaine, "rayon=%lf\n", &rayon);
    			sscanf(chaine, "gravite=%lf\n", &gravite);
    			sscanf(chaine, "densite=%lf\n", &densite);
     
     
            }
     
    		poids=(4.0/3.0)*pi*(rayon*rayon*rayon)*densite*gravite ;
     
     
    		printf("poids=%e \n",poids);
            fclose(fichier);
        }
     
        return 0;
    }
    il faut donc que sscanf soit bien entendu à l'intérieur de la boucle while.

    Merci, le code marche bien.

    Seul problème : je dois lire les données dans l'ordre (comme elles sont dans le fichier), ça veut dire que je ne peux pas simplement extraire une donnée (par exemple gravite ) qui se trouverait à une position quelconque. Je pense que je dois en quelque sorte affecter une adresse à chaque paramètre comme si je lisais dans un tableau... je me trompe peut être??? Et si c'est le cas, comment procéder? as-tu une solution à me proposer?

    Il faut créer une structure?

    Déjà je pense que cette solution aidera beaucoup de monde, elle est suffisante s'il y a très peu de données à lire.

  4. #4
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Ton code marche "par chance". Normalement, tu ne devrais pas utiliser de boucle mais 3 séries de fgets-sscanf. Pour la suite, il suffit juste d'utiliser des tableaux :
    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
    #define NB_PARAMS 3
     
    enum params {RAYON, GRAVITE, DENSITE};
    const char * param_name[NB_PARAMS] = {"rayon", "gravite", "densite"};
     
    #define MAX_PARAM_NAME 13
     
    int main() {
        ...
        double param_value[NB_PARAMS];
        int i;
        ...
        while (fgets(chaine, TAILLE_MAX, fichier) != NULL) {
            char name[MAX_PARAM_NAME];
            double value;
            sscanf(chaine, "%[^=]=%lf\n", name, &value);
            i = get_param_index(name);
            param_value[i] = value;
        }
    }
    Donc on a le rayon dans param_value[RAYON], la gravité dans param_value[GRAVITE] et la densité dans param_value[DENSITE]. int get_param_index(const char * name) est évidemment une fonction qui retourne l'index associé, dans le tableau param_value, à un paramètre en fonction de son nom. Par exemple, get_param_index("rayon") doit retourner 0 (RAYON), get_param_index("gravite") doit retourner 1 (GRAVITE), etc.

    T'as du travail dis donc . Tu dois également penser à améliorer le programme au niveau robustesse ...

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 122
    Points : 66
    Points
    66
    Par défaut
    Tout d'abord merci. Oui j'ai du travail... j'apprends le c depuis 1 mois et demi seulement (et pas tous les jours) donc je suis loin d'être un spécialiste...

    Ton code ne compile pas, il ne trouve pas la fonction get_param_index().

    Je suis sous window avec MinGW

  6. #6
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Oui, ce code ne compilera pas avant que tu ne l'aie complété. La fonction get_param_index, t'étais également censé l'écrire mais comme je vois que t'as un peu de mal, je vais te montrer un exemple d'implémentation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int get_param_index(const char * name) {
        int i;
        for(i = 0; i < NB_PARAMS; i++) {
            if (strcmp(param_name[i], name) == 0)
                break;
        }
        return i;
    }
    Maintenant, assemble tout ça pour obtenir un code complet qui compile. Poste ensuite ton code pour qu'on puisse encore l'améliorer, surtout au niveau robustesse, qui est une chose très importante.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 122
    Points : 66
    Points
    66
    Par défaut
    ok, j'ai assemblé mon code, la compilation se passe bien, quand je l'exécute, il m'affiche les bonnes positions de mes paramètres dans le tableau, cependant, il affiche 0.000000 pour toutes les valeurs de mes paramètres alors qu'aucune de ces valeurs n'est nulle.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    rayon=0.5
    gravite=9.81
    densite=2500
    Voici le code :

    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
     
     
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #define TAILLE_MAX 1000
     
    #define NB_PARAMS 3
    #define MAX_PARAM_NAME 13
     
    enum params {rayon, gravite, densite};
    const char * param_name[NB_PARAMS] = {"rayon", "gravite", "densite"};
     
     int get_param_index(const char * name) 
     {
        int i;
        for(i = 0; i < NB_PARAMS; i++) {
            if (strcmp(param_name[i], name) == 0)
                break;
        }
        return i;
    }
     
     
     
    int main()
     {
        FILE* fichier = NULL;
        char chaine[TAILLE_MAX] = "";
        //double rayon,densite,poids,gravite;
     
        double param_value[NB_PARAMS],r;
        int k;
        fichier = fopen("parametres.txt", "r");
     
        while (fgets(chaine, TAILLE_MAX, fichier) != NULL) {
            char name[MAX_PARAM_NAME];
            double value;
            sscanf("%s=%lf\n", name, &value);
            k = get_param_index(name);		
            param_value[k] = value;
     
        }
     
    	printf("rayon=%lf \n",param_value[densite]);
    	printf("position densite dans tableau=%d \n",get_param_index("densite"));
     
     
     
    //poids=(4.0/3.0)*pi*(rayon*rayon*rayon)*densite*gravite ;
     
     
     
        fclose(fichier);
     
     
    }
    Merci à toi.

  8. #8
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    En effet, j'ai commis deux "petites" erreurs :

    1. Ce n'est pas sscanf("%s=%lf\n", ...) mais sscanf(chaine, "%s=%lf\n", ...). En effet, sscanf "scanfe" une chaîne passée en paramètre, contrairement à scanf qui scanfe une chaîne entrée depuis stdin.

    2. Ce n'est pas sscanf(chaine, "%s=%lf\n", ...) mais sscanf(chaine, "%[^=]=%lf\n", ...). %[^=] signifie qu'on lit tous les caractères jusqu'à ce que l'on rencontre = (alors que %s signifie qu'on lit tous les caractères jusqu'à ce qu'on rencontre un "blanc", un espace par exemple). "scanf" est une fonction très subtile, c'est pourquoi son usage est souvent déconseillé aux débutants.

    En éditant ton code en tenant compte de ces remarques, on obtient :
    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
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #define TAILLE_MAX 1000
     
    #define NB_PARAMS 3
    #define MAX_PARAM_NAME 13
     
    enum params {rayon, gravite, densite};
    const char * param_name[NB_PARAMS] = {"rayon", "gravite", "densite"};
     
    int get_param_index(const char * name) 
    {
        int i;
        for(i = 0; i < NB_PARAMS; i++) {
            if (strcmp(param_name[i], name) == 0)
                break;
        }
        return i;
    }
     
    int main()
    {
        FILE * fichier = NULL;
        char chaine[TAILLE_MAX];
     
        double param_value[NB_PARAMS];
        int k;
        fichier = fopen("parametres.txt", "r");
     
        while (fgets(chaine, TAILLE_MAX, fichier) != NULL) {
            char name[MAX_PARAM_NAME];
            double value;
     
            sscanf(chaine, "%[^=]=%lf", name, &value);
            printf("%s=%f\n", name, value);
            k = get_param_index(name);        
            param_value[k] = value;
        }
     
        /* poids = (4.0 / 3.0) * pi * (rayon *rayon * rayon) * densite * gravite; */
     
        fclose(fichier);
     
        return 0;
    }
    J'ai galement édité en conséquence mes anciennes réponses.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 122
    Points : 66
    Points
    66
    Par défaut
    Merci Melem pour tes conseils, j'ai appris beaucoup de choses...

    Le code fonctionne correctement.

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 03/07/2014, 19h08
  2. Lire un fichier de données et les mettre dans un tableau
    Par giovanni dans le forum Entrée/Sortie
    Réponses: 19
    Dernier message: 18/02/2014, 15h50
  3. Réponses: 7
    Dernier message: 06/01/2011, 20h29
  4. Réponses: 4
    Dernier message: 24/05/2010, 14h06
  5. Lire un fichier de donnée en utilisant des variables
    Par mehdichess74 dans le forum VB.NET
    Réponses: 1
    Dernier message: 14/04/2008, 12h48

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