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 :

Modification d'une chaine de caracteres (char *) dans un fonction


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    7
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2010
    Messages : 7
    Points : 12
    Points
    12
    Par défaut Modification d'une chaine de caracteres (char *) dans un fonction
    Bonsoir,

    Je dois développer un petit bout de code permettant de gérer des éléments dans une table de hachage. Ces éléments seront des structures composées d'une chaîne de caractères (char *) et d'un entier.

    Il m'est imposé de ne pas utiliser le char * directement mais de passer par le typedef suivant :

    Cela afin de pouvoir changer de type utilisé de manière aisée.

    J'ai donc développé le code suivant :

    clef.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef CLE_H
    #define CLE_H
     
    #include <string.h>
    #include <stdlib.h>
     
    typedef char * Clef;
     
    void initialisationClef( Clef * pLaClef );
    int copieClef( Clef * pClefDest, Clef * pClefSource );
    int testamentClef( Clef * pLaClef );
     
    #endif
    clef.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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    #include "clef.h"
     
    void initialisationClef( Clef * pLaClef )
    {
        // met le pointeur a NULL
        *pLaClef = NULL;
    }
     
    int copieClef( Clef * pClefDest, Clef * pClefSource )
    {
        int iErreur = -1;
     
        // si le pointeur est a NULL
        if( *pClefDest == NULL )
        {
            // alloue la memoire pour la chaine de caractere
            *pClefDest = malloc( ( strlen( pClefSource ) * sizeof (char) ) + 1 );
     
            // copie la chaine de caractere
            strcpy( pClefDest, pClefSource );
     
            // aucune erreur
            iErreur = 0;
        }
        else
        {
            // erreur : essaie de copier une chaine de caractere sur un pointeur non nulle
            iErreur = 1;
        }
     
        // retourne le code d'erreur
        return iErreur;
    }
     
    int testamentClef( Clef * pLaClef )
    {
        int iErreur = -1;
     
        // si le pointeur n'est pas a null
        if( *pLaClef != NULL )
        {
            // libere la memoire
            free( *pLaClef );
     
            // met le pointeur a NULL
            *pLaClef = NULL;
     
            iErreur = 0;
        }
        else
        {
            // Erreur : essaie de desallouer un pointeur nulle
            iErreur = 2;
        }
     
        // retourne le code d'erreur
        return iErreur;
    }
    main.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
     
    #include "clef.h"
    #include "stdio.h"
     
    int main()
    {
        char toto[5] = "toto";
        printf( "toto='%s'\n", toto );
     
        Clef clefCopieToto;
     
        printf( "toto='%s', clefCopieToto='%s'\n", toto, clefCopieToto );
     
        initialisationClef( &clefCopieToto );
        printf( "init. clef OK\n" );
     
        printf( "toto='%s', clefCopieToto='%s'\n", toto, clefCopieToto );
     
        copieClef( &clefCopieToto, (Clef *) toto );
        printf( "copie clef OK\n" );
     
        printf( "toto='%s', clefCopieToto='%s'\n", toto, clefCopieToto );
     
        testamentClef( &clefCopieToto );
        printf( "testament clef OK\n" );
     
        return 0;
    }
    Le seul soucis est que si je passe en paramètre directement le type clef (char*), mes modifications ne sont appliquées que dans la fonction et dès que je retourne dans le main les modification ont disparu.

    J'ai donc décider de passer un pointeur sur clef (char **) afin que les modifications ne soient pas apportées sur une copie de la clef.

    Le soucis est qu'il doit y avoir un concept qui m'échappe (cela fait un moment que je n'ai pas fait de C ) car ce bout de code n'est pas fonctionnelle. En effet j'obtiens une runtime error à la ligne (après la copie) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf( "toto='%s', clefCopieToto='%s'\n", toto, clefCopieToto );
    J'imagine que mon malloc ou mon strcpy est flingué à cause de mon obligation de caster Clef* en char* ou autre.

    Est-ce que quelqu'un aurait une idée sur la question ?

    Merci d'avance,

    BenJ

    PS : je développe sous Ubuntu 10.4 avec CodeBloc et gcc.

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 720
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 720
    Points : 31 043
    Points
    31 043
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par benbarate Voir le message
    Bonsoir,

    Je dois développer un petit bout de code permettant de gérer des éléments dans une table de hachage. Ces éléments seront des structures composées d'une chaîne de caractères (char *) et d'un entier.

    Il m'est imposé de ne pas utiliser le char * directement mais de passer par le typedef suivant :

    Salut

    C'est bien de définir un type commun permettant de centraliser les changements futurs mais dans ton cas, je vois mal une clef devenir autre chose qu'une chaine de caractères.

    Par ailleurs c'est une super mauvaise idée de masquer une étoile dans un type. Ca obscurcis le code. Ensuite, tu sais plus si tu gères un pointeur ou un pointé. L'étoile a un sens. Faut pas en avoir peur et savoir la manipuler franchement...

    Citation Envoyé par benbarate Voir le message
    Le seul soucis est que si je passe en paramètre directement le type clef (char*), mes modifications ne sont appliquées que dans la fonction et dès que je retourne dans le main les modification ont disparu.

    J'ai donc décider de passer un pointeur sur clef (char **) afin que les modifications ne soient pas apportées sur une copie de la clef.
    Exact. C'est une des bases du C: les paramètres sont passés par copie. Si tu veux modifier une variable dans une fonction, il faut alors passer l'adresse de la variable à la fonction pour que la fonction sache où taper dans la mémoire.

    Et donc si tu veux modifier un pointeur type char*, il faut que effectivement que ta fonction reçoive l'adresse du pointeur qu'elle stockera dans un char ** !!!

    Citation Envoyé par benbarate Voir le message
    Le soucis est qu'il doit y avoir un concept qui m'échappe (cela fait un moment que je n'ai pas fait de C ) car ce bout de code n'est pas fonctionnelle. En effet j'obtiens une runtime error à la ligne (après la copie) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf( "toto='%s', clefCopieToto='%s'\n", toto, clefCopieToto );
    J'imagine que mon malloc ou mon strcpy est flingué à cause de mon obligation de caster Clef* en char* ou autre.
    Non. Dans ta fonction "copieClef", ton malloc te renvoie une adresse que tu stockes dans la copie du pointeur et non dans le pointeur lui-même. Ton pointeur reste non alloué et tu perds en plus l'adresse de la zone allouée en fin de fonction (fuite mémoire)...

    A la limite, si vraiment tu veux définir un type "clef" bien à toi, et pour éviter les problèmes de char **, alors tu crées une structure qui contient la clef style
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {
        char *string;
    } t_clef;

    Ensuite tu définis une variable de type "t_clef"

    Puis tu passes l'adresse de ta variable à tes fonctions. Les fonctions recevant l'adresse sauront où est la variable et pourront taper dans string sans soucis

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int copieClef(..., t_clef *clef)
    {
        ...
        clef->string=malloc(...);
    }
     
    int main()
    {
        t_clef maClef;
        ...
        copieClef(..., &maClef);
    }

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    7
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2010
    Messages : 7
    Points : 12
    Points
    12
    Par défaut
    Merci pour ton aide. Ton message m'a permis d'ouvrir les yeux et donc de modifier mon strcpy de la manière suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // copie la chaine de caractere
            strcpy( *pClefDest, pClefSource );
    En effet cela ne pouvait pas marcher car j'oubliai de dé-référencer pClefDest.

    Je suis tout a fait d'accord avec toi pour l'histoire du masquage du char* avec un typedef mais malheureusement je n'ai pas le choix .

    Il y a juste une petite question qui me tourmente. La fonction strcpy a la signature suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char * strcpy ( char * destination, const char * source );
    Comment le char * destination peut être modifié alors qu'elle n'attend pas un char **? J'ai l'impression qu'une finesse du concept m'échappe encore !

    En tout cas un grand Merci,

    Benjamin

  4. #4
    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
    Comment le char * destination peut être modifié alors qu'elle n'attend pas un char **?
    Ce qu'on passe en argument destination est l'adresse de destination. La fonction ne cherche pas à modifier cet argument, mais à modifier le tableau qui commence à cette adresse passée en argument (donc *destination, *(destination+1),...)

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 720
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 720
    Points : 31 043
    Points
    31 043
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par benbarate Voir le message
    Il y a juste une petite question qui me tourmente. La fonction strcpy a la signature suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char * strcpy ( char * destination, const char * source );
    Comment le char * destination peut être modifié alors qu'elle n'attend pas un char **? J'ai l'impression qu'une finesse du concept m'échappe encore !

    En tout cas un grand Merci,

    Benjamin
    Le contenu de la chaine est modifié, pas l'adresse pointant sur celle-ci !!!

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 01/09/2014, 16h12
  2. Réponses: 5
    Dernier message: 01/08/2010, 09h07
  3. Réponses: 9
    Dernier message: 06/11/2007, 12h36
  4. Réponses: 11
    Dernier message: 05/11/2007, 14h38
  5. Réponses: 1
    Dernier message: 08/03/2004, 11h35

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