[Débutant en C] L'intérêt du pointeur.
-
Dire qu’on peut s’en passer, moi j’ai du mal à voir. Je ne connais aucun programme sérieux en C qui se passe de pointeurs. Cela fait parti du b.a.-ba du langage. Tableaux dynamiques, chaînage de listes, appels d’API, etc, autant dire qu’on va pas bien loin sans ça.
Je me rappelle que mon prof de programmation en embarqué temps réel nous avait présenté la chose de manière imagée en considérant qu’un pointeur c’est « comme une boite à lettre »: on peut y mettre ce qu’on veut. Je n’ai jamais trop adhéré. Dans les faits, on ne pourrait y stocker qu’un seul « courrier » (une adresse mémoire) mais en fait c’est bien plus. C’est plutôt comme une « porte des étoiles » car au lieu d’un simple contenu c’est carrément un accès vers un espace mémoire (un autre monde de l’Univers de notre programme pour faire filer la métaphore à la Stargate): structures, liste, tableau mono ou multi-dimensionnel des pixels d’une image, etc.
En plus, si on reprend l’exemple de thellier, on peut même utiliser les pointeurs de manière à parcourir des tableaux entiers puisque chaque incrémentation de l’adresse du pointeur de notre tableau permet de passer à un élément suivant (pixel ou tout autre type de données). Et là, on touche quasiment l’assembleur en terme de logique et donc de perfs.
Là où les pointeurs sont « dangereux » c’est qu’il n’y a pas de garde fou si on essaie d’accéder à une adresse hors limite (ex: au delà du nombre de pixels d’une image pour rester sur l’exemple de thellier). C’est pour ça que certains langages « bien pensant » ont essayé d’éradiquer la notion de pointeur mais cela se fait au prix de performances très dégradées.
Conseil de routard: toujours mettre ses pointeurs à NULL lorsqu’ils ne sont plus utiles (voire même dès l’init si ils ne sont pas utilisés de suite). Je dis ça, je dis rien mais c’est très utile lorsqu’on debug au pas à pas, ça limite les risques de violation d’accès et ça facilite le pistage des fuites mémoires. 😉
En fait en C, il manque la référence et on n’a que les pointeurs (contrairement au c++).
D’ailleurs ce n’est pas pour rien que l’opérateur «*» se nomme «opérateur de déréferencement».
Le gros problème des pointeurs, ce sont les casts sauvages (conversion d’un type vers un autre type). D’autre part, l’arithmétique des pointeurs embrouille souvent le débutant, car une incrémentation d’un pointeur modifie le pointeur en ajoutant la taille de l’objet pointé, et non pas 1 octet. Ce qui conduit à des bugs folkloriques. On se fait même avoir quand on a l’habitude
D’ailleurs j’ai souri en lisant ceci:
RGB=&(RGB[3]); au lieu de RGB=RGB+3; pour passer à un pixel suivant
Si RGB est une struct, ça risque de ne pas donner l’effet escompté 🙂
Et je pense que RGB est une struct. À moins que ce ne soit un simple pointeur *char.
Un programme pour l’auteur du premier post de ce thread, afin de bien montrer le risque de confusion:
[code]
#include<stdio.h>
#include<malloc.h>int main(void)
{
typedef struct { char r; char g; char b; } RGB;
RGB *rgb = malloc (1024);
RGB *save_rgb = rgb;
printf(« adresse de base rgb: %p\n », rgb);
rgb++;
printf(« adresse après incrémentation: %p\n », rgb);
rgb+=3;
printf(« adresse après addition de 3: %p\n », rgb);free(save_rgb);
return 0;
}[/code]
En résumé, je dirais que les pointeurs c’est pourri, et qu’il vaut mieux limiter leur utilisation à du passage de paramètre quand on est obligé de faire du C et non du C++.
Pour le reste, les algos de base sont déjà dans la Glib, alors pas la peine de réimplémenter ce qui est déjà fort bien fait (listes chainées, tableaux, queues…).
Sauf si bien sûr on pense que «recoder une libc», c’est formateur.
Et également, un tableau n’est PAS un pointeur en C !
http://www.levenez.com/lang/c/faq/fclc007.html
La simple insertion d’un élément dans une liste chaînée de glib fait déréférencer 0 et crasher le programme dès qu’on manque de mémoire…
Ce n’est que l’une des innombrables points qui font déconseiller l’utilisation de cette bibliothèque.Surtout que les listes exec fonctionnent parfaitement et que leur utilisation donne un code plus petit et plus rapide.
Pas besoin d’importer toutes les m*rdes Unix sur Amiga…Je constate qu’AI est rempli de programmeurs (on appelle çà désormais des développeurs il parait).
Je suis 100% pour l’apprentissage de la programmation par le C ou C++; mais je n’ai pas toujours raison. Comme d’autres ici, j’ai dans un premier tps appris en autodidacte dans mon adolescence, puis j’ai compris plus tard que je ne suis pas fait pour « coder » toute la journée, et encore moins pour pondre des schémas plus lourds que l’administration Française;)
Ca reste un hobby, donc un plaisir, et c’est suffisant ainsi.
De l'Amiga et bien d'autres ici:
http://tutosproc.blogspot.fr/
L’apprentissage de la programmation par le C ou le C++ ça a ses avantages… et ses inconvénients !!!
Avec le recul, je me dis que la progression qu’on avait en DUT n’était pas si mal (il y a 20 ans…) : Pascal pour être proche de l’algorithme « pur » et donc proche de la logique des milliards de programmes qui tournent sur Terre, et assembleur (68000) pour savoir comment tout cela est compris par la machine (on appelait d’ailleurs ce cours « architecture des ordinateurs »). Et ensuite on a attaqué le C, puis le C++… et enfin après le DUT (mais là c’était plus pour le concept…), on a vu du Java (mouais…), du LISP (Lot of Insipid and Stupid Parenthesis pour ceux qui en ont souffert… 🙂 ) et… et c’est déjà pas mal ! 😀
En tout cas, pour moi l’algo et l’assembleur c’est un peu comme le solfège dans la musique. On peut faire sans, mais en faisant avec on aura de toute façon de meilleures bases pour la suite. A moins d’être un Dieu de la programmation (ou de la musique ! 😀 )… Sinon on se perd dans tout ce bordel !
A500+ACA500 - A600+Vampire 2+indivision ECS - A1200+Vampire V2 1200 - Mac Mini 1.42 sous MOS - Just CPC 128k - CPC 6128 - Atari STE 4Mo/CosmosEx - Atari Falcon CT60/SuperVidel 🙂
C64C + 1541-II + Lecteur K7 + SD - Sharp X68000 CZ-601C 4Mo + CF - Sharp X68000 CZ-611C 10Mo + CF + ext. MIDI@modulo
Tu est d’une mauvaise fois AFFLIGEANTE
Je voulais souligner que les notations
RGB=&(RGB[3]); au lieu de RGB=RGB+3;
étaient équivalentes
Et tu sais elles restent équivalente qque soit la « taille » de RGB>je pense que RGB est une struct. À moins que ce ne soit un simple pointeur *char.
Qui donc pourrait croire celà (que c’est une struct et non pas un char*) puisque je dis que je passe au pixel suivant de cette manière, en faisant +3, donc fatalement j’avais char *RGB;>Et également, un tableau n’est PAS un pointeur en C !
>http://www.levenez.com/lang/c/faq/fclc007.htmlTa référence ne contient aucun argument valable il vaut mieux faire référence au « langage C » de Kerninghan et Ritchie pages 95 à 97
qui est bien moins tranché
« le nom d’un tableau est synonyme de l’adresse de son élément initial »
« En résumé,une expression comportant un tableau et un indice est équivalente à une autre écrite avec un pointeur et un déplacement »
Mais aussi à propos d’un tableau a
« un nom de tableau n’est pas une variable; donc des instructions telles a=pa; et a++ sont incorrectes »Mais surtout je voulais surtout dire que les tableaux en C n’ont pas de garde fou non plus en ce sens ils sont aussi con que des pointeurs…
char tab[10];
int x;
x=100;
tab[x]=0; ==> bangAlain
Alain
Vous êtes grands !
Je ne comprends déjà plus rien.
Enfin, pour l’instant.
Par contre, ce que je crois avoir compris, c’est que sur nos systèmes, il est préférable d’initialiser un pointeur à une adresse avant son utilisation. Sinon…. Ca plante. Je me trompe ?Tiki
Haha, oué, tu m’étonnes 😀
si t’envoie ton code vers une adresse aléatoire, au moyen d’un pointeur non initialisé, le comportement de ton programme sera totalement imprévisible (allant de « ça plante à tout les coups » à « je comprends pas, pourtant ça marche chez moi »).D’autant que l’Amiga est quand même super tolérant avec les dérapages mémoires. Faudra pas compter sur lui pour te signaler les sorties de l’espace mémoire de ton process (mais des outils existent pour remédier à ça).
@zzd10h :))))
J’pensais plutôt à http://eab.abime.net/showthread.php?t=65321J’enseigne le C à Toulouse donc je vais essayer de faire un résumé de ce que j’explique à mes étudiants.
Les passages de paramètres à un sous-programme en C ne marchent que par valeur.
C’est à dire qu’on recopie la valeur du paramètre effectif (ce qui est passé en paramètre quand tu appelle une fonction) dans le paramètre formel (la variable qui est utilisée dans la fonction).
Du coup, la seule solution pour modifier une variable dans une fonction est de passer son adresse en paramètre et de la manipuler avec une variable pointeur.
Pourquoi ne pas travailler directement sur la variable ?
Ceci n’est possible que si la variable est globale et dans ce cas le sous-programme ne servira qu’à modifier cette variable.
Or quand on écrit un sous-programme le but c’est qu’il puisse travailler avec n’importe qu’elle variable.
Sans pointeur :
int x; int y;
void fonction() {
x = x + 1;
}
void main() {
x = 1; y = 6;
fonction();
}
Ici la fonction ne peut ajouter 1 qu’à la variable x. Si je veux faire pareil sur la variable y il faut créer une autre fonction 🙁
Avec pointeur :
void fonction(int *p) {
*p = *p + 1;
}
void main() {
int x, y;
x=1; y=6;
fonction(&x); fonction(&y);
}
Ici lors du premier appel j’ajoute 1 à la variable x et la seconde fois j’ajoute 1 à la variable y. Ma fonction marche pour n’importe qu’elle variable entière.
Ce qui se passe : quand j’appelle la fonction je donne la valeur de l’adresse de la variable x (c’est à dire l’endroit où on stocke les données en mémoire). La variable pointeur p va donc contenir cette adresse. Quand je fais *p je manipule l’espace mémoire qui se trouve à l’adresse contenue dans p. Et donc *p vaut la valeur contenue à cet endroit en mémoire (qui correspond à l’endroit en mémoire de la variable x). Quand je fais *p = XXX; j’écris une nouvelle valeur à cet endroit en mémoire et donc je modifie le contenu de la variable x.
Bon bien sûr il y a plein de détails en plus. La taille de la zone mémoire manipulée dépend du type. Ici int correspond (en général) à 4 octets en mémoire. Donc quand je fais *p = XXX; je modifie en fait 4 octets en mémoire à partir de l’adresse contenue dans p.
Enfin dernier exemple de ce qui ne marche pas :
void fonction(int p) {
p = p + 1;
}
void main() {
int x, y;
x=1; y=6;
fonction(x);
}
Ici la variable p (le paramètre formel) reçoit la valeur de la variable x, puis la variable p est modifiée mais pas la variable x. Donc ça ne fait pas ce qu’on veut (augmenter de un la variable passée en paramètre effectif).
--
Patrice aka Hialmar
A500+/A600+aca620/A1200+aca1233
Membre de Silicium
- Vous devez être connecté pour répondre à ce sujet.
› Forums › AmigaOS, MorphOS et AROS › Développement › [Débutant en C] L'intérêt du pointeur.