Bonjour,
Je voulais savoir si l'on pouvait se dispenser d'initialiser un pointeur si plus tard dans le programme on fait un malloc de ce pointeur et que jusqu'a ce malloc on ne se sert pas du pointeur en question?
merci
Bonjour,
Je voulais savoir si l'on pouvait se dispenser d'initialiser un pointeur si plus tard dans le programme on fait un malloc de ce pointeur et que jusqu'a ce malloc on ne se sert pas du pointeur en question?
merci
Tu peux, rien ne t'empeche. Cependant, si on conseille d'initialiser les pointeurs, c'est pour éviter un comportement dangereux et permettre un debuggage plus facile.
Imagine que tu n'as pas initialiser ton pointeur a null, et tu passes ton programme a quelqu'un...lui il a pas trop suivi ce que t'as fait et il tente d'utiliser ton pointeur avant le malloc : tu vas te retrouver avec un programme au comportement indéfini qui pourrait écrire des données a de mauvaises adresses etc...Bref, un truc faux et pas évident a débugger. Au moins en initialisant ton pointeur a null tu ne risque pas d'écrire à un mauvais emplacement et en cas d'utilisation du pointeur, le programme plantera net à chaque fois (au lieu d'avoir un comportement flou)
C'est techniquement possible mais formellement déconseillé.Envoyé par sone47
ou mieux (ce n'est pas toujours possible)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 T *p = NULL; p = malloc (...);
Nota. On ne fait pas un "malloc de ce pointeur", mais "on alloue un bloc avec malloc(), dont on stocke l'adresse dans ce pointeur".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 T *p = malloc (...);
Attention à utiliser la bonne terminologie, sinon, tu donnes l'impression de ne pas maitriser ton sujet...
Oui, et surtout, tu peux le détecter avec un if (p != NULL)Envoyé par Ksempac
Salut,
Théoriquement, rien ne t'empêche de déclarer un pointeur sans l'initialiser dans la foulée...
Cependant, il faut bien comprendre que, quand tu déclare une variable, meme si, comme pour un pointeur, elle va contenir une adresse mémoire, sa valeur avant d'être initialisée est... tout et n'importe quoi...
Pour etre précis, la valeur est... ce qui s'est trouvé à l'adresse utilisée par la mémoire la dernière fois qu'elle a été utilisée (ca peut etre des valeurs qui étaient utilisées par une application qui a été fermée depuis des heures... voir des jours)
Il s'en suit que, tant que tu n'es pas sur que l'adresse que la variable contient est belle et bien valide, le fait d'essayer d'accéder à cette adresse va provoquer des catastrophes pouvant aller jusqu'au crash système dans les cas les plus graves...
C'est la raison pour laquelle il est très fortement conseillé d'initialiser les pointeurs à NULL (car, au moins, c'est une valeur facilement testable) tant qu'ils ne prennent pas une adresse valide, et de systématiquement vérifier les valeurs des pointeurs avant d'essayer d'y accéder et/ou apres une fonction d'allocation![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
et de remettre à NULL après libération de la ressource pointée...Envoyé par koala01
Envoyé par Emmanuel Delahaye
oui... évidemment... sinon le reste n'a aucun sens
![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
d'accord merci,
je demandais ceci car un prof m'avais barré mes init pointeurs car plus tard on allouait de la memoire.
L'action de mon prof aurait été plus credible si on allouait dessuite apres avoir creé le pointeur.
Est il possible de savoir de quel taille a été une allocation en ayant juste l'adresse premiere case car je n'ai pas saisi si pour toutes les chaines la terminaison était toujours '\0'?
Merci
Desormais je mettrai toujours a NULL quelque soit le cas ceci ne peut donc que m'éviter ds prob.
merci
Une autre question dans l'elan si j'utilise un pointeur qui pointe vers un autre pointeur comment se definit le premier?
Pour ce qui est des chaines de caractères, et uniquement des tableaux de caractères considérés comme tel (car un char peut très bien etre considéré comme un entier... ne permettant qu'un nombre restreint de valeur), il faut savoir que toutes les fonctions qui les manipulent vont rechercher ce fameux caractères '\0' pour déterminer si la fin de la chaine a été atteinte...
On en arrive aux situations assez particulieres que:
- si le caractère '\0' a été "oublié", ta chaine sera considérée comme continuant bien au delà de la mémoire qui lui a été allouée (jusqu'à ce que l'équivalent d'un '\0' soit trouvé), ... avec des résultats... surprenants...
- Si tu as un caractère '\0', par exemple à la 10 eme position dans un tableau de 100 caractères, les 90 caractères qui suivent sont purement et simplement ignorés... Ce qui ne veut nullement dire que tu obtiendras une erreur si, par la suite tu essayes de mettre une chaine de 20 caractères dans le tableau
- il est courent, quand tu veux "juste" vider une chaine de caractères, en attendant de la réutiliser, ou quand tu veux supprimer une partie de la fin de la chaine, de placer le caractère '\0' en chaine[0]; dans le premier cas et en chaine[nombre_de_caractères_gardés+1] dans le deuxième (où chaine est, bien entendu, la variable qui correspond à ta chaine de caractères
)
Autrement dit:
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 int main() { char *chaine1;/* Danger important: non initialisé et non NULL (intestable) */ char *chaine2=NULL;/* Danger important: non initialisé (mais testable :D)*/ char *chaine3=malloc(taille);/* Danger moyen: initialisé mais pas forcément vide (sizeof(char)==1 => taille==taille*sizeof(char) ;) risques lors de l'affichage ;) */ char chaine4[100]="salut";/* surprise: 100 caractères dispos, mais la chaine n'en fait que 5 ;) */ chaine4[3]='\0';/* chaine4 vaut "sal" */ chaine4[0]='\0';/* chaine4 est considérée comme vide strlen(chaine4)==0 alors qu'en mémoire on trouve "\0al\0ut\0...." ;)*/ }
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Merci mais donc en utilisant calloc, le fait d'init ne place pas le caractere '\0' en fin.
Ce que je me pose comme question c'est si on alloue de la memoire via calloc et que l'on passe dans une fonction l'adresse de la premiere case comment faire pour savoir jusqu'ou a été l'allocation?
Je me pose également la question plus haute sur les pointeurs de pointeurs car j'ai pas trouvé d'exemple sur le net.
merci
je dirais plutôt équivalent au précédent, les 2 à danger moyens. Le premier car possbile utilisation si on oublie malloc, le second car on est pas sûr que l'allocation se soit bien déroulée. Donc dans tous les cas tester...Envoyé par koala01
Pour les pointeurs de pointeurs, tu reprends le principe des pointeurs, et tu fais pareil:
Pour définir un pointeur, c'est
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 /* définition "statique" d'un pointeur */ int a=100: int *pta=&a;/* prend comme valeur l'adresse à laquelle se trouve a */ /* définition dynamique d'un pointeur */ int *ptab=malloc(sizeof(int)*taille); (...)/* principalement, tester que ptab ne vaut pas NULL avant toute chose*/ /* définition "statique" d'un pointeur de pointeur (prend l'adresse d'un pointeur défini précédemment)*/ int **ppta=&pa; /* définition dynamique d'un pointeur de pointeur: on signale qu'il nous faut la taille nécessaire à un pointeur sur entier */ int **pptab=malloc(sizeof(int*)*taille); /* et, ce n'est qu'une fois que l'on a notre pointeur de pointeur qu'on peut allouer la mémoire pour les pointeur qu'il contient... si l'allocation de pptab a réussi uniquement */ if(pptab!=NULL)/* on n'entre pas ici si l'allocation de pptab a échoué */ { for(i=0;i<taille;i++)/* on passe chaque pointeur en revue */ { pptab[i]=malloc(sizeof(int)*taillecolone);/* pour chacun d'eux, on alloue la mémoire nécessaire */ (...) /* à chaque fois tester que l'allocation a réussi... sinon, il faudra gérer l'erreur (*vraissemblablement* libérer la mémoire de tout et quitter ;)*/ } }
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Envoyé par souviron34
:
- malloc ne fait qu'une chose: fournir un espace mémoire de la taille que tu lui demande... Ce qui se trouve dans cet espace mémoire est... tout ce qui s'y trouvait du fait d'une utilisation antérieur de la mémoire... des crasses
- realloc fait un peu plus: copier ce qui se trouve dans l'espace dont on demande la réallocation dans l'espace alloué, de telle sorte que le plus petit rentre dans le plus grand (==> danger si tu fais un realloc qui demande une taille inférieure à celle que tu avais avant: troncature possible de la chaine)
- calloc, je ne m'y suis jamais intéressé
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
je ne sais pas pourquoi tu dis ça en me citantEnvoyé par koala01
![]()
Le point 1 est exactement ce que je disais : meême si tu utilises en initalisation malloc, il faut quand même tester que l'allocation s'est bien déroulées avant d'utiliser le pointeur.
Le point 2 : le danger ne vient pas de ce que tu dis. Il vient du fait au contraire que si tu demandes plus grand, il est possbile que ça échoue. Et donc il vaut mieux faire un realloc dans un pointeur temporaire, véfifier, et ensuite affecter.
Le point 3 est justement très pratique pour les chaînes et les structures, puisqu'il initialise tout à NULL (je crois). Donc aucun danger (sauf si on dépasse la taille allouée bien entendu) d'oublier un '\0', et si on fait des copies par opération de pointeur, on est cependant certain que ce sera terminé par un '\0'..
.
Merci d'avoir pris le temps de rep.
En utilisant ces explications si je veux passer en parametre d'une fonction plusieurs tableaux je créé un pointeur sur un autre pointeur avec chaque case de mon premier pointeur qui pointe sur le pointeur de mes tab.
Ceci differe t il de ce que vous m'avez marqué plus haut a savoir de ne pas attribuer de memoire sur les 'premiers' pointeurs tant que le pointeur de pointeur n'a pas eut sa memoire allouée?
Dans mon cas est ce necessaire vu que mes 'premiers' pointeurs sont deja pointés vers une zone allouée.
la je veux passer deux tableaux en parmetre:
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 void main() { float init_pt1; float init_pt2; float * pt1; float * pt2; float ** pptr; pt1=&init_pt1; pt2=&init_pt2; pptr=pt1; .../*travail sur pt1 et pt2 allocation remplissage*/ float **pptr = (float **)calloc(2,sizeof(float *)); if (pptr==NULL) { printf("Error of memory allocation !!!"); exit(1); } else { *(pptr)=pt1; *(pptr+1)=pt2; } ... /* et la je peux passer pptr en parametre pour travailler dans ma fonction sur les deux tableaux*/ return 0; }
Tu crois mal. calloc() initialise tout à "all bits to zero", ce qui marche sur certaines architectures, notamment nos PC x86 et les nombres à virgule flottante IEEE 754 mais PAS PARTOUT.Envoyé par souviron34
D'ailleurs, il n'est même pas garanti qu'un pointeur nul, qui vu du C vaut zéro, soit bien représenté par "all bits to zero" en mémoire.
Edit: Ni même un entier (un bète int), je pense...
Bref, ce n'est pas portable.
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.
Non, à 0. Cf les multiples discussions sur "NULL n'est pas nécessairement 0".Envoyé par souviron34
Cela dit, dans la majorité des cas, NULL = 0, et de même 0.0 se code avec tout à zéro.
autant pour moi, souviron... j'ai cliqué sur le mauvais bouton...
Ce que je voulais citer, c'était le post juste au dessus, de saune:
Merci mais donc en utilisant calloc, le fait d'init ne place pas le caractere '\0' en fin.
Ce que je me pose comme question c'est si on alloue de la memoire via calloc et que l'on passe dans une fonction l'adresse de la premiere case comment faire pour savoir jusqu'ou a été l'allocation?
Je me pose également la question plus haute sur les pointeurs de pointeurs car j'ai pas trouvé d'exemple sur le net.
merci![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Partager