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 :

Projet récalcitrant "recherche de mot"


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2010
    Messages
    119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2010
    Messages : 119
    Par défaut Projet récalcitrant "recherche de mot"
    Bonjour à tous,
    Je me suis replongé hier dans un vieux TP de C, et ne me suis couché qu'à 5h du matin... Confronté à un problême insoluble pour moi.
    J'ai donc à créer une commande "mgrep", qui a partir d'une suite de ligne (dans un fichier par exemple...) sur l'entrée standard, renvoie sur la sortir standard les lignes contenant le mot passé en paramêtre.
    Désolé de vous imposer tout ce code, j'ai tenté de le commenter un maximum (je ne mets pas ici les headers des fichiers (readl.c et fatal.c) :
    fatal.c : renvoie une erreur personnalisé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
    #include <stdio.h>
    #include <stdlib.h>
     
     
    /* 
    Envoie une erreur sur stderr
    si assert est different de 0
    */
    void fatal(int assert, const char* chaine, int status){
    	if(assert){
    		fprintf(stderr,"%s \n", chaine);
     
    		exit(status);
    	}
    }
    readl.c : Lit une ligne de 80 caracteres ou moins, renvoie la longueur de la chaine lue, ou "End Of File" si c'est le cas. Place la chaine dans le pointeur en parametre :
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include "fatal.h"
    #include "const.h"
     
     
    int readl(char* line){
    	int i=0;
    	char c;
    	c=fgetc(stdin);
    	while (c!=EOF && c!='\n' && i<MAXLINE){
    		if(c!='\0'){
    			line[i++]=c;
    		}
    		c=fgetc(stdin);
    	}
    	fatal((i>=MAXLINE), "ligne trop longue (plus de 80 caracteres)", 1);
    	if(c==EOF){return(EOF);}
            if(c=='\n'){line[i]='\n';}
    	return i;
    }
    mgrep.c : et enfin la fonction main elle même :
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include "readl.h"
    #include "fatal.h"
    #include "const.h"
     
    /* Affiche sur la sortie standard, les lignes
    de la chaine ou du fichier de l'entree standard
    contenant le mot passe en parametre */
     
    int main(int argc, char *argv[]){
    	int booleanMotTrouve = 0;
    	char* word;
    	char ligne[MAXLINE];
    	int index;
    	int i;
    printf("1 \n");
    	if(argc==2){			
    		word=argv[1];		
    	}
    	else{				
    		fatal(1, "liste de parametres incorrecte", 2); 
    	}
    printf("2 \n");
    	while(readl(ligne)!= EOF){	
    		for(index=0; index<(readl(ligne)); ++index){ 
    			if (ligne[index]== *word){     
    				word++;
    				if(*word=='\0'){ 
     
    					booleanMotTrouve = 1;  
    					for(i=0; i<(readl(ligne)+1); ++i){
    						putc(ligne[i], stdout); 
    					}
    				}	
    			}
    		}
    	word=argv[1]; 
    	}
    printf("3 \n");
    	return (booleanMotTrouve==1?0:1);  
     
    }
    RQE : la constante MAXLINE, est définie dans un fichier "const.h" comme valant 81.

    Le projet compile parfaitement, donc l'erreur vient clairement d'un problême de conception de ma part...
    Lorsque je lance la commande mgrep, suivi d'un mot à chercher, puis d'un fichier sur l'entree standard, il ne se passe rien, et j'obtiens un nouvel invite de commande.

    EDIT : j'ai un peu modifié mon code, et à l'éxécution d'une commande type "./mgrep la < text" avec "text" un fichier de plusiseurs lignes, dont certaines contiennent "la", j'obients :
    1
    2
    3

    Merci à tout ceux qui prendront le temps de m'aider, et merci déjà d'avoir lu tout ça!

  2. #2
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Bonjour,
    Pour commencer, ton intention est-elle de refaire ce TP avec les mêmes restrictions qu'à l'époque ?
    En particulier au niveau des fonctions de la bibliothèque standard utilisables ou pas.
    Parce que si non, il y a largement moyen d'améliorer le code...

    Quoiqu'il en soit, le problème vient de la boucle while.
    Excuse-moi de le dire comme ça, mais elle est complètement foireuse...
    As-tu une idée du nombre de lignes lues dans une seule itération ?
    Je ne serais pas étonné que dans pas mal de cas, l'entrée standard soit complètement lue dès la première itération...

    Il faut savoir que, à moins de savoir exactement ce que l'on fait, c'est une mauvaise idée d'appeler une fonction avec des effets de bord dans la condition d'une boucle.
    Dans le meilleur des cas, les conséquences sont négligeables, voire ça fait ce que l'on veut ; dans le pire des cas, cela rend le programme incohérent.

    Lorsque tu appelles readl, tu lis une ligne de l'entrée standard, et par conséquent tu déplaces le curseur interne (le fameux effet de bord) ; de plus, tu modifies de contenu des données pointées par ligne.
    Lors d'un appel suivant, l'état de l'entrée standard a changé, et tu ne peux espérer obtenir le même résultat que précédemment.

    Pour en revenir aux boucles, tu dois savoir que la condition est évaluée à chaque itération.
    Alors si tu appelles readl dans la condition, elle sera exécutée à chaque itération, et comme je le disais juste au-dessus, aura un résultat potentiellement différent.
    Autrement dit, à chaque itération, une nouvelle ligne est lue depuis l'entrée standard (et donc le curseur interne est déplacé), le contenu de la chaîne ligne est modifié, et une valeur a priori différente est retournée.
    Tu commences à voir ce qui pose problème ?

    Décortiquons un peu ton 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
    while(readl(ligne)!= EOF){  /* La première ligne de l'entrée standard est lue,
                                 * ligne contient la première ligne,
                                 * la longueur de la première ligne est retournée.
                                 */
        for(index=0; index<(readl(ligne)); ++index){  /* La deuxième ligne est lue à l'entrée dans la boucle,
                                                       * ligne contient la deuxième ligne,
                                                       * la longueur de la deuxième ligne est retournée.
                                                       * À chaque itération suivante, la ligne suivante est lue,
                                                       * ligne contient cette ligne,
                                                       * la longueur de cette ligne est retournée.
                                                       */
                (...)
                for(i=0; i<(readl(ligne)); ++i){  /* À l'entrée dans la boucle, et pour chaque itération, la ligne suivant la ligne courante est lue,
                                                   * ligne contient cette ligne,
                                                   * la longueur de cette ligne est retournée.
                                                   */
                    (...)
                }
            }
        }
    Toi qui t'attends à obtenir la même valeur pour toutes les itérations des boucles for...

    Il faut que tu t'assures de ne lire qu'une seule ligne par itération de la boucle [codeninline]while[/codeinline].
    Autrement dit, il faut que la fonction readl ne soit appelée qu'une fois par itération.
    Et pour cela, tu n'as pas le choix : utilise des variables auxiliaires (ligne en est déjà une ).


    Une fois que tu auras résolu ce problème, tu te heurteras à un autre.
    Hé oui, désolé...
    Ta façon de détecter qu'un mot est bien présent dans une ligne n'est pas bonne.
    En réalité, tu testes si tous les caractères du mot recherché apparaissent dans la ligne courante, et dans le même ordre.
    Par exemple, ton programme (corrigé) trouverait que le mot « toto » apparaît dans la ligne suivante :
    Nous allons tous ensemble fêter Noël !
    Bon courage.

  3. #3
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Citation Envoyé par Alba.1337 Voir le message
    EDIT : j'ai un peu modifié mon code, et à l'éxécution d'une commande type "./mgrep la < text" avec "text" un fichier de plusiseurs lignes, dont certaines contiennent "la", j'obients :
    1
    2
    3
    C'est exactement ce que je disais...
    Citation Envoyé par Steph_ng8 Voir le message
    Je ne serais pas étonné que dans pas mal de cas, l'entrée standard soit complètement lue dès la première itération...

  4. #4
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2010
    Messages
    119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2010
    Messages : 119
    Par défaut
    Bon sang mais c'est bien sur!
    Merci beaucoup... J'y retourne (pis merci de ne pas m'avoir filé une réponse toute faire, je fais ça pour réviser, et je suis du genre feignasse...).
    Je posterai le résultat ici si ça marche, voir si je peux optimiser.

  5. #5
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Citation Envoyé par Alba.1337 Voir le message
    (pis merci de ne pas m'avoir filé une réponse toute faire, je fais ça pour réviser, et je suis du genre feignasse...)
    À ton service.
    Et puis, ce n'est pas la philosophie de la maison...

  6. #6
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2010
    Messages
    119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2010
    Messages : 119
    Par défaut
    OUF! Merci, j'arrive enfin à un résultat qui commence à devenir intéressant...
    Voilà mes fichier .c à l'heure actuelle :
    readl.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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <stdio.h>
    #include <stdlib.h>
    #include "fatal.h"
    #include "const.h"
     
     
     
     
    /*
    Lit une ligne et une seule sur l'entrée standard;
    retourne EOF, si la fin du fichier est atteinte,
    sinon, retourne le nombre de caracteres lus.
    Quitte sur une erreur si la chaine fait plus de 80 caracteres.
     
    Stocke dans "line" la ligne lue.
    */
    int readl(char* line){
        int i=0;
        char c;
        c=fgetc(stdin);
    /*printf("-r- %c\n", c);*/
        while (c!=EOF && c!='\n' && c!='\0' && i<MAXLINE){
            line[i++]=c;
            c=fgetc(stdin);
    /*printf("-r- %c\n", c);*/
        }
        fatal((i>=MAXLINE), "ligne trop longue (plus de 80 caracteres)", 1);
        if(c==EOF){return(EOF);}
        if(c=='\n'){line[i]='\n';}
        if(c=='\0'){line[i]='\0';}
     
        return i;
    }
    mgrep.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
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include "readl.h"
    #include "fatal.h"
    #include "const.h"
     
    /* Affiche sur la sortie standard, les lignes
    de la chaine ou du fichier de l'entree standard
    contenant le mot passe en parametre */
     
    int main(int argc, char *argv[]){
        int booleanMotTrouve = 0;
        char* word;
        char ligne[MAXLINE];
        int index;
        int i;
        if(argc==2){
            word=argv[1];
        }
        else{
            fatal(1, "liste de parametres incorrecte", 2);
        }
        i = (readl(ligne));
        while(i!= EOF){
            for(index=0; index<=i; ++index){
                if (ligne[index]== *word){
                    word++;
                    if(*word=='\0'){
     
                        booleanMotTrouve = 1;
                        printf("%s", ligne);
                    }
                }
                else {
                    word=argv[1];
                }
            }
        i=(readl(ligne));
        }
        return (booleanMotTrouve==1?0:1);
     
    }
    Bon comme je disais j'ai un résultat "intéressant", donc y'a encore un truc qui doit merdouiller...

    Quand j'appelle "./mgrep la < text > res", les fichiers sont :
    text :
    la neige est belle
    il fait beau
    il pleut
    il fait de la pelle
    il nage
    la peche c'est bien
    l'avion vole
    il fait du velo
    j'ai de la moustache
    RQE : Ca a été fait a 4h du mat' hein...

    res :
    la neige est belle
    r·il fait de la pelle
    ·la peche c'est bien
    ·j'ai de la moustache
    Et voilà!
    Si vous avez une idée de ce qui peut déconner...
    Merci en tout cas de votre aide!

Discussions similaires

  1. Rechercher enregistrement avec ' (quote)
    Par jpo dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 02/08/2007, 17h54

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