Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pointeur

pointeur ne prend pas la valeur qu'il pointe

Sujet résolu
    29 mars 2021 à 15:18:50

    Bonjour,

    J'ai un exercice sur les pointeur que je n'arrive pas à assimiler ta correction.

    static void f(int *p1,int *p2,int *p3){
    
    	p1 = p2;
    	*p2 = *p3;
    	*p3 = 8;
    
    }
    int main(int argc, char const *argv[])
    {
    	int *a,*b,*c = NULL;
    	a = (int*)malloc(1*sizeof(int));
    	b = (int*)malloc(1*sizeof(int));
    	c = (int*)malloc(1*sizeof(int));
    
    	*a = 1;
    	*b = 2;
    	*c = 3;
    	f(a,b,c);
    	printf(" %d %d %d\n",*a, *b, *c );
    
    
    	return 0;
    }

    La valeur de retour : 1 3 8;

    Avant d'executer le code, j'ai fait sur feuille le processus est je suis tombe sur :  3 3 8

    Pourquoi mon résultat est faux ?

    static void f(int *p1,int *p2,int *p3){
    
    	printf("%d %d\n",*p1,*p2 );
    	p1 = p2;
    	printf("%d %d\n",*p1,*p2 );
    	
    	*p2 = *p3;
    
    	printf("%d %d\n",*p1,*p2 );
    
    	*p3 = 8;
    
    
    }

     J'ai inserer les printf et sa me donne raison sur mon résultat (3 3 8)  mais la correction me donne faux.

    Je sais que j'ai faux mais je ne comprend pas mon erreur. Merci de bien m'éclairer

    -
    Edité par IbBk 29 mars 2021 à 15:41:00

    • Partager sur Facebook
    • Partager sur Twitter
      29 mars 2021 à 15:49:06

      dans la fonction f, ligne 3, pourquoi tu ne déréférence pas p1 et p2  ?
      • Partager sur Facebook
      • Partager sur Twitter
        29 mars 2021 à 16:54:00

        rouloude: enfaite c'est l'exercice en lui-meme qui est comme ça. Il n'y a rien a  changer dans l'exo
        • Partager sur Facebook
        • Partager sur Twitter
          29 mars 2021 à 16:57:14

          Bonjour,

          plutôt qu'un long discours → visualisation pas à pas sur C tutor.

          Edit: Tu attends un peu que ça démarre et tu verras ce qui se passe, le pas à pas se fait avec le bouton next.

          -
          Edité par White Crow 29 mars 2021 à 16:59:08

          • Partager sur Facebook
          • Partager sur Twitter
            29 mars 2021 à 17:08:29

            Merci WhiteCrow pour le site.

            J'ai fait la simulation. J'ai compris mon erreur. Mais la correction on donne une tout autre explicatio. Sa dit:

            "p1 = p2 n'aura aucun effet en sortie de la fonction puisque l'adresse p1 n'est pas accessible "

            Je n'ai pas compris l'explication.

            • Partager sur Facebook
            • Partager sur Twitter
              29 mars 2021 à 17:30:52

              La fonction prend copie de ses paramètres.
              On prend une copie de p1 et on lui assigne une valeur dans la fonction, mais elle n'est pas retournée dans le main.
              Si tu veux la retourner, change le type de ta fonction pour *int au lieu de void et fais un return de p1.
              Tu pourrais passer en paramètre un pointeur vers un pointeur, mais ça risque d'être compliqué.
              • Partager sur Facebook
              • Partager sur Twitter

              Le Tout est souvent plus grand que la somme de ses parties.

                29 mars 2021 à 17:37:04

                Je fais l'hypothèse que tu sais que les arguments d'une fonction sont copiés. Du coup je ne sais pas trop ce que tu n'as pas compris.

                À tout hasard, j'écris deux versions du prototype de la fonction :

                static void f(int *p1, int *p2, int *p3) // version originale
                static void f(int* p1, int* p2, int* p3) // version qui montre bien que
                                                         // les paramètres sont p1, p2, p3

                La deuxième version montre bien que les paramètres de la fonction sont p1 et p2 (et p3), ce sont donc eux qui sont recopiés. L'affectation « p1 = p2 » concerne les copies de p1 et p2, c'est pourquoi elle n'aura aucun effet sur le p1 du programme appelant, la fonction n'ayant pas accès directement à ce 'p1' mais à sa copie (« p1 n'est pas accessible »).

                -
                Edité par robun 29 mars 2021 à 17:39:48

                • Partager sur Facebook
                • Partager sur Twitter
                  29 mars 2021 à 18:02:04

                  Tu peux afficher la valeur d'un pointeur dans un printf avec la spécification  %p
                  printf("%p\n", p1);
                  Fais le dans le main avant et après l'appel. Fais-le dans la fonction au début et à la fin.
                  Ça devrait t'aider à comprendre.
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                    29 mars 2021 à 22:33:18

                    Merci de vos aide à tous.

                    Par votre cause, j'ai pu assimilé le concept "copie" d'une variable.

                    Car je pensais, que p1 = a alors que p1 est un pointeur locale qui pointe sur le pointeur a.

                    A la fin de la fonction f, p1 p2 p3 seront supprimer.

                    quand p1 = p2, on est d'accord que p1 pointe sur p2 qui elle pointe sur b ?( p1 est comme un pointeur de pointeur ????)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      29 mars 2021 à 22:47:16

                      IbBk a écrit:

                      [...]

                      quand p1 = p2, on est d'accord que p1 pointe sur p2 qui elle pointe sur b ?( p1 est comme un pointeur de pointeur ????)

                      Absolument pas. Cette ligne fait que p1 et p2 pointe sur le même endroit en mémoire.

                      Le type pointeur sur pointeur sur un entier serait :

                      int **pp;

                      et pour le faire pointer sur p2 il faut lui donner l'adresse de p2 via l'opérateur & :

                      pp=&p2;

                      Quand tu as des variables plus classiques comme des entiers :

                      int a=1;
                      int b=a;
                      

                      b ne va pas pointer sur a mais on va copier la valeur de a dans b … c'est pareil pour p1 et p2. On copie le contenu de p2 = l'adresse mémoire pointée dans p1 ce qui donnera pour résultat que les contenus de p1 et p2 seront identiques = ils pointent au même endroit.




                      • Partager sur Facebook
                      • Partager sur Twitter
                        29 mars 2021 à 22:57:31

                        White Crow

                        c'est parfait, merci de ton aide.

                        Toutes dernier question,

                        1: si p1 = &p2 peut-on dire que p1 est un pointeur de pointeur ?

                        2:

                        Cette ligne

                        (int*)malloc(1*sizeof(int)) 

                        est elle equivalent à :

                        malloc(1*sizeof(int*)) 
                        ?

                        -
                        Edité par IbBk 29 mars 2021 à 23:08:32

                        • Partager sur Facebook
                        • Partager sur Twitter
                          29 mars 2021 à 23:10:31

                          IbBk a écrit:

                          [...]

                          Cette ligne

                          (int*)malloc(1*sizeof(int)) 

                          est elle equivalent à :

                          malloc(1*sizeof(int*)) 

                          Non. Il y a deux remarques :

                          • il ne faut jamais caster le retour de malloc en C, jamais, never ;
                          • le paramètre donné à malloc est la taille demandée. Pour obtenir la taille d'un objet on utilise l'opérateur sizeof à qui l'on fourni un type ou une variable. Ici tu a sizeof(int) la taille d'un entier en premier et sizeof(int *) la taille d'un pointeur en second. Il ne sont a priori par égaux.

                          Un moyen simple pour moins se tromper est :

                          un_type_quelconque *new = malloc( sizeof *new );
                          

                          ce qu'on peut traduire en français par : alloue moi la mémoire nécessaire pour contenir au moins 1 objet du même type que celui pointé par new.

                          Et si tu en veux plusieurs consécutifs :

                          un_type_quelconque *new = malloc( nombre_souhaité * sizeof *new );

                          mais pour cela tu peux aussi utiliser calloc →

                          un_type_quelconque *new = calloc( nombre_souhaité , sizeof *new );

                          calloc, contrairement à malloc, remplit la zone allouée avec des 0. malloc la laisse tel quel avec plein de garbage.



                          • Partager sur Facebook
                          • Partager sur Twitter
                            29 mars 2021 à 23:14:14

                            non !   sizeof(int)  renvoi la taille d'un int et   sizeof(int*)   renvoi la taille d'un pointeur sur int !

                            le transtypage sur le retour de malloc est inutile !  La multiplication par 1 aussi d'ailleurs ! Ce qui fait que tes allocations aurait pu s'écrire de cette façon :

                            a = malloc(sizeof(int));



                            • Partager sur Facebook
                            • Partager sur Twitter
                              29 mars 2021 à 23:22:48

                              IbBk a écrit:

                              Toutes dernier question,

                              1: si p1 = &p2 peut-on dire que p1 est un pointeur de pointeur ?

                              [...]-

                              Edité par IbBk il y a 7 minutes


                              La seule façon de déterminer le type d'une variable en C est de lire sa déclaration. Avec une ligne du genre 

                              p1 = &p2;

                              tout ce qu'on peut dire c'est que celui qui a écrit ces lignes donner comme valeur à p1 l'adresse de p2. On peut raisonnablement penser que p1 est un pointeur et que son type est sans doute «pointeur sur type de p2», mais rien de plus en l'état.

                              On pourrait très avoir :

                              int p2=12;
                              int *p1=&p2;

                              p1 est un pointeur sur entier

                              Mais aussi :

                              int ***p2=NULL;
                              int ****p1=&p2;
                              

                              p1 est un pointeur sur un pointeur sur un pointeur sur un pointeur sur un entier …

                              Ou pire :

                              int p2=12;
                              char *p1=&p2;

                              qui est autorisé mais produit un warning … p1 est un pointeur sur char et on lui fournit l'adresse d'un int.





                              Edit:

                              En revanche le type de l'expression :

                              &p2

                              sera toujours «pointeur sur type de p2»

                              -
                              Edité par White Crow 29 mars 2021 à 23:25:55

                              • Partager sur Facebook
                              • Partager sur Twitter
                                31 mars 2021 à 13:07:23

                                Cependant, j'ai encore un autre soucis :

                                int *a,*b,*c = NULL;
                                    a = (int*)malloc(1*sizeof(int));
                                    b = (int*)malloc(1*sizeof(int));
                                    c = (int*)malloc(1*sizeof(int));

                                a, b et c sont des pointeur qui sont initiliaslié à NULL (il pointe sur rien).

                                Et par la suite

                                a = (int *) malloc(1*sizeof(int)), qui se traduit :

                                réserve moi pour l'adresse que pointe a une case mémoire de type int , mais a ne pointe sur rien aucune variable, comment réserve pour l'adresse que pointe a alors qu'il pointe sur a ? (je sais pas si je me suis fais comprendre)

                                Je sais pas si j'ai bien traduit cette ligne . Merci d'avance de vos reponse

                                (je n'ai toujours pas compris le int* devant la malloc à quoi il sert ?)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  31 mars 2021 à 13:19:44

                                  À l'initialisation, 'a' ne pointe sur rien puisqu'il a l'adresse 0, OK.

                                  Ensuite, on demande d'affecter à 'a' le retour de la fonction 'malloc'. Cette fonction fait deux choses :

                                  • elle réserve un espace en mémoire ;
                                  • elle retourne l'adresse de cet espace en mémoire.

                                  Du coup 'a' récupère cette adresse (affectation « a = malloc »). Désormais, 'a' contient l'adresse d'un certain espace en mémoire. C'est ce qu'on appelle pointer sur cet espace.

                                  (Sauf si le 'malloc' a échoué.)

                                  -
                                  Edité par robun 31 mars 2021 à 19:35:55

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    31 mars 2021 à 13:26:55

                                    IbBk a écrit:

                                    (je n'ai toujours pas compris le int* devant la malloc à quoi il sert ?)

                                    Le (int*) est appelé un "cast", ça permet la conversion. malloc() retourne un void* à convertir dans le bon type et nous on sait que l'on réservé un int.
                                    Et dans ce cas particulier il est même préférable de ne pas le mettre. Tu peux l'oublier, tu verras ça plus tard.

                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    En recherche d'emploi.

                                      31 mars 2021 à 13:46:58

                                      Du coup, la fonction malloc ne doit être utiliser que pour des type pointeur comme  tableau, chaine de caracter ....
                                      donc a va pointer sur un espace mémoire qui n'a pas éte au prélable déclarer mais la fonction malloc qui va s'en occuper, du coup?
                                      Ah ok  je l'avais pas vu comme sa. je vais voir comment est construit malloc.
                                      Merci . c'est kiffant les forums, sa permet de confronter ces explications avec d'autre

                                      -
                                      Edité par IbBk 31 mars 2021 à 13:53:38

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        31 mars 2021 à 16:25:23

                                        IbBk a écrit:

                                        int *a,*b,*c = NULL;

                                        a, b et c sont des pointeur qui sont initiliaslié à NULL (il pointe sur rien).

                                        Non, seul c est initialisé.

                                        $ cat a.c
                                        #include <stdio.h>
                                        
                                        int main() {
                                        	int *a, *b, *c = NULL;
                                        	printf("%p %p %p\n", a, b , c);
                                        	return 0;
                                        }
                                        $ gcc a.c
                                        $ ./a.out 
                                        0x7ffd8f5b6590 0x5564ddf0f050 (nil)
                                        



                                        En compilant avec les bonnes options, le compilateur l'aurait signalé

                                        $ gcc a.c -Wall -Wextra -pedantic -Werror
                                        a.c: In function ‘main’:
                                        a.c:5:11: error: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Werror=format=]
                                          printf("%p %p %p\n", a, b , c);
                                                  ~^           ~
                                                  %ls
                                        a.c:5:14: error: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘int *’ [-Werror=format=]
                                          printf("%p %p %p\n", a, b , c);
                                                     ~^           ~
                                                     %ls
                                        a.c:5:17: error: format ‘%p’ expects argument of type ‘void *’, but argument 4 has type ‘int *’ [-Werror=format=]
                                          printf("%p %p %p\n", a, b , c);
                                                        ~^            ~
                                                        %ls
                                        a.c:5:2: error: ‘a’ is used uninitialized in this function [-Werror=uninitialized]
                                          printf("%p %p %p\n", a, b , c);
                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                        a.c:5:2: error: ‘b’ is used uninitialized in this function [-Werror=uninitialized]
                                        cc1: all warnings being treated as errors
                                        

                                        ça et d'autres choses.

                                        Notamment que printf attend, avec la spécification, un void*, parce qu'en C (Les Détails Sordides Du Langage C Vont Vous Surprendre) tous les pointeurs ne sont pas forcément de la même longueur (voir du côté des microcontroleurs).

                                        C'est un cas où le "typecast" d'un pointeur "typé" vers un pointeur "générique" doit être explicite.

                                        Pour bien faire nous eussions dû écrire

                                        a = b = c = NULL;
                                        printf("%p %p %p\n", (void *) a, (void *) b , (void *) c);




                                        Mais c'est une autre histoire.


                                        ---

                                        pour les curieux, c'est lié à l'utilisation de "varargs", le code de printf (qui interprète la liste d'arguments selon les formats) ne peut pas deviner la taille du paramètre qu'il a reçu. Voir le code https://code.woboq.org/userspace/glibc/stdio-common/vfprintf-internal.c.html dans la bibliothèque glibc, du côté de la ligne 864 (amis du goto, et des macros de plusieurs centaines de lignes, bonjour !)

                                        Du coup, c'est le compilo qui, sachant que printf et cie sont des fonctions bizarroides, impose le typage explicite.




                                        -
                                        Edité par michelbillaud 31 mars 2021 à 17:06:00

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          31 mars 2021 à 19:47:18

                                          IbBk a écrit:

                                          Du coup, la fonction malloc ne doit être utiliser que pour des type pointeur comme  tableau, chaine de caracter ....
                                          donc a va pointer sur un espace mémoire qui n'a pas éte au prélable déclarer mais la fonction malloc qui va s'en occuper, du coup?

                                          .

                                          La fonction 'malloc' ne doit être utilisée que pour une variable de type pointeur. Peu importe vers quoi pointe ce pointeur (vers un simple petit caractère isolé ou vers le début d'un énoôôôrme tableau). La fonction 'malloc' retourne une adresse, et seul un pointeur peut recevoir une adresse.

                                          Oui, 'a' va en effet pointer vers un espace mémoire qui n'appartient à aucune variable. D'ailleurs cet espace mémoire est séparé de la mémoire des variables déclarées par le programme.

                                          • Les variables déclarées dans le programme sont mémorisées dans une partie de la mémoire vive appelée la pile. C'est un espace mémoire minuscule : 16 Mo sous Linux, un peu moins sous Windows je crois (quand j'utilisais Windows 7 c'était 8 Mo) − il me semble que gcc admet une option de compilation pour redimensionner ça.
                                          • Tandis que les données rangées dans un espace créé par 'malloc' le sont dans le tas, qui correspond à une bonne partie de la mémoire vive (plusieurs Go en pratique).

                                          Maintenant, on peut faire pointer un pointeur vers une variable déclarée. C'est ce qu'on fait lorsqu'on n'utilise pas 'malloc'. Exemple :

                                          int a = 38 ;
                                          int* pointeur = &a ;

                                          Le pointeur reçoit l'adresse de 'a', on dit qu'il pointe sur 'a'. L'adresse d'une variable déclarée (dans la pile) et l'adresse d'une zone allouée (dans le tas) sont le même type d'adresse et conviennent toutes les deux.

                                          -
                                          Edité par robun 31 mars 2021 à 19:48:58

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            31 mars 2021 à 20:59:45

                                            White Crow a écrit:

                                            le paramètre donné à malloc est la taille demandée. Pour obtenir la taille d'un objet on utilise l'opérateur sizeof à qui l'on fourni un type ou une variable.

                                            On fournit une expression, pas une variable.

                                            D'ailleurs, je n'arrive pas à me souvenir de cas en C où il faut fournir une variable. Il y a des cas où il faut fournir une lvalue, mais ça reste un concept bien plus général que la variable.

                                            -
                                            Edité par Marc Mongenet 31 mars 2021 à 22:03:59

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              31 mars 2021 à 21:25:30

                                              Oui, une expression qui n'est pas évaluée … seul le type sera extrait :

                                              #include <stdio.h>
                                              
                                              int main(void)
                                              {
                                                  int i=0;
                                                  printf("i=%d\n", i);
                                                  printf("sizeof(i++)=%zu\n", sizeof(i++));
                                                  printf("i=%d\n", i);
                                                  return 0;
                                              }
                                              

                                              donnera à l'exécution :

                                              i=0
                                              sizeof(i++)=4
                                              i=0
                                              




                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                31 mars 2021 à 21:34:51

                                                Merci de vos reponses.

                                                J'en aurais appris sur les pointeur et de leur déclaractions.

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  1 avril 2021 à 17:44:34

                                                  Marc Mongenet a écrit:

                                                  D'ailleurs, je n'arrive pas à me souvenir de cas en C où il faut fournir une variable. Il y a des cas où il faut fournir une lvalue, mais ça reste un concept bien plus général que la variable.

                                                  Quand on joue avec le préprocesseur ?

                                                  #define NUMBER_OF_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))
                                                  
                                                  int main() {
                                                      int t1[] = {1, 2, 3, 4};
                                                      print_array(t1, NUMBER_OF_ELEMENTS(t1));
                                                  }
                                                  




                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    2 avril 2021 à 18:03:13

                                                    michelbillaud a écrit:

                                                    Marc Mongenet a écrit:

                                                    D'ailleurs, je n'arrive pas à me souvenir de cas en C où il faut fournir une variable. Il y a des cas où il faut fournir une lvalue, mais ça reste un concept bien plus général que la variable.

                                                    Quand on joue avec le préprocesseur ?

                                                    #define NUMBER_OF_ELEMENTS(array) (sizeof(array)/sizeof(array[0]))
                                                    
                                                    int main() {
                                                        int t1[] = {1, 2, 3, 4};
                                                        print_array(t1, NUMBER_OF_ELEMENTS(t1));
                                                    }
                                                    

                                                    Non, pas spécialement. Bien sûr, il s'agit là d'une macro faite pour s'appliquer à des expressions de type tableau, et il est difficile de passer une expression de type tableau qui n'est pas constituée d'un simple nom de variable. Mais ça peut se faire:

                                                    int main() {
                                                        print_array("hello", NUMBER_OF_ELEMENTS("hello"));
                                                    }



                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      2 avril 2021 à 20:55:48

                                                      voire en passant par des objets temporaires :

                                                      int main() {
                                                          print_array( (int []){1,2,3}, 3  );
                                                      }



                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Pointeur

                                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                      • Editeur
                                                      • Markdown