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 :

pointeur et double pointeur


Sujet :

C

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

    Informations forums :
    Inscription : Avril 2008
    Messages : 89
    Points : 56
    Points
    56
    Par défaut pointeur et double pointeur
    Bonjour.
    Je cherche à pointer vers un mot dans une chaine de caractères via un programme tel que celui ci dessous.
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char* getLastWordKO(char* src, char* lastWord);
    char* getLastWordOK(char* src, char** lastWord);
     
    int main()
    {
        char* testStr = "chaine test\0";
        char* lastWord = "str\0";
        char* lastWord2 = "str2\0";
        lastWord2 = getLastWordKO(testStr, lastWord);
        printf("KO : param : %s - ret : %s\r\n", lastWord, lastWord2);
     
        lastWord2 = getLastWordOK(testStr, &lastWord);
        printf("OK : param : %s - ret : %s\r\n", lastWord, lastWord2);
     
        return 0;
    }
     
    //redirection de lastword pour pointer vers le premier espace.
    //Ne fonctionne pas sur le pointeur passé en paramètre, mais retourne bien la bonne adresse.
    char* getLastWordKO(char* src, char* lastWord)
    {
        lastWord = strrchr(src, ' ')+1;
        return lastWord;
    }
     
    //redirection de lastword pour pointer vers le premier espace.
    //fonctionne dans les 2 cas.
    char* getLastWordOK(char* src, char** lastWord)
    {
        *lastWord = strrchr(src, ' ')+1;
        return *lastWord;
    }
    En passant par un simple pointeur, la première fonction renvoie bien la bonne adresse (lastWord2 pointe vers "test\0"), mais le pointeur lastWord n'est pas modifié et pointe vers "str\0"
    En utilisant un double pointeur dans la deuxième fonction, le résultat est correct (les deux pointeurs sont à l'adresse de "test\0").

    J'ai du mal à comprendre ce qui ne fonctionne pas dans le premier cas. c'est le fait de modifier une adresse plutôt qu'une donnée ?
    Dans ce cas, en écrivant dans la première fonction *lastWord ="aaa\0"; ou plutôt strcpy(lastWord, "aaa\0"); mon programme devrait afficher aaa au lieu de str, mais cela me donne une erreur d'exécution dans les 2 cas...
    merci d'avance pour vos éclaircissements.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Réfléchis 2 minutes c'est simple

    Avec un simple pointeur, en faisant lastWord = strrchr(src, ' ')+1;, tu mets la valeur dans une variable temporaire.

    Avec un double pointeur et le déférencement, tu vas chercher la bonne variable

  3. #3
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    En C les arguments de fonction (pointeurs compris) sont passés par valeur, pour altérer les variables extérieures il faut donc passer leur adresses.

    C'est un sujet fréquent.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Attention, en C il y a une incohérence entre le code et la réalité, pour des raisons historiques:
    Une chaîne littérale est en fait stockée en mémoire constante, malgré qu'on puisse pointer dessus sans warning avec un char*.

    Il n'y a pas de solution à ce problème en C sous Visual Studio, mais il y en a une sous gcc: si tu ajoutes le paramètre -Wwrite-strings à ta ligne de commande de compilation, les chaînes littérales seront déclarées constantes, ce qui donnera des warnings sur les lignes 10 à 12.

    Le code correct sera alors:
    Code C : 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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char const* getLastWordKO(char const* src, char const* lastWord);
    char const* getLastWordOK(char const* src, char const** lastWord);
     
    int main()
    {
    	char const* testStr = "chaine test\0";
    	char const* lastWord = "str\0";
    	char const* lastWord2 = "str2\0";
    	lastWord2 = getLastWordKO(testStr, lastWord);
    	printf("KO : param : %s - ret : %s\r\n", lastWord, lastWord2);
     
    	lastWord2 = getLastWordOK(testStr, &lastWord);
    	printf("OK : param : %s - ret : %s\r\n", lastWord, lastWord2);
     
    	return 0;
    }
     
    //redirection de lastword pour pointer vers le premier espace.
    //Ne fonctionne pas sur le pointeur passé en paramètre, mais retourne bien la bonne adresse.
    char const* getLastWordKO(char const* src, char const* lastWord)
    {
        lastWord = strrchr(src, ' ')+1;
        return lastWord;
    }
     
    //redirection de lastword pour pointer vers le premier espace.
    //fonctionne dans les 2 cas.
    char const* getLastWordOK(char const* src, char const** lastWord)
    {
        *lastWord = strrchr(src, ' ')+1;
        return *lastWord;
    }
    Note: Si tu regardes le prototype de strrchr(), tu constateras une autre erreur: Elle accepte un pointeur const, mais retourne un pointeur non-constant. C'est très dangereux, mais il est trop tard pour le changer dans la norme C, car trop de programmes ne compileraient plus...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Il y a déjà une discussion récente à ce sujet Différentes déclarations de Chaines de Caractères

  6. #6
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Très bons conseils de Médinoc qui est, je m'en rend compte, le seul d'entre nous à avoir attentivement lu le code proposé.

  7. #7
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    [...]
    Note: Si tu regardes le prototype de strrchr(), tu constateras une autre erreur: Elle accepte un pointeur const, mais retourne un pointeur non-constant. C'est très dangereux, mais il est trop tard pour le changer dans la norme C, car trop de programmes ne compileraient plus...
    Ce n'est pas une erreur. Il est tout à fait légitime de ne pas renvoyer un pointeur constant. Le const dans le prototype n'indique pas que strchr n'accepte que des const char * mais indique que la fonction s'engage à ne pas modifier la string. const et read only ne sont pas la même notion.
    Ce que tu appelles erreur est quelque part un manque de polymorphisme : ce serait bien d'avoir «si je te donne un paramètre const char * alors tu me renvoies un const char * mais si je te donne un char * alors tu me renvoie un char *». Une sorte de qualificateur de type qui resterait … C'est peut-être possible avec les _Generic de C11, faudrait que j'y jette un œil à l'occasion.

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Il n'empêche que la fonction n'est pas const-correct, puisqu'elle fait un cast de pointeur const en non-const sans le dire.
    Il aurait fallu, dès l'origine, deux fonctions différentes (mais en C, contrairement au C++, elles seraient alors contraintes d'avoir des noms différents).

    Edit: D'ailleurs, il en est de même pour strtol() et ses sœurs.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Il n'empêche que la fonction n'est pas const-correct, puisqu'elle fait un cast de pointeur const en non-const sans le dire.
    Il aurait fallu, dès l'origine, deux fonctions différentes (mais en C, contrairement au C++, elles seraient alors contraintes d'avoir des noms différents).

    Edit: D'ailleurs, il en est de même pour strtol() et ses sœurs.
    Oui, la const correctness en C n'est pas applicable car en C const n'est pas read only mais couvre plusieurs notions. Les mécanismes de C foutent encore plus le bordel dans l'élaboration d'une const correctness, c'est clair.
    Et tu as tout à fait raison, il aurait fallu deux fonction différentes, tout comme dans math.h il y a tout (ou presque) en triple : une version float, une version double et une version long double.
    Heureusement avec l'introduction des _Generic en C11 cela simplifie un peu l'api.
    On pourrait imaginer quelque chose d'équivalent à tgmath.h (type generic math) →
    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 <stdio.h>
    #include <string.h>
     
    const char* const_strchr(const char *s, int c)
    {
      return (const char*) strchr(s,c);
    }
     
    #define strchr(s,c) _Generic( (s), \
                                  const char *: const_strchr, \
                                  default: (strchr) ) (s,c)
     
    #define what_is(c) _Generic( (c), \
                                 const char *: "const char *", \
                                 char *: "char *", \
                                 default: "something else" )
     
    int main(void)
    {
      const char const_test[]="this is a const test";
      char simple_test[]="this is a simple test";
     
      printf("const_test  →  '%s'\n"
             "simple_test →  '%s'\n", what_is(strchr(const_test, '\0')),
                                      what_is(strchr(simple_test, '\0')));
     
      return 0;
    }
    Un quick and dirty pour tester …

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 89
    Points : 56
    Points
    56
    Par défaut
    Bonjour,

    Merci à tous, et plus particulièrement à Médinoc pour vos réponses. Je comprends mieux d'où venait mon problème.
    Je suis sous GCC (et microcontrôleur ARM), je vais faire les modifs et regarder ça de plus près.

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

Discussions similaires

  1. double pointeur dans un fichier txt
    Par micka180 dans le forum VBScript
    Réponses: 14
    Dernier message: 22/01/2008, 16h23
  2. Comment convertir un pointeur en Double?
    Par Art19 dans le forum Langage
    Réponses: 13
    Dernier message: 20/07/2007, 11h05
  3. Réponses: 6
    Dernier message: 07/07/2007, 18h12
  4. Réponses: 6
    Dernier message: 04/01/2007, 01h30
  5. double pointeur?
    Par ostralo dans le forum C++
    Réponses: 17
    Dernier message: 23/02/2006, 18h24

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