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

Réseau C Discussion :

Lire un mot dans un fichier [Débutant(e)]


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2007
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2007
    Messages : 17
    Par défaut Lire un mot dans un fichier
    Bonjour à tous

    Voila j'aurais besoin d'un coup de main pour un petit programme surrement enfantin pour vous:

    Dans mon programme principal :
    - j'ouvre un fichier en lecture
    - je fait appel à une procédure qui doit lire le premier mot du fichier et le mettre dans une chaine de caractère

    Voilà ce que j'ai fait :
    ------------------------------------------------------------
    Dans mon programme principal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int main(int argc, char **argv){
     
    FILE * fichier;
    char * p;
    p = (char*) calloc(50,sizeof(char));
     
    fichier = fopen(argv[1], "r");                                         //ouverture du fichier
    liremot(&fichier,&p);                                                   //lecture du premier mot
    printf("Le premier mot du fichier est : %s\n",p);            //affichage du premier mot
    ----------------------------------------------------------------------------------------------
    Ma procédure (dans un autre fichier .c)

    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
     
    void liremot(FILE **f, char **p){
     
    char c;
    char * q = (*p);
     
    while ((c = fgetc(*f)) == ' ') {}               //permet d'ignorer les espaces avant le mot
     
    *q = c;
     
    while ((c = fgetc(*f)) != ' ') {                        //on lit les caractères suivant jusqu'à ce
                                                                   //qu'on trouve un autre espace
    q++;
    *q=c;
    }
    -------------------------------------------------------

    Ca compile sans erreur, aucune erreur non plus avec valgrind.

    Dans mon fichier test.sl j'ai écrit : "PRINT LET "

    J'ai quelques questions à propos de ce truc, car en fait j'ai réussi à le faire fonctionner un peu en y allant au pif.....

    1 / Est ce que je peut faire des simplifications ? (par exemple ne pas utiliser le pointeur q ou la variable c dans la procédure)

    2/ Comment initialiser ma chaine de caratères p au début de la procédure : car si je lit le premier mot puis le second, pour le second au lieu d'obtenir LET j'obtient LETNT (la fin de PRINT est toujours la). En effet elle est seulement initialisée au début du programme avec la fonction calloc (et je doute que faire un free et un autre calloc a chaque fois soit une solution....)

    3/ Comment je doit modifier cette ligne pour qu'il s'arrête également à un retour à la ligne, à une tabulation ou à la fin du fichier...?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    while ((c = fgetc(*f)) != ' ')
    (ne suffit pas car si par exempe c'est le dernier mot du fichier il ne trouve pas d espace et j 'ai un segmentation fault...)

    J'ai essayé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while ((c = fgetc(*f)) != (' ' || '\n' || '\t' || EOF))
    mais ca ne fonctionne pas


    Voilà c'est tout pour le moment mais c'est le début d'un projet qui consiste à créer un interpreteur de "simple langage" donc je pense que j'aurais encore besoin de votre aide lol...

  2. #2
    Membre émérite Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Par défaut

    Penser aussi à l'indentation du code...

  3. #3
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2007
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2007
    Messages : 17
    Par défaut
    Ok pour la balise c'est vrai que c'est plus lisible.

  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 : 48
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Salut,

    Dans main(), tu fait deux erreurs graves: tu ne testes pas la valeur de retour de calloc, ni celle de fopen. Comme pour malloc, il n'est pas conseillé de caster la valeur de retour de calloc. Ainsi, on peut écrire:
    p = calloc(50, sizeof *p);

    En ce qui concerne, liremot, je ne comprend pas pourquoi tu utilises l'interface suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void liremot(FILE **f, char **p)
    Je te conseille d'utiliser le prototype suivant pour définir ta fonction. Le commentaire Doxygen correspond à la spécification de la fonction que je
    d'écrire en améliorant ton code. Dis-moi si elle t'intéresse (?):
    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
     
    /**
     * Lit un mot dans le fichier.
     *
     * @param file Pointeur sur le fichier ouvert par fopen()
     * @param p_buff Pointeur sur le 1er élément d'un tableau de caractères
     *               servant de tampon
     * @param buff_size Taille du tampon
     *
     * @return Code d'erreur: 0 si OK, >0 si une erreur de lecture est intervenue
     *                        (mot coupé car buff_size insuffisant), et EOF si
     *                        si EOF est rencontré, ou si file ou p_buff vaut NULL.
     */
    int lire_mot(FILE *file, char *p_buff, size_t buff_size)
    {
        /* ... */
     
    }
    En attendant, n'oublie pas que fgetc() retourne un int et non un char. Asnis, on doit avoir:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int c;
    c = fgetc(fp); /* où fp est de type pointeur sur FILE et ouvert avec fopen()*/
    Si tu définis c comme un char, il ne pourra pas recevoir la valeur de fin de fichier EOF.

    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 averti
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2007
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2007
    Messages : 17
    Par défaut
    Merci pour tes explications.

    Pour tester le retour le fopen je fait un "if fichier != NULL etc..." c'est ca ?
    Par contre pour tester le calloc je vois pas ...?

    Concernant la fonction liremot je lui envoi en paramètre le fichier que j'ai ouvert (sauf que le double pointeur doit etre de trop) ainsi que l'adresse du pointeur de chaine de caractère (comme le pointeur va etre modifié je lui envoi l'adresse...enfin c'est ce qu'on m'a apris)

    Sinon pour la fonction je veux bien oui, sauf que je comprend pas trop le "size_t buff-size...."

    En fait mon programme (un interpreteur), doit lire un fichier dans lequel se trouve des instructions écrites en "simple langage"
    (instructions élémentaires : BEGIN, END, PRINT, LET, GET, FOR...ROF, IF...FI)
    Donc la première étape est de lire un mot dans le fichier pour détecter ces mots clé.
    Je déclare donc un pointeur de chaine dans le programme principale et j'utilise ma fonction liremot pour lire un mot dans le fichier...ensuite je compare le contenu de la chaine pointée par p avec les différents mot clé pour lancer une procedure correspondante. Enfin je sais pas si je me fait bien comprendre lol.

    Le fait est que je declare un pointeur p de taille 50*sizeof(char) pour etre sur de pouvoir stocker tous les mots car je vois pas du tout comment redimensionner mon pointeur en fonction du mot à lire...d'autant plus que je le declare dans mon programme principale et qu'il faut le modifier dans une procedure...

    Bref je debute je m'embrouille un peu avec tout ca ^_^ Mais je veux bien voir ta fonction ca me donnera une idée de ce qu'on peut faire de bien

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 15
    Par défaut
    La fonction calloc te retourne un pointeur sur la zone mémoire allouée. Si le calloc n'a pas fonctionné alors le pointeur retourné est le pointeur NULL.

    Il faut donc que tu testes si le pointeur p est NULL ou non. Du manière générale quand un malloc (calloc ...) retourne un pointeur NULL alors tu termines purement et simplement l'application. Pour ma part pour tester le code de retour de ces fonctions j'utilise la fonction assert qui termine le programme si l'assertion est fausse.

    Dans ton cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    assert((p = calloc(50,sizeof(char)) != NULL)
    Si le pointeur p est NULL alors l'application se termine avec un joli message d'erreur

    J'ai une question moi aussi : pourquoi il est déconseillé de caster la valeur de retour d'un calloc ou malloc ? Dans le cadre du c++ ca ne marche pas si on ne fait pas le cast.

  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 : 48
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Duf59
    Sinon pour la fonction je veux bien oui, sauf que je comprend pas trop le "size_t buff-size...."
    buff_size te permet de spécifier la taille du tampon, un peu à la manière de la fonction fgets() pour la saisie d'une ligne. C'est à dire que si ton mot est plus long que la mémoire allouée à ton tampon, tu peux avoir des problèmes.

    Dans la fonction que je te propose ici, il y a acquisition dans le tampon p_buff de haut plus buff_size-1 caractères et le caractère nul terminal est ajouté automatiquement à la fin de la chaine, et cela, même si ton fichier contient un mot très long. La fonction lire_mot() renvoie les codes d'erreur suivant:
    • 0 si tout c'est bien passé
    • EOF si la fin de fichier à été rencontrée sans qu'aucun caractère différent d'un espace ait été lu
    • EOF si NULL est passé en paramètre pour file ou p_buff. Auncune lecture n'est effectuée et le contenu du tampon n'est pas modifié.
    • le nombre de caractères placés dans p_buff (>0) si le mot est plus long buff_size-1 (le caractère nul est toujours placé à la fin de la chaine).

    Je l'ai fait assez rapidement, c'est pas forcément le code le plus élégant, mais ça compile sans avertissement, et les tests donnent une exécution correcte:
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
     
    /**
     * Lit un mot dans le fichier.
     *
     * @param file Pointeur sur le fichier ouvert par fopen()
     * @param p_buff Pointeur sur le 1er élément d'un tableau de caractères
     *               servant de tampon
     * @param buff_size Taille du tampon
     *
     * @return Code d'erreur: 0 si OK, >0 si une erreur de lecture est intervenue
     *                        (mot coupé car buff_size insuffisant), et EOF si
     *                        si EOF est rencontré sans qu'aucun caractère n'ait été
     *                        lu, ou si file ou p_buff vaut NULL.
     */
     
    int lire_mot(FILE *file, char *p_buff, size_t buff_size)
    {
        /*-TC- Attention, fgetc() retourne un int, car EOF ne peut être
           représenté par un char */
        int c;
        int i;        /* indice de boucle */
        int err = 0;  /* code d'erreur*/
     
        if (file != NULL && p_buff != NULL)
        {
            /* -TC- inclure le fichier d'en-tête standar ctype.h pour isspace() */
            while (isspace(c = fgetc(file)) && (c != EOF))
            {
                continue; /*Cette boucle ne fait rien */
            }
            if (c != EOF)
            { /* Le fichier contient au moins un caractère différent d'un espace
                 ou de EOF*/
     
                /* Acquisition du mot: au plus buff_size-1 caractère. Fin du mot
                   marquée par un espace ou par EOF */
                for (p_buff[0] = c, i = 1;
                        (i < (int) buff_size - 1) &&
                        (c = fgetc(file)) != EOF &&
                        !isspace(c);
                        ++i)
                {
                    p_buff[i] = c;
                }
                /* On place un caractère nul à la fin de la chaîne */
                p_buff[i] = '\0';
     
                /* Si la fin du mot n'a pas été atteinte: le mot est plus long que
                   buff_size-1 caractères --> La fonction retourne le nombre de
                   caractères placés dans p_buff */
                if (!isspace(c) && c != EOF)
                {
                    err = i;
                }
            }
            else
            {
                /* Lorsque le status d'erreur est EOF, p_buff ne reçoit aucun caractère*/
                p_buff[0] = '\0';
                err = EOF;
            }
        }
        else
        {
            err = EOF;
        }
     
        return err;
     
    }
     
    /* Fonction main() de test de lire_mot */
    int main(void)
    {
        int i; /* indice de boucle */
        int rc; /* return code */
        char s_buffer[15] = {'\0'};
        FILE *fp;
     
        /* Création d'un fichier test.txt*/
        fp = fopen("test.txt", "w");
        if (fp == NULL)
        {
            fprintf(stderr, "Impossible d'ouvrir test.txt en écriture!\n");
            exit(EXIT_FAILURE);
        }
        fprintf(fp, "  mot1 un_autre_mot2 ceci_est_un_mot_long");
        fclose(fp);
     
        /* Lecture du fichier test.txt */
        fp = fopen("test.txt", "r");
        if (fp == NULL)
        {
            fprintf(stderr, "Impossible d'ouvrir test.txt en lecture!\n");
            exit(EXIT_FAILURE);
        }
     
        for (i = 1; i <= 6; ++i)
        {
            rc = lire_mot(fp, s_buffer, sizeof s_buffer);
            switch (rc)
            {
            case 0:
                printf("%d: Mot-> \"%s\" err_status-> %s!\n",
                       i, s_buffer, "OK");
                break;
            case -1:
                printf("%d: Mot-> \"%s\" err_status-> %s!\n",
                       i, s_buffer, "EOF");
                break;
            default:
                printf("%d: Mot-> \"%s\" err_status-> %s!\n",
                       i, s_buffer, "Mot trop long");
                break;
            }
        }
        close(fp);
        return EXIT_SUCCESS;
    }
    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++

    +

Discussions similaires

  1. Lire un mot dans un fichier texte
    Par Sophie_Géo dans le forum Développement de jobs
    Réponses: 9
    Dernier message: 12/03/2015, 14h06
  2. Ecrire & Lire des énumérés dans un fichier Texte
    Par WebPac dans le forum Langage
    Réponses: 8
    Dernier message: 18/06/2008, 10h04
  3. lire un mot dans un fichier
    Par ibtisss dans le forum Langage
    Réponses: 3
    Dernier message: 08/11/2005, 12h14
  4. Comment changer des mots dans un fichier?
    Par ptitbonum dans le forum Linux
    Réponses: 5
    Dernier message: 07/04/2004, 23h42
  5. Lire un attribut dans un fichier XML en C++
    Par ti.k-nar dans le forum XML
    Réponses: 2
    Dernier message: 14/10/2002, 15h22

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