ludoztw a écrit :
Bonjour à tous,
J'ai demain une évaluation sur les pointeurs en langage C. J'ai bien bossé mon cours ainsi que mes TP mais tout n'est pas pour autant clair dans ma tête.
Ce chapitre reste toujours vague.Mes questions sont les suivantes :
- A quoi sert réellement un pointeur? Dans quel cas est-il vraiment utile?
|
Bonjour
Tant pis pour l'évaluation, j'arrive trop tard. Toutefois, ce n'est pas pour ça que tu doives laisser tomber.
Donc comme cela a été dit, un pointeur est une variable faite pour contenir une adresse, généralement l'adresse d'une autre variable
Exemple
Code :
int entier=18; int *pt=&entier; // La variable "pt" contient l'adresse de "entier"
|
A quel moment est-ce vraiment utile ?
Généralement dans 2 cas principaux
1) quand une fonction doit modifier une variable qui appartient à une autre fonction
Comme la plage d'adressage de l'ensemble des variables du programme est globale et unique ; et parce qu'une fonction ne reçoit qu'une copie de ce qu'on lui passe, si elle doit modifier une autre variable il faut alors lui passer l'adresse de cette autre variable.
Exemple
Code :
void modif(int *local) { *local=18; } int main() { int entier=5; int *pt=&entier; modif(pt); }
|
2) Quand tu dois faire passer à une autre fonction un élément complexe (une structure, un tableau). Comme là encore la fonction recevra une copie de ce que tu lui passes, il vaut mieux lui passer l'adresse de l'élément (la copie se fera sur une simple adresse de 2 ou 4 octets plutôt que sur l'élément lui-même qui peut avoir plusieurs milliers d'octets)
Exemple
Code :
int main() { int tab[]={1, 2, 3, 3, 2, 1}; affiche(tab, 6); // Pourquoi "tab" et pas "&tab" puisqu'on passe une adresse ? Parce que le nom "tab" correspond à l'adresse de son premier élément. Ainsi tab <=> &tab[0] } void affiche(int *tab, int nb) { int i; for (i=0; i < nb; i++) printf("tab[%d]=%d\n", i, tab [i ]); // Comme la fonction ne sait pas où tab est sensé s'arrêter, on est obligé aussi de lui passer le nombre d'éléments du tableau }
|
Tous les autres cas où on utilise les adresses ne dérivent que de ces deux cas principaux.
ludoztw a écrit :
- Je m'embrouille aussi avec l'utilisation de l'adresse (& ), du *, et de l'utilisation de la simple variable. Si quelqu'un pouvait me réexpliquer brièvement, ce serait for sympathique
|
Pas de souci
Là encore ça se divise en 2 cas
1er cas: tu dois utiliser le pointeur (ou plus précisément le contenu de l'adresse). Dans ce cas, il te faut mettre autant d'étoiles que le pointeur en a
Exemple: int ***pt: Adresse de l'adresse de l'adresse d'un entier
Si tu veux obtenir cet entier, il te faut demander ***pt
Exemple: int var=***pt;
2° cas: tu veux remplir un pointeur. Dans ce cas, il te faut juste connaitre la nature de ce que tu as en main pour savoir comment le référencer pour que le pointeur soit correctement rempli
Prenons mon second exemple
Code :
void modif(int *local) { *local=18; }
|
La fonction "modif" est sensé recevoir l'adresse d'un entier ; et stocker cette adresse dans la variable "local".
Exemple n° 1: tu as, de ton coté, un entier => int i=100
Si tu veux passer ce "i" à la fonction, comme la fonction doit recevoir une adresse, il te faut lui passer l'adresse de cet entier
Code :
- int i=100;
- modif(&i);
|
Exemple n° 2: tu as maintenant l'adresse d'un entier => int *pt
Puisque pt est déjà une adresse, il te suffit alors de le passer directement à la fonction
Code :
- int i=100;
- int *pt=&i;
- modif(pt);
|
Exemple n° 3: tu as un tableau d'entiers => int tab[]={...,...,...}
Puisque la fonction n'est prévue que pour l'adresse d'un entier, et que chaque tab[x] correspond à un entier, il te suffit de passer l'adresse de cet entier (&tab[x]) à la fonction. Toutefois, puisque l'arithmétique des pointeurs dit que &tab[x] équivaut à tab + x, tu peux alors utiliser cette équivalence pour simplifier l'écriture (attention cela n'optimise que l'écriture et en rien le code car dans les deux cas il y a toujours une addition de faite)
Code :
int tab[]={1, 2, 3, 4, 5, 6}; int i; for (i=0; i < 6; i++) { modif(&tab[i]); // Ces deux écritures modif(tab + i); // Sont totalement équivalentes }
|
Remarque sur l'exemple n° 3: dans le cas où tu travailles souvent sur tab[x], tu sais que chaque appel à tab[x] se soldera par un décalage de x positions à partir de tab (donc une addition) ; tu peux pour optimiser les appels, mémoriser ce décalage dans un pointeur dédié puis utiliser ce pointeur à la place de tab[x]. Ainsi, le décalage (l'addition) ne se fera qu'une fois.
Exemple
Code de base
Code :
int tab[]={1, 2, 3, 4, 5, 6}; int i; for (i=0; i < 6; i++) printf("j'affiche 3 fois chaque élément i: %d - %d - %d\n", tab [i ], tab [i ], tab [i ]); // A chaque tab[i], le compilo se tape le décalage à partir de tab
|
Code optimisé
Code :
int tab[]={1, 2, 3, 4, 5, 6}; int *pt; int i; for (i=0; i < 6; i++) { pt=&tab[i]; // Ou bien pt=tab + i printf("j'affiche 3 fois chaque élément i: %d - %d - %d\n", *pt, *pt, *pt ); // Comme j'ai mémorisé l'adresse de tab[i] dans pt, je peux afficher le contenu "*pt" donc le contenu de tab[i] }
|
Et on peut en plus utiliser les possibilités de la virgule pour le raccourcir de cette façon
Code :
for (i=0, pt=tab; i < 6; i++, pt++) printf("j'affiche 3 fois chaque élément i: %d - %d - %d\n", *pt, *pt, *pt ); // Puisque pt s'incrémente avec i, alors *pt reste solidaire de tab[i] }
|
Cet exemple pourrait être le 3° cas d'utilisation des pointeurs mais comme c'est facultatif je préfère le laisser comme cas particulier qui dérive du cas n° 2
Message édité par Sve@r le 14-10-2013 à 08:54:31
---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.