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 :

[Débutant] Chaînes de caractères structurées en listes


Sujet :

C

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut [Débutant] Chaînes de caractères structurées en listes
    Bonsoir,
    Je travaille en ce moment sur un sujet qui traite d'une implémentation assez spéciale des chaînes de caractères en liste chaînée (appelée lstring). Une chaîne structurée en liste est en fait une liste chaînée de tableaux de caractères terminés par '\0'. On alloue les tableaux dynamiquement pour contenir exactement exactement le nombre de caractères nécessaires. On représente une chaîne vide par une liste vide et non par un élément qui contiendrait un tableau représentant la chaîne vide "".
    Il est demandé d'implémenter des procédures d'initialisation, affichage, destruction, obtention de la taille, ajout d'une chaîne de caractères classique à la fin d'une lstring, obtention d'un caractère à partir de son indice, recherche d'un motif de caractères....
    J'ai pour ma part des soucis avec l'ajout d'une string et l'obtention de la taille d'une lstring.
    Ci-dessous mon fichier d'en-tête:
    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
    #ifndef LSTRING__H
    #define LSTRING__H
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    typedef struct Cellule{
        char *chaine;
        struct Cellule *suivante;
    } Cellule;
     
    typedef Cellule *lstring;
     
    bool initialiser(lstring *lstr, const char src[]);
    /* Initialiser une lstring à partir d'une chaine ou d'un pointeur NULL */
     
    bool est_vide(lstring lstr);
    /* Tester si une lstring est vide */
     
    void afficher(lstring lstr);
    /* Afficher une lstring (avec un retour à la ligne à la fin) */
     
    void detruire(lstring *lstr);
    /* Detruire une lstring */
     
    size_t taille(lstring lstr);
    /* Obtenir la taille d'une lstring */
     
    bool ajouter(lstring *lstr, const char src[]);
    /* Ajouter une chaîne de caractères classique à la fin d'une lstring */
     
    char obtenir(lstring lstr, size_t indice);
    /*  Obtenir un caractère dans une lstring à partir de son indice */
     
    bool motif(lstring lstr, const char s[]);
    /* Chercher si un motif est présent dans une lstring */
     
    bool supprimer(lstring *lstr, size_t inf, size_t max);
    /* Supprimer une sous-partie d'une lstring comprise entre deux indices */
     
    #endif
    Ma procédure d'initialisation:
    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
    bool initialiser(lstring *lstr, const char src[]){
        if (src==NULL || strcmp(src,"")==0){
    	*lstr=NULL;
    	return true;
        } else{
    	(*lstr)=malloc(sizeof(**lstr));
    	if (*lstr){
    	    (*lstr)->chaine=malloc((strlen(src)+1)*sizeof(char));
    	    if ((*lstr)->chaine){
    		strcpy((*lstr)->chaine, src);
    		return true;
    	    } else{
    		free(*lstr);
    		(*lstr)=NULL;
    		fprintf(stderr, "Mémoire insuffisante\n");
    		return false;
    	    }
    	}else{
    	    fprintf(stderr, "Mémoire insuffisante\n");
    	    return false;
    	}
        }
    }
    Ma procédure taille:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    size_t taille(lstring lstr){
        size_t resultat=0;
        Cellule *curseur=lstr;
        while (curseur!=NULL){
    	resultat+= strlen(curseur->chaine);
    	curseur=curseur->suivante;
        }
        return resultat;
    }
    La procédure qui permet d'obtenir un caractère suivant son indice dans la lstring:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    char obtenir(lstring lstr, size_t indice){
        /* A optimiser */
        //assert(indice<taille(lstr));
        Cellule *curseur=lstr;
        size_t taille_cumule=strlen(curseur->chaine);
        while (curseur!=NULL && indice>=taille_cumule){
    	curseur=curseur->suivante;
    	taille_cumule+=strlen(curseur->chaine);
        }
        return curseur->chaine[strlen(curseur->chaine)-(taille_cumule-indice)];
    }
    Et ma procédure d'ajout qui pose à priori des soucis dans mon 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
    bool ajouter(lstring *lstr, const char src[]){
        if (src!=NULL || strcmp(src,"")==0)
    	/* Si la liste est vide, on ne fait rien! */
    	return true;
        else{
    	Cellule *curseur=*lstr;
    	while(curseur->suivante!=NULL){
    	    curseur=curseur->suivante;
    	}
    	Cellule *nouvelle=malloc(sizeof(*nouvelle));
    	if (nouvelle){
    	    nouvelle->chaine=malloc(sizeof(char)*strlen(src));
    	    if (nouvelle->chaine){
    		strcpy(nouvelle->chaine,src);
    		nouvelle->suivante=NULL;
    		curseur->suivante=nouvelle;
    		return true;
    	    }else{
    		fprintf(stderr,"Mémoire insuffisante\n");
    		return false;
    	    }
    	}else{
    	    fprintf(stderr,"Mémoire insuffisante\n");
    	    return false;
    	}
        }
    }
    Pour résumer cette dernière procédure. Si la liste n'est pas vide (autrement on ne fait rien), je déclare un pointeur sur cellule (curseur) qui me permettra de parcourir la liste jusqu'à la dernière cellule, arrivée à celle-ci, j'alloue une nouvelle cellule pointée par "nouvelle" où je copie la chaîne à ajouter. Je relie finalement cette nouvelle cellule à la précédente, pointée par curseur, et je boucle la liste par NULL.
    Là où ça marche pas c'est dans mes tests. Je déclare une lstring avec un seul élément "abc", je rajoute une autre chaîne "defg" en utilisant ma procédure ajouter mais la taille renvoyé avec la procédure correspondante est toujours égale à 3 (p-e le problème vient-il de ce SP!).
    Egalement, quand j'essaie d'obtenir le caractère d'indice 3 (i.e: 'd') j'ai une segmentation fault.
    Au final, le problème peut venir de n'importe où.

    Merci d'éclairer ma lanterne.
    Cordialement,

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 26
    Points : 30
    Points
    30
    Par défaut
    Je viens de tester ton code

    Dans Ajouter ce n'est pas src!NULL mais src==NULL

    De plus c'est la liste que tu veux savoir si elle est vide donc il faudrait corriger en *lstr==NULL, ca irait aussi

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Citation Envoyé par plumedesiles Voir le message
    Je viens de tester ton code

    Dans Ajouter ce n'est pas src!NULL mais src==NULL

    De plus c'est la liste que tu veux savoir si elle est vide donc il faudrait corriger en *lstr==NULL, ca irait aussi
    - Merci c'était bien src==NULL.
    - Non c'est bien src que je veux tester, si elle est vide, pas la peine de créer une nouvelle cellule, on ne fait rien.

    En modifiant l'erreur, la taille est toujours égale à 3 après rajout de la chaîne "defg". Cependant, j'ai constaté une erreur que je n'avais pas encore remarqué: la commande "putchar(obtenir(s,2));" provoque une erreur de segmentation, alors que le caractère d'indice 2 est censé être 'c'. Donc la procédure "obtenir" couak aussi. Décidemment...

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 26
    Points : 30
    Points
    30
    Par défaut
    Normal il faut que tu inverses les deux lignes dans le while car tu peux te ramasser un pointeur NULL sans l'avoir tester

  5. #5
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    - Dans la fonction initialiser() :
    le champ suivante n'est pas initialisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ....
    if ((*lstr)->chaine)
    {
      strcpy((*lstr)->chaine, src);
      (*lstr)->suivante  = NULL ; //<-------
      return true;
    }
    ....
    - Dans les fonctions taille(), obtenir() et ajouter(), une écriture dangereuse qui pourra conduire à des problèmes plus tard :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    size_t taille(lstring lstr)
    {
    ...
        Cellule *curseur=lstr;
    lstr, du type lstring, est converti en cellule *. C'est vrai pour le moment puisque lstring est bien le type Cellule *. Mais si on a défini un type lstring, c'est bien pour différencier les deux types. D'ailleurs, on peut trouver avantageux de modifier ultérieurement le type lstring par exemple pour lui ajouter un pointeur sur la dernière cellule ce qui facilitera les concaténations, ou modifier le type Cellule pour lui ajouter la longueur de la chaine stockée ce qui évitera les strlen() à répétition qui vont pénaliser grandement les performances.

    -Dans ajouter(), outre le src==NULL déjà signalé, la quantité allouée est incorrecte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nouvelle->chaine=malloc(strlen(src)+1);
    Pouquoi si la liste est vide, ne fait-on rien ? On devrait mettre la chaine dans la liste !
    Je pense qu'il y a une ambiguïté sur les rôles de initialiser() et ajouter() puisque initialiser() ajoute une chaine (à une liste vide) lorsque ajouter() est incapable de le faire dans ce cas.
    ajouter() devrait être capable de placer une chaine dans une liste vide. Alors, initialiser() doit créer une nouvelle liste vide, c'est son rôle essentiel, et si on spécifie une chaine pour initialiser la liste alors la fonction initialiser() appelle ajouter() pour faire l'opération.

    - Pour la fonction obtenir(), aucune vérification n'est faite pour s'assurer que l'indice est dans une plage correcte. Réfléchir à ce problème.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Citation Envoyé par diogene Voir le message
    - Dans la fonction initialiser() :
    le champ suivante n'est pas initialisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ....
    if ((*lstr)->chaine)
    {
      strcpy((*lstr)->chaine, src);
      (*lstr)->suivante  = NULL ; //<-------
      return true;
    }
    ....
    C'est corrigé.

    - Dans les fonctions taille(), obtenir() et ajouter(), une écriture dangereuse qui pourra conduire à des problèmes plus tard :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    size_t taille(lstring lstr)
    {
    ...
        Cellule *curseur=lstr;
    lstr, du type lstring, est converti en cellule *. C'est vrai pour le moment puisque lstring est bien le type Cellule *. Mais si on a défini un type lstring, c'est bien pour différencier les deux types. D'ailleurs, on peut trouver avantageux de modifier ultérieurement le type lstring par exemple pour lui ajouter un pointeur sur la dernière cellule ce qui facilitera les concaténations, ou modifier le type Cellule pour lui ajouter la longueur de la chaine stockée ce qui évitera les strlen() à répétition qui vont pénaliser grandement les performances.
    Ça rejoint ce que mon prof nous a raconté en cours. Instinctivement, l'utilité du curseur n'était pour moi que de pointer vers une cellule. Cependant, dans le sujet le type lstring n'est pas modifié plus tard, mais cela reste toutefois plus robuste de différencier une lstring d'un pointeur vers cellule.

    -Dans ajouter(), outre le src==NULL déjà signalé, la quantité allouée est incorrecte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nouvelle->chaine=malloc(strlen(src)+1);
    Corrigé.

    Pouquoi si la liste est vide, ne fait-on rien ? On devrait mettre la chaine dans la liste !
    Faute de frappe: "Si la chaîne est vide, on ne fait rien". Pas la peine d'allouer une nouvelle cellule.

    Je pense qu'il y a une ambiguïté sur les rôles de initialiser() et ajouter() puisque initialiser() ajoute une chaine (à une liste vide) lorsque ajouter() est incapable de le faire dans ce cas.
    ajouter() devrait être capable de placer une chaine dans une liste vide. Alors, initialiser() doit créer une nouvelle liste vide, c'est son rôle essentiel, et si on spécifie une chaine pour initialiser la liste alors la fonction initialiser() appelle ajouter() pour faire l'opération.
    Initialiser ne doit pas pouvoir créer une nouvelle liste, mais placer une chaîne dans une liste à peine déclarée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     lstring s;
    /* Tests basiques */
    initialiser(&s, "abc");
    assert(!est_vide(s));
    assert(taille(s)==3);
    Ajouter rajoute une chaîne à une liste déjà définie (lstr==NULL étant une définition comme les autres).

    - Pour la fonction obtenir(), aucune vérification n'est faite pour s'assurer que l'indice est dans une plage correcte. Réfléchir à ce problème.
    J'ai rajouté un assert(indice<taille(lstr)) en début de fonction.

    -------
    J'ai modifié ma fonction obtenir en mettant un do-while au lieu d'un while.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char obtenir(lstring lstr, size_t indice){
        /* A optimiser */
        assert(indice<taille(lstr));
        assert(!est_vide(lstr));
        lstring curseur=lstr;
        lstring buffer;
        size_t taille_cumule=0;
        do{
    	taille_cumule+=strlen(curseur->chaine);
            buffer=curseur;
    	curseur=curseur->suivante;
        }while (curseur!=NULL && indice>=taille_cumule);
        return buffer->chaine[strlen(buffer->chaine)-(taille_cumule-indice)];
    }
    C'est peut-être un peu redondant, mais ça marche. J'ai passé un bon quart d'heure à faire des schémas de structure sur papier ainsi que l'évolution de la pile mémoire pour me rendre à l'évidence que le problème ne vient pas de là.
    Là avec mes assert, après avoir ajouté la chaîne "defg", il n'essaie même pas d'obtenir le caractère 'd' puisque la taille reste égale à 3 et l'assert l'en n'empêche donc.
    Je rappelle que les appels obtenir(s,'0'), obtenir(s,'1') et obtenir(s,'2') renvoient bien 'a', 'b' et 'c'. Ma chaîne initiale étant "abc".

    Idem pour la fonction ajouter, l'analyse sur papier n'a révélé à priori aucun soucis dans 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
    bool ajouter(lstring *lstr, const char src[]){
        if (src==NULL || strcmp(src,"")==0)
    	/* Si la chaîne est vide, on ne fait rien! */
    	return true;
        else{
    	lstring curseur=*lstr;
    	while(curseur->suivante!=NULL){
    	    curseur=curseur->suivante;
    	}
    	Cellule* nouvelle=malloc(sizeof(*nouvelle));
    	if (nouvelle){
    	    nouvelle->chaine=malloc(sizeof(char)*(strlen(src)+1));
    	    if (nouvelle->chaine){
    		strcpy(nouvelle->chaine,src);
    		nouvelle->suivante=NULL;
    		curseur->suivante=nouvelle;
    		return true;
    	    }else{
    		fprintf(stderr,"Mémoire insuffisante\n");
    		return false;
    	    }
    	}else{
    	    fprintf(stderr,"Mémoire insuffisante\n");
    	    return false;
    	}
        }
    }
    Idem en fin pour la fonction taille:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    size_t taille(lstring lstr){
        size_t resultat=0;
        lstring curseur=lstr;
        while (curseur!=NULL){
    	resultat+= strlen(curseur->chaine);
    	curseur=curseur->suivante;
        }
        return resultat;
    }
    Retour au point de départ donc (ou presque). La source du problème peut-être n'importe où. J'ai tout passé au peigne fin et ça m'énerve.

    Cordialement.

  7. #7
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Initialiser ne doit pas pouvoir créer une nouvelle liste, mais placer une chaîne dans une liste à peine déclarée.
    Je maintiens qu'ajouter() doit pouvoir le faire. Sinon, l'utilisateur doit savoir si la liste est vide ou non pour choisir d'utiliser initialiser() ou ajouter(). C'est extrèmement mal commode de devoir tester son état avant d'appeler la bonne fonction. En plus c'est injustifié, cela aboutit à dupliquer du code dans les deux fonctions (avec en plus un oubli)! :

    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
    	(*lstr)=malloc(sizeof(**lstr));
    	if (*lstr){
    	    (*lstr)->chaine=malloc((strlen(src)+1)*sizeof(char));
    	    if ((*lstr)->chaine){
    		strcpy((*lstr)->chaine, src);
                   (*lstr)->suivante  = NULL ;
    	    } else{
    		free(*lstr);
    		(*lstr)=NULL;
    		fprintf(stderr, "Mémoire insuffisante\n");
    		return false;
    	    }
    	}else{
    	    fprintf(stderr, "Mémoire insuffisante\n");
    	    return false;
    	}
    //---------------------------------------------------------
    	Cellule *nouvelle=malloc(sizeof(*nouvelle));
    	if (nouvelle){
    	    nouvelle->chaine=malloc(sizeof(char)*strlen(src));
    	    if (nouvelle->chaine){
    		strcpy(nouvelle->chaine,src);
    		nouvelle->suivante=NULL;
    ....
    	    }else{ //// <-------et il manque ici la récupération de nouvelle 
    		fprintf(stderr,"Mémoire insuffisante\n");
    		return false;
    	    }
    	}else{
    	    fprintf(stderr,"Mémoire insuffisante\n");
    	    return false;
    	}
        }
    Le seul rôle que peut avoir initialiser() est justement de créer une nouvelle liste (éventuellement initialisée par une chaine). Si lstring devait être plus complexe qu'actuellement, ce serait utile pour initialiser correctement ses champs.

    Après les corrections signalées, je ne constate pas de problèmes sur ce petit test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main(void)
    {
     lstring string;
     char a ;
     int len;
     initialiser(&string,"abcd");
     len = taille(string);        // résultat 4
     a = obtenir(string,2);       // résultat 'c'
     ajouter (&string,"123456");
     len = taille(string);        //résultat 10
     a = obtenir(string,7);       //résultat '4'
     return 0;
    }
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Mea culpa. Vous avez raison, ça marche.
    C'est mon test d'ajout qui était faux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert(ajouter(s,"defg"));
    Il manquait le '&'..

    Je suis spécialiste de ces erreurs là. Une fois j'avais passé toute une nuit à débugger un programme car j'avais tapé 'o' au lieu de '0'.

    Merci encore pour votre patience.
    Je peux donc maintenant m'attaquer aux deux procédures qui restent:
    - Chercher si un motif (passé comme une chaîne classique) est présent dans une lstring.
    - Supprimer une sous-partie d'une lstring comprise entre deux indices.

  9. #9
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Mea culpa. Vous avez raison, ça marche.
    C'est mon test d'ajout qui était faux:

    Code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert(ajouter(s,"defg"));Il manquait le '&'..
    Normalement, si le niveau des warning du compilateur était bien règlé, il aurait dû signaler cette anomalie (dans le genre "pointeurs incompatibles")
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Je relance le sujet car je bloque sur l'implémentation de la fonction de recherche d'un motif donné (sous forme de chaîne de caractères classique) dans une lstring.
    Voici la spécification que j'ai retenu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bool motif(lstring lstr, const char s[]);
    /* Chercher si un motif est présent dans une lstring */
    Pour le code, je ne connais pas très bien les fonctions de la bibliothèque <string.h>, mais en cherchant un peu j'en ai trouvé une qui pourrait m'être utile. Il s'agit de la fonction strspn() qui détermine la taille de la sous-chaine maximale de s ne contenant que des caractères présents dans la chaîne d'entrée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t strspn(const char *s, const char *accept);
    Après je ne crois pas avoir le droit de l'utiliser (en supposant qu'elle me soit utile) vu que les fonctions autorisées dans le sujet sont strcmp(), strncmp(), strlen(), strcpy() et strncpy().

    J'avais pensé à utiliser strcmp() et strncmp() mais j'ai quelques lacunes dans la comparaison de chaînes de caractères. L'entier renvoyé, est-ce la différence de la somme des codes ASCII des deux chaînes?

    Système D. Il me resterait la boucle de comparaison caractère à caractère mais j'avoue que ça me tente pas trop.

    En vous remerciant.

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 26
    Points : 30
    Points
    30
    Par défaut
    Le man dit ca

    The strcmp() function compares the two strings s1 and s2. It returns an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2.

    Si j'ai bien compris ton problème tu sois identifier une chaine de caractère dans un maillon de ta lstring exact ?

    Il te suffit donc de parcourir chaque maillon de ta lstring. Comparer avec strcmp si la chaine du maillon courant contient cette chaine.

    if strcmp("ab",maillon->chaine) >= 0) printf("chaine trouvée\n");

    Si tu dois trouver cette chaine dans la lstring complète, il faudrait peut-etre faire un strcat du maillon précédent et maillon courant pour savoir si la chaine recherchée ne se trouve pas entre les deux.

    La réponse a ton problème est elle correcte ?

  12. #12
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Citation Envoyé par plumedesiles Voir le message
    Le man dit ca

    The strcmp() function compares the two strings s1 and s2. It returns an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2.

    Si j'ai bien compris ton problème tu sois identifier une chaine de caractère dans un maillon de ta lstring exact ?

    Il te suffit donc de parcourir chaque maillon de ta lstring. Comparer avec strcmp si la chaine du maillon courant contient cette chaine.

    if strcmp("ab",maillon->chaine) >= 0) printf("chaine trouvée\n");

    Si tu dois trouver cette chaine dans la lstring complète, il faudrait peut-etre faire un strcat du maillon précédent et maillon courant pour savoir si la chaine recherchée ne se trouve pas entre les deux.

    La réponse a ton problème est elle correcte ?
    Effectivement la chaîne peut se trouver dans la lstring complète (entre deux cellules).
    Je ne comprends toujours pas ce que signifie s1 less or greather than s2. Comment est faite la comparaison? J'ai essayé de regarder le code source de strcmp() sans comprendre grand chose.

    Merci.

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 26
    Points : 30
    Points
    30
    Par défaut
    Citation Envoyé par scarabee10 Voir le message
    Effectivement la chaîne peut se trouver dans la lstring complète (entre deux cellules).
    Je ne comprends toujours pas ce que signifie s1 less or greather than s2. Comment est faite la comparaison? J'ai essayé de regarder le code source de strcmp() sans comprendre grand chose.

    Merci.
    Le man est plus utile que le code source ou faire une recherche google pour exemple. Bref

    Si s1 est trouvé dans s2, cela te renverra une valeur supérieur ou égale à zéro. Je crois ne pas avoir dis de bétise là

    Tu peux tester avec un exemple de wikipedia http://en.wikipedia.org/wiki/Strcmp

  14. #14
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 44
    Points : 25
    Points
    25
    Par défaut
    Citation Envoyé par plumedesiles Voir le message
    Le man est plus utile que le code source ou faire une recherche google pour exemple. Bref

    Si s1 est trouvé dans s2, cela te renverra une valeur supérieur ou égale à zéro. Je crois ne pas avoir dis de bétise là

    Tu peux tester avec un exemple de wikipedia http://en.wikipedia.org/wiki/Strcmp
    Après consultation de la doc, et test avec le petit programme sur wikipédia. Il s'avère que ce n'est absolument pas ça.
    strcmp() compare suivant l'ordre lexicographique.

    Ordre lexicographique sur un produit cartésien
    Les ensembles (A, ≤) et (B, ≤) sont tous deux ordonnés, l'ordre étant noté de la même façon pour les deux ensembles, une liberté qui ne devrait troubler personne. L'ordre lexicographique sur A × B, que l'on note encore ≤, est défini de la façon suivante, pour (a,b) et (a’,b’) deux couples de A × B :
    (a,b) ≤ (a’,b’) si et seulement si [a < a’ ou (a = a’ et b ≤ b’)]
    et on en déduit facilement la propriété analogue pour l'ordre lexicographique strict :
    (a,b) < (a’,b’) si et seulement si [a < a’ ou (a = a’ et b < b’)].
    Il s'agit bien de l'ordre du dictionnaire, par exemple :
    lu < ne car l < n (on ne regarde que la première lettre)
    le < lu car e < u (les premières lettres sont identiques, on regarde la seconde).
    Le choix de la première composante pour commencer la comparaison est purement arbitraire, mais, comme illustré par l'exemple alphabétique qui précède, si l'on commence la comparaison par la seconde composante, on obtient un ordre différent.
    Il n'y a donc aucune corrélation entre le fait qu'une chaîne soit incluse dans une autre et la valeur renvoyée par strcmp().
    Preuve:
    strcmp("xyz","axyz") renvoie un entier positif (car x>a)
    strcmp("abc","xabc") renvoie un entier négatif (car a<x)

    Cordialement,

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2010
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 26
    Points : 30
    Points
    30
    Par défaut
    La solution la plus simple est d'utiliser strstr(s1,s2) qui cherche s2 dans s1.
    Si s2 est trouvé alors la fonction renvoie un pointeur sur le début de la chaine, sinon elle renvoie NULL

    Un exemple

    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
     
     
    int main(int argc, char* argv[])
    {
     
           char *v=NULL;
     
     
           v = strstr (argv[1], argv[2]);
     
    	 if (v ==NULL)
            printf ("'%s' Non trouve '%s'.\n", argv[1], argv[2]);
     
    	if (v !=NULL)
            printf ("'%s' trouve '%s'  %s.\n", argv[1], argv[2], v); 
     
    return 0;
     
    }
    Sinon avec strncmp()
    Attention s2 doit toujours être plus petite que s1 !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    while( i< (strlen(argv[1])-strlen(argv[2])+1) && v!=0)
    {
    	v=strncmp(&argv[1][i],argv[2],strlen(argv[2]));
     
    	i++;
     
    }
    C'est en gros ce que fait strstr. Tu compares le début de la chaine avec ton motif.
    Si cela ne correspond pas, tu compares à partir du second caractère de la chaine avec ton motif etc... jusqu'à que tu trouves.

  16. #16
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Système D. Il me resterait la boucle de comparaison caractère à caractère mais j'avoue que ça me tente pas trop.
    Je crains que tu ne sois contraint de te faire violence. Comme la chaine peut être distribuée sur plusieurs cellules, je ne vois pas de fonction standard qui puisse être commodément utilisée.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/04/2010, 19h59
  2. Réponses: 3
    Dernier message: 13/05/2008, 13h11
  3. [Débutant] Chaîne de caractères en tableau
    Par heycjuju dans le forum LabVIEW
    Réponses: 1
    Dernier message: 17/12/2007, 09h44
  4. Chercher une chaîne de caractères dans une liste
    Par baedal dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 28/05/2007, 23h42
  5. [Débutant] Chaîne de caractère
    Par Anonn dans le forum C++
    Réponses: 6
    Dernier message: 14/03/2006, 18h08

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