|
|
|
|
Bonjour,
j'étais excellent au C, mais quand on arrive au cours de pointeur je me suis perdu!!
bon je sais pas ce que c'est un pointeur exactement, ce que je sais c'est un pointeur c comme une boite avec un numéro, ce numéro est l'adresse qui est désigné par p par exemple, et le contenue de cette boite qui est désigné par *p.
je voudrais savoir c'est koi la différence entre un pointeur est une variable, j'arrive pas a comprendre ca sert a quoi l'adress du pointure ,
pouvez vous me donnez quelques exemple de programme simple svp?
Merci d'avance
Configuration: Windows XP Google Chrome
Slt,
|
Un pointeur est juste une adresse. Le fait de typer un pointeur permet de débloquer les features suivantes :
|
Dans l'ensemble tu as compris mais il y a quelques imprécisions.
int p[100]; ... on alloue un bloc mémoire de 100*sizeof(int) et on stocke l'adresse de ce bloc dans p (qui n'est jamais qu'un int *, donc une adresse). Si le pointeur est incrémenté il avance par le nombre d'octet, ça dépend de chaque variable (sizeof) Non Ça dépend du type du pointeur incrémenté/décrémenté. Ainsi tu peux tout à fait écrire : #include <stdio.h>
int main(){
unsigned i;
int pi[100]; // j'alloue une plage de 100*sizeof(int) == 400*sizeof(char)
char *pc = (char *) pi;
for(i=0;i<50;++i,++pc) *pc = 'z';
*pc = '\0';
printf("%s\n",(char *)pi);
return 0;
}
Alors ok c'est une manière bien tordue d'allouer un buffer et il aurait été plus logique de déclarer un char buffer[400]; ce qui aurait éviter de faire des casts. Cet exemple sert juste à te montrer que les opérations sur les pointeurs ne dépendent pas de la manière dont la variable a été allouée ou déclarée, mais uniquement du type du pointeur. La seule chose dont il faut s'assurer c'est qu'on ne déborde pas du tableau (ce qui est le cas ici puisqu'on ne parcours que 50 octets sur les 400 alloués). - il faut libérer la case mémoire du pointeur après l'avoir utilisé, on libère chaque pointeur qui n'a pas de valeur (NULL) Non Il faut uniquement libérer avec un free() les plages mémoires allouées avec un malloc ou toute autre fonction d'allocation mémoire. Il ne faut désallouer cette plage mémoire qu'une seule fois. En général, qui dit malloc dit un free correspondant. Il est clair que faire un free(NULL) va planter car c'est une adresse à laquelle le programme n'a pas pu allouer un bloc mémoire. Si tu regardes les pointeurs pi et pc dans mon exemple, ils n'ont pas été initalisés via une fonction d'allocation mémoire (malloc ...), c'est directement l'adresse d'une variable. Dans ce cas, pas de free, les variables locales associées seront désallouées à la fin du scope. {
int x;
int *p = &x;
} // x <-- est désalloué
A contrario : {
int *x;
{
int *p = (int *)malloc(100*sizeof(int));
x = p;
} // p est désalloué car c'est une variable locale, mais pas ce qui s'y trouve
//...
free(x); // ce qui se trouve à l'adresse x (anciennement p) est désalloué
} // x est désalloué en tant que variable locale du scope
Bonne chance |
Répondre à Hatrix
|
donc on n'utilise pas de free si on a pas utilisé malloc! Oui ! (malloc ou calloc, ou tout autre fonction d'allocation mémoire dynamique).
int p[100]; celà signifie que tu alloues un bloc de 100 entiers en tant qu'espace. Cet espace débute à l'adresse p. En mémoire... c'est juste un espace mémoire. La notion de type ne permet au compilateur que de savoir dimensionner un espace mémoire. Par exemple un int est encodé sur 32 bits, un char est codé sur 8 bits etc... Une fois alloué, tu peux utiliser cet espace mémoire comme tu le souhaites. Par exemple dans l'exemple de mon message précédent, pi était à priori un espace prévu pour accueillir 100 entiers, or avec pc je l'ai détourné pour en faire un espace dans lequel stocker des caractères. Mais en soi, c'est juste un espace mémoire. Bon mais attention, ne me fais pas dire ce que je n'ai pas dit. Si tu as besoin de stocker un tableau de caractère il est plus logique de déclarer un char[100] ou d'allouer avec un malloc un espace mémoire pointé par un char * : char *buffer = (char *)malloc(sizeof(char)*100); ... free(buffer); À partir de là, tu dois avoir compris qu'écrire char buffer[100] revient à allouer un bloc contigu de mémoire dont la taille fait 100*sizeof(char) et que cet espace est situé à l'adresse p. Ecrire par la suite p[i] revient à évaluer (vu que p est un char *) l'espace de taille sizeof(char) situé à l'adresse p décalée i*sizeof(char). B o n j o u r \0 0 1 2 3 4 5 6 7 Ici : p[0] = 'B' p[1] = 'o' ... Maintenant pour achever de te convaincre que c'est de la mémoire et vu que sizeof(int) = 4 * sizeof(char), si tu écris : int * pi = p; ... alors écrire pi[0] revient à évaluer les bits formés par la concaténation des bits formés par les caractères "Bonj" (c'est-à-dire p[0],p[1],p[2],p[3]) en tant qu'un entier. Ok ça va faire une valeur en carton pâte, mais d'un point de vue mémoire c'est la même chose. Mais bon là je tombe un peu dans le détail, concrètement tu n'as jamais à te poser ce genre de question. Ce que tu dois retenir c'est que : - déclarer un tableau équivaut à déclarer un bloc de mémoire contigu - écrire p[i] équivaut à écire *(p+i) - qui dit malloc (ou autre fonction d'allocation mémoire) dit free (et uniquement dans ce cas) - évaluer ce qui se trouve à une adresse mémoire invalide provoque une erreur de segmentation (c'est typiquement ce qui se passe quand tu accèdes à la cases 101 d'un tableau de 100 éléments, tu sors de ton espace mémoire). - une variable locale est désallouée à la fin du scope - un paramètre de fonction est une recopie de la variable passée lors de l'appel de cette fonction. J'en profite pour faire une digression sur ce dernier point : #include <stdio.h>
int f(int x){ // ce x est une recopie du x du main
++x;
printf("%d\n",x); // la copie est incrémentée
}
int f2(int *x){ // la valeur recopiée est l'adresse de x
++(*x); // ... donc ici, c'est bien la variable x du main que je modifie
printf("%d\n",*x);
}
int main(){
int x = 3;
f(x); // écrit 4 (la copie est incrémentée)
printf("%d\n",x); // écrit 3, car la variable x du main vaut toujours 3
f(*x); // écrit 4 (x est bien incrémenté)
printf("%d\n",x); // écrit 4
return 0;
}
Si tu as tout compris, tu sais tout ce qu'il est important de savoir sur les pointeurs ;-) Il reste deux trois notions sur les const à voir mais c'est à peu près tout. Bonne chance |
donc on n'utilise pas de free si on a pas utilisé malloc!
|
Effectivement mais c'est exceptionnel et quand ça arrive, c'est précisé dans la doc. Un exemple : getline avec un buffer passé à NULL.
{
char *buffer = (char *) malloc(sizeof(char)*n);
//...
free(buffer);
}
Si c'est une fonction qui alloue un objet (structure...) le malloc étant fait dans la fonction qui assure la construction, il est logique de placer la désallocation dans la fonction qui fait office de destructeur. Et en général on choisit pour ces deux fonctions un nom suffisamment explicite pour ne pas le perdre de vue (par exemple new_plop() et delete_plop()) qui seront à leur tour placé soit dans un même scope, soit chacun dans un "constructeur" ou un "destructeur" : struct plop{
char *buffer;
};
struct plop new_plop(unsigned n){
plop p;
p.buffer = (char *) malloc(sizeof(char)*n);
}
struct delete_plop(plop *p){
free(p.buffer);
}
int main(){
plop p = new_plop(255);
//...
delete_plop(p);
return 0;
}
Bonne chance |
Ah oui pardon :
#include <stdlib.h>
struct plop{
char *buffer;
};
struct plop new_plop(unsigned n){
struct plop p;
p.buffer = (char *) malloc(sizeof(char)*n);
}
struct plop delete_plop(struct plop p){
free(p.buffer);
}
int main(){
struct plop p = new_plop(255);
//...
delete_plop(p);
return 0;
}
Merci Char sniper |