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 :

Usage des pointeurs dans les fonctions


Sujet :

C

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 1
    Points
    1
    Par défaut Usage des pointeurs dans les fonctions
    Bonjour,

    je cherche une explication à un problème de bon usage des pointeurs lors d'un appel de fonction C.

    Voici 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
     
    #include <stdio.h>
     
    int entier;
     
    int foo ( int *ptr ) {
      ptr = &entier;
    }
     
    int main ( void ) {
      int *a;
      entier = 200;
      foo(a);
      printf("%d\n",*a);
    }
    Dans le programme principal, je pensais qu'après l'appel de foo(), mon pointeur "a" prendrait l'adresse de la variable globale "entier". Il semblerait que non... Est ce que quelqu'un pourrait m'expliquer pourquoi ? Est ce que parce que passé ainsi, ce pointeur est en fait passé par valeur, ce qui empêche toute modification ?

    Merci d'avance

    Didou

  2. #2
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Effectivement, après quelques ajouts permettant de visualiser les différentes adresses, voici la trace (et le code associé) :

    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
     
    #include <stdio.h>
     
    int entier;
     
    int foo ( int *ptr ) {
     
      ptr = &entier;
      printf("Adresse pointée par ptr : %x\n",ptr);
    }
     
    int main ( void ) {
     
      int *a;
      printf("Adresse de la variable entier %x\n",&entier);
      entier = 200;
      foo(a);
      printf("Adresse pointée par a : %x\n",a);
      printf("entier = %d, *a = %d\n",entier,*a);
    }
    La trace :
    Adresse de la variable entier 80496b0
    Adresse pointée par ptr : 80496b0
    Adresse pointée par a : b7815ff4
    entier = 200, *a = 1318268

    Une explication ?

  3. #3
    Membre actif
    Avatar de fmdao
    Profil pro
    Formateur en informatique
    Inscrit en
    Novembre 2010
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Formateur en informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 90
    Points : 210
    Points
    210
    Par défaut
    Il faut une double indirection.
    Il faut passer comme parametre un pointeur sur le pointeur.

    foo( int **ptr)

  4. #4
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Arrivé par hasard sur le sujet je me permet de l'enrichir d'une question supplémentaire (surtout pour voir si j'ai compris).

    Le code suivant serait-il équivalent à ce que propose fmdao ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
     
    int entier;
     
    int foo ( int *ptr ) {
      ptr = &entier;
    }
     
    int main ( void ) {
      int a;
      entier = 200;
      foo(&a);
      printf("%d\n",a);
    }

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  5. #5
    Membre éprouvé 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 : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Bonsoir.
    C'est la fonction foo qui pose problème, donc... oui...
    Du moins sur le fait qu'après l'appel de la fonction, la valeur pointée par/de a n'est pas celle d'entier.

    La seule différence, c'est que dans le code de fmdao, a ne pointe sur aucune zone particulière (pointe n'importe où, en gros), et donc *a n'est pas forcément valide.

  6. #6
    Membre actif
    Avatar de fmdao
    Profil pro
    Formateur en informatique
    Inscrit en
    Novembre 2010
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Formateur en informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 90
    Points : 210
    Points
    210
    Par défaut
    Ok mais, ce n'était pas la logique du premier programme.

    int main ( void ) {
    int *a;
    entier = 200;
    foo(a);
    printf("%d\n",*a);
    }


    Voulait-il récupérer la valeur de a ou un pointeur sur un entier qui existe belle et bien puisque en globale ?

    Je suis d'accord que dans l'absolu, c'est maladroit

  7. #7
    Membre éprouvé 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 : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Désolé transgohan, j'ai lu trop vite...
    Ton code est plutôt équivalent à celui de didou31...
    (Dans le sens où il ne fait pas ce qu'il lui demande... )

    @fmdao Je pense qu'il voulait simplement que a pointe sur une variable globale...

  8. #8
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Citation Envoyé par Steph_ng8 Voir le message
    Désolé transgohan, j'ai lu trop vite...
    Ton code est plutôt équivalent à celui de didou31...
    (Dans le sens où il ne fait pas ce qu'il lui demande... )
    Dans quel sens ? Le fait que je n'utilise pas un pointeur dans le main ? Ou bien que le changement ne sera pas pris en compte ?

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  9. #9
    Membre éprouvé 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 : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Le changement ne sera pas pris en compte.

  10. #10
    Membre actif
    Avatar de fmdao
    Profil pro
    Formateur en informatique
    Inscrit en
    Novembre 2010
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Formateur en informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 90
    Points : 210
    Points
    210
    Par défaut
    En C, on passe forcément les paramètres par valeur, ce qui signifie que l'on peut utiliser la valeur de ce paramètre.
    Ce parametre est comme une variable locale à la fonction qui disparaîtra au retour de la fonction.

    Pour pouvoir modifier, un argument, il faut passer à la fonction l'adresse de l'argument :


    - soit en lui donnant la valeur du pointeur :

    void foo(int *pointeurSurUnEntier)
    {
    *pointeurSurUnEntier = 20;
    }

    main()
    {
    int a;
    foo( &a); // argument = l'adresse de a qui va devenir un pointeur dans la fonction
    // a a la même valeur que entier
    }

    - soit en faisant un passage par référence ( c'est mieux : pas de ces pointeurs de merde) :


    void foo( int &referenceUnEntier)
    {
    referenceUnEntier = 20;
    }

    main()
    {
    int a;

    foo ( a); // argument = une référence vers a
    }

  11. #11
    Membre éprouvé 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 : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par fmdao Voir le message
    - soit en faisant un passage par référence ( c'est mieux : pas de ces pointeurs de merde) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void foo( int &referenceUnEntier)
    {
       referenceUnEntier = 20;
    }
     
    main()
    {
     int a;
     
     foo ( a);  // argument = une référence vers a
    }
    Euh... c'est du C++, ça...

  12. #12
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Merci pour vos différentes réponses. Je clarifie certains points et je poursuis la discussion :

    - je développe effectivement en C et non en C++. Je ne peux donc pas utiliser un passage par variable tel que void foo ( int &referenceUnEntier ).

    - je cherche effectivement à programmer une fonction qui me renvoie un pointeur sur un objet (ici un int) qui est en variable globale. Afin d'économiser de la mémoire, je cherche donc à ne pas dupliquer cet objet dans le main. La solution proposée par transgohan ne me convient pas puisque l'entier est créé dans le main en plus de la variable globale.

    - si je comprends bien, dans mon code initial, le pointeur est passé par valeur, il ne peut donc pas être modifié (c'est bien basique mais ça m'avait échappé !). Je vois donc deux solutions pour résoudre mon problème :

    o soit passer par un pointeur sur ce pointeur comme proposé par fmdao. Ça donne :

    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
     
    foo ( int **ptr ) {
     
      *ptr = &entier;
      printf("Adresse pointée par ptr : %x\n",*ptr);
    }
     
    main () {
     
      int *a;
      printf("Adresse de la variable entier %x\n",&entier);
      entier = 200;
      foo ( &a );
      printf("Adresse pointée par a : %x\n",a);
      printf("entier = %d, *a = %d\n",entier,*a);
    }
    ça fonctionne, voici la trace :
    Adresse de la variable entier 80496b0
    Adresse pointée par ptr : 80496b0
    Adresse pointée par a : 80496b0
    entier = 200, *a = 200

    o soit fournir le pointeur par le retour de la fonction :

    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
     
    int* foo () {
     
      return &entier;
    }
     
    main () {
     
      int *a;
      printf("Adresse de la variable entier %x\n",&entier);
      entier = 200;
      a = foo ( );
      printf("Adresse pointée par a : %x\n",a);
      printf("entier = %d, *a = %d\n",entier,*a);
    }
    ça fonctionne aussi, voici la trace :
    Adresse de la variable entier 8049670
    Adresse pointée par a : 8049670
    entier = 200, *a = 200

    La première solution me permet d'utiliser un return pour gérer un retour de la fonction, ce qui n'est pas possible dans le second cas...

    Merci pour vos contributions.

  13. #13
    Membre éprouvé 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 : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    C'est bien ça.

    Citation Envoyé par didou31 Voir le message
    Afin d'économiser de la mémoire, je cherche donc à ne pas dupliquer cet objet dans le main.
    À moins que ce soit un objet très gros (ou très complexe) ou que tu sois limité en mémoire, ce n'est pas nécessaire.

    Citation Envoyé par didou31 Voir le message
    La première solution me permet d'utiliser un return pour gérer un retour de la fonction, ce qui n'est pas possible dans le second cas...
    Certes, mais je ne vois pas pourquoi tu pourrais avoir besoin d'utiliser la valeur de retour de la fonction...
    Elle n'a aucune chance d'échouer, et je ne vois pas ce que tu pourrais renvoyer comme autre information.

    Plutôt que d'utiliser une variable globale, tu peux utiliser une variable statique locale à la fonction.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int * f()
    {
        static entier = 200;
        return &entier;
    }
     
    /*******************/
     
    void f(int **ptr)
    {
        static entier = 200;
        *ptr = &entier;
    }
    entier ne sera initialisée qu'au premier appel de f, donc ça correspond à ce que tu veux.
    Et puis, ça a l'avantage de ne pas utiliser de variable globale... ()
    Par contre, s'il n'y a aucun moyen de l'initialiser en une seule instruction, ce n'est pas possible d'utiliser cette méthode.

Discussions similaires

  1. Réponses: 1
    Dernier message: 14/06/2010, 16h24
  2. Réponses: 15
    Dernier message: 23/01/2010, 18h39
  3. [plpgsql] transaction dans les fonctions ?
    Par hpghost dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 27/06/2004, 16h56
  4. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14

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