178 votes

Qu'est-ce que les gens trouvent difficile à propos des pointeurs en C ?

D'après le nombre de questions posées ici, il est clair que les gens ont des problèmes assez fondamentaux lorsqu'ils se familiarisent avec les pointeurs et l'arithmétique des pointeurs.

Je suis curieux de savoir pourquoi. Ils ne m'ont jamais vraiment causé de problèmes majeurs (bien que j'aie appris leur existence au néolithique). Afin d'écrire de meilleures réponses à ces questions, j'aimerais savoir ce que les gens trouvent difficile.

Donc, si vous avez des difficultés avec les pointeurs, ou si vous en aviez récemment mais que vous avez soudainement "compris", quels sont les aspects des pointeurs qui vous ont posé problème ?

55 votes

Réponse hargneuse, exagérée, inutilement controversée, avec une part de vérité : Ils ont été handicapés - mentalement mutilés, je vous le dis - en apprenant d'abord un de ces langages de haut niveau "expressifs". Ils auraient dû commencer par programmer sur du métal nu comme Dieu et Daniel Boone l'avaient prévu !

3 votes

...et Programmer serait mieux parce qu'il sera se transformer en une discussion malgré tous vos efforts.

0 votes

C'est argumentatif et subjectif, cela génère des résultats N, mon difficile est votre facile. Cela fonctionnera probablement sur les programmeurs, mais nous n'y migrons pas encore ces questions car le site n'est pas sorti de la phase bêta.

152voto

Jeff Knecht Points 1778

Lorsque j'ai commencé à travailler avec eux, le plus gros problème que j'ai rencontré était la syntaxe.

int* ip;
int * ip;
int *ip;

sont toutes les mêmes.

mais :

int* ip1, ip2;  //second one isn't a pointer!
int *ip1, *ip2;

Pourquoi ? parce que la partie "pointeur" de la déclaration appartient à la variable, et non au type.

Et le déréférencement de la chose utilise une notation très similaire :

*ip = 4;  //sets the value of the thing pointed to by ip to '4'
x = ip;   //hey, that's not '4'!
x = *ip;  //ahh... there's that '4'

Sauf lorsque vous avez réellement besoin d'obtenir un pointeur... alors vous utilisez une esperluette !

int *ip = &x;

Hourra pour la cohérence !

Puis, apparemment juste pour faire les cons et prouver leur intelligence, beaucoup de développeurs de bibliothèques utilisent des pointeurs vers des pointeurs vers des pointeurs, et s'ils attendent un tableau de ces choses, pourquoi ne pas simplement passer un pointeur vers cela aussi.

void foo(****ipppArr);

pour appeler ceci, j'ai besoin de l'adresse du tableau de pointeurs vers des pointeurs vers des pointeurs d'ints :

foo(&(***ipppArr));

Dans six mois, lorsque je devrai maintenir ce code, je passerai plus de temps à essayer de comprendre ce que tout cela signifie qu'à réécrire depuis le début. (oui, j'ai probablement mal interprété la syntaxe - ça fait un moment que je n'ai rien fait en C. Ça me manque un peu, mais je suis un peu massochiste)

23 votes

Votre commentaire sur le premier, >>*ip = 4 ; //sets the value of ip to '4'<< est faux. Il devrait être >>//sets the value of the thing pointed at by ip to '4'.

2 votes

C'est ce que j'aime dans l'assemblage. Vous avez un DWORD et vous pouvez le traiter comme un int, un int*, un pointeur vers n'importe quelle structure ou fonction, et tout sans caste.

0 votes

@ruslik : C'est très peu sûr, en dehors de toute autre chose. Si votre DWORD est un int, vous ne pouvez pas soudainement l'appeler un int*- parce que maintenant votre programme se plante.

87voto

jkerian Points 8328

Je pense que les gens vont un peu trop loin dans leurs réponses. Une compréhension de l'ordonnancement, des opérations réelles du CPU ou de la gestion de la mémoire au niveau de l'assemblage n'est pas vraiment nécessaire.

Lorsque j'enseignais, j'ai constaté que les lacunes suivantes dans la compréhension des élèves étaient la source la plus courante de problèmes :

  1. Stockage en tas ou en pile. Il est tout simplement stupéfiant de voir combien de personnes ne comprennent pas cela, même de manière générale.
  2. Cadres d'empilage. Juste le concept général d'une section dédiée de la pile pour les variables locales, ainsi que la raison pour laquelle il s'agit d'une "pile"... les détails tels que le stockage de l'emplacement de retour, les détails du gestionnaire d'exception et les registres précédents peuvent être laissés en toute sécurité jusqu'à ce que quelqu'un essaie de construire un compilateur.
  3. "Le Casting change juste les versions des opérateurs ou la place que le compilateur accorde à un morceau particulier de mémoire. Vous savez que vous avez affaire à ce problème lorsque les gens parlent de "quelle variable (primitive) X vraiment est".

La plupart de mes étudiants étaient capables de comprendre un dessin simplifié d'un morceau de mémoire, généralement la section des variables locales de la pile à la portée actuelle. En général, le fait de donner des adresses fictives explicites aux différents emplacements a aidé.

Je pense qu'en résumé, je dis que si vous voulez comprendre les pointeurs, vous devez comprendre les variables et ce qu'elles sont réellement dans les architectures modernes.

1 votes

Cela ressemble exactement à mon professeur pour mon cours d'informatique 1 et 2 (structures de données). Le tout premier jour, nous avons rempli des modèles de mémoire pour certains programmes et nous avons suivi le déroulement des programmes. Les adresses fictives pour le tas ont aidé, et le fait d'être constamment interrogé/testé sur ces modèles aide vraiment à comprendre les pointeurs. Nous en avons même suivi certains dans le cours sur les structures de données pour des études de cas.

15 votes

À mon avis, la compréhension de la pile et du tas est aussi inutile que les détails de bas niveau du CPU. La pile et le tas sont des détails d'implémentation. La spécification ISO C ne mentionne pas une seule fois le mot "pile" et K&R non plus.

1 votes

Honnêtement, tu n'as plus besoin de le savoir. Ils avaient l'habitude d'enseigner le latin et le grec à l'école. Ce n'est plus le cas. Bien sûr, certaines personnes peuvent avoir besoin de les connaître, mais dans l'ensemble, ce n'est pas nécessaire.

52voto

Robert Harvey Points 103562

Pour bien comprendre les pointeurs, il faut connaître l'architecture de la machine sous-jacente.

Aujourd'hui, de nombreux programmeurs ne savent pas comment fonctionne leur machine, tout comme la plupart des gens qui savent conduire une voiture ne savent rien du moteur.

0 votes

Joli avec le point de vue neutre, là.

18 votes

@dmckee : Eh bien, ai-je tort ? Combien de programmeurs Java pourraient gérer un défaut de segmentation ?

1 votes

@Robert Harvey : How many Java programmers could deal with a segfault? Et c'en est fini du point de vue neutre ! ;-) (je ne dis pas que je ne suis pas d'accord avec votre commentaire)

44voto

David Titarenco Points 17148

Lorsqu'il s'agit de pointeurs, les personnes qui s'y perdent sont généralement dans l'un des deux camps. J'ai été (suis ?) dans les deux.

Le site array[] foule

Ce sont les personnes qui ne savent pas comment passer de la notation par pointeur à la notation par tableau (ou qui ne savent même pas qu'elles sont liées). Voici quatre façons d'accéder aux éléments d'un tableau :

  1. notation de tableau (indexation) avec le nom du tableau
  2. notation de tableau (indexation) avec le nom du pointeur
  3. la notation du pointeur (le *) avec le nom du pointeur
  4. la notation du pointeur (le *) avec le nom du tableau

    int vals[5] = {10, 20, 30, 40, 50}; int *ptr; ptr = vals;

    array element pointer notation number vals notation

    vals[0] 0 10 (ptr + 0) ptr[0] (vals + 0)

    vals[1] 1 20 (ptr + 1) ptr[1] (vals + 1)

    vals[2] 2 30 (ptr + 2) ptr[2] (vals + 2)

    vals[3] 3 40 (ptr + 3) ptr[3] (vals + 3)

    vals[4] 4 50 (ptr + 4) ptr[4] (vals + 4)

L'idée ici est que l'accès aux tableaux via des pointeurs semble assez simple et direct, mais une tonne de choses très compliquées et intelligentes peuvent être faites de cette façon. Certaines d'entre elles peuvent laisser les programmeurs C/C++ expérimentés perplexes, sans parler des débutants inexpérimentés.

Le site reference to a pointer y pointer to a pointer foule

Este est un excellent article qui explique la différence et que je citerai et dont je volerai du code :)

À titre de petit exemple, il peut être très difficile de voir exactement ce que l'auteur voulait faire si vous tombez sur quelque chose comme ceci :

//function prototype
void func(int*& rpInt); // I mean, seriously, int*& ??

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  ....
  return 0;
}

Ou, dans une moindre mesure, quelque chose comme ça :

//function prototype
void func(int** ppInt);

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(&pvar);
  ....
  return 0;
}

Au bout du compte, que résolvons-nous vraiment avec tout ce charabia ? Rien.

Maintenant, nous avons vu la syntaxe de ptr-to-ptr et ref-to-ptr. Existe-t-il avantages de l'une par rapport à l'autre ? Je crains que non. L'utilisation de l'un des deux, pour certains programmeurs sont juste préférences personnelles. Certains qui utilisent ref-to-ptr disent que la syntaxe est plus "propre". tandis que d'autres qui utilisent ptr-to-ptr, disent que que la syntaxe ptr-to-ptr rend plus clair pour pour ceux qui lisent ce que vous faites.

Cette complexité et la apparemment L'interchangeabilité (apparente en gras) avec les références, qui est souvent un autre inconvénient des pointeurs et une erreur des nouveaux arrivants, rend la compréhension des pointeurs difficile. Il est également important de comprendre, par souci d'achèvement, que les pointeurs vers les références sont illégaux en C et C++ pour des raisons confuses qui vous amènent à lvalue - rvalue sémantique.

Comme l'a fait remarquer une réponse précédente, il arrive souvent que des programmeurs de haut niveau pensent qu'ils sont intelligents en utilisant le système ******awesome_var->lol_im_so_clever() et la plupart d'entre nous sont probablement coupables d'écrire de telles atrocités à certains moments, mais ce n'est tout simplement pas du bon code, et il n'est certainement pas maintenable.

Eh bien, cette réponse s'est avérée plus longue que je ne l'avais espéré...

6 votes

Je pense que vous avez peut-être donné une réponse C++ à une question C ici... au moins la deuxième partie.

0 votes

Les pointeurs vers les pointeurs s'appliquent également au C :p

1 votes

Hein ? Je ne vois des pointeurs sur des pointeurs que lorsque je fais passer des tableaux - votre deuxième exemple n'est pas vraiment applicable à la plupart des codes C décents. De plus, vous entraînez le C dans le désordre du C++ - les références en C n'existent pas.

30voto

John Bode Points 33046

Je blâme personnellement la qualité des documents de référence et les personnes qui enseignent ; la plupart des concepts en C (mais notamment ) sont tout simplement enseigné à mal. Je continue de menacer d'écrire mon propre livre C (intitulé La dernière chose dont le monde a besoin est un autre livre sur le langage de programmation C. ), mais je n'ai ni le temps ni la patience de le faire. Alors je traîne ici et je lance des citations aléatoires de la norme aux gens.

Il y a aussi le fait que lorsque C a été initialement conçu, il était supposé vous avez compris l'architecture des machines à un niveau assez détaillé simplement parce qu'il n'y avait aucun moyen de l'éviter dans votre travail quotidien (la mémoire était si étroite et les processeurs si lents que vous deviez comprendre comment ce que vous écriviez affectait les performances).

3 votes

Oui. 'int foo = 5 ; int *pfoo = &foo ; Vous voyez comme c'est utile ? OK, on avance...' Je n'ai pas vraiment utilisé de pointeurs jusqu'à ce que j'écrive ma propre bibliothèque de listes à double lien.

2 votes

+1. J'avais l'habitude de donner des cours particuliers à des étudiants de CS100 et un grand nombre de leurs problèmes étaient résolus simplement en expliquant les pointeurs de manière compréhensible.

1 votes

+1 pour le contexte historique. Ayant commencé bien après cette époque, cela ne m'a jamais effleuré.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X