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é.
Le Tout est souvent plus grand que la somme de ses parties.
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 »).
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.
Le Tout est souvent plus grand que la somme de ses parties.
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.
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.
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 :
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.
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 ?)
À 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.
(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.
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.
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.
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.
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.
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.
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"));
}
× 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.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
En recherche d'emploi.