J'ai récemment commencé à apprendre le C ++, et comme la plupart des gens (selon ce que j'ai lu), j'ai du mal avec les pointeurs.
Pas dans le sens traditionnel, je comprends ce qu'ils sont, pourquoi ils sont utilisés et comment peuvent-ils être utiles, mais je ne peux pas comprendre comment l'incrémentation des pointeurs serait utile, quelqu'un peut-il expliquer comment l'incrémentation d'un pointeur est un concept utile et idiomatique C ++?
Cette question est venue après que j'ai commencé à lire le livre A Tour of C ++ de Bjarne Stroustrup, on m'a recommandé ce livre, parce que je connais assez bien Java, et les gars de Reddit m'ont dit que ce serait un bon livre de `` basculement '' .
Réponses:
Lorsque vous avez un tableau, vous pouvez configurer un pointeur pour pointer vers un élément du tableau:
Indique ici
p
le premier élément dea
, qui esta[0]
. Vous pouvez maintenant incrémenter le pointeur pour pointer vers l'élément suivant:Maintenant , les
p
points au deuxième élément,a[1]
. Vous pouvez accéder à l'élément ici en utilisant*p
. C'est différent de Java où vous devez utiliser une variable d'index entier pour accéder aux éléments d'un tableau.L'incrémentation d'un pointeur en C ++ où ce pointeur ne pointe pas vers un élément d'un tableau est un comportement non défini .
la source
L'incrémentation des pointeurs est idiomatique en C ++, car la sémantique des pointeurs reflète un aspect fondamental de la philosophie de conception derrière la bibliothèque standard C ++ (basée sur la STL d'Alexander Stepanov )
Le concept important ici est que la STL est conçue autour de conteneurs, d'algorithmes et d'itérateurs. Les pointeurs sont simplement des itérateurs .
Bien sûr, la possibilité d'incrémenter (ou d'ajouter / de soustraire) des pointeurs remonte à C. De nombreux algorithmes de manipulation de chaîne C peuvent être écrits simplement en utilisant l'arithmétique des pointeurs. Considérez le code suivant:
Ce code utilise l'arithmétique du pointeur pour copier une chaîne C terminée par un caractère nul. La boucle se termine automatiquement lorsqu'elle rencontre le null.
Avec C ++, la sémantique des pointeurs est généralisée au concept d' itérateurs . La plupart des conteneurs C ++ standard fournissent des itérateurs, accessibles via les fonctions membres
begin
etend
. Les itérateurs se comportent comme des pointeurs, en ce sens qu'ils peuvent être incrémentés, déréférencés et parfois décrémentés ou avancés.Pour parcourir un
std::string
, nous dirions:Nous incrémentons l'itérateur comme nous incrémenterions un pointeur sur une chaîne en C simple. La raison pour laquelle ce concept est puissant est que vous pouvez utiliser des modèles pour écrire des fonctions qui fonctionneront pour tout type d'itérateur qui répond aux exigences de concept nécessaires. Et c'est la puissance de la STL:
Ce code copie une chaîne dans un vecteur. La
copy
fonction est un modèle qui fonctionnera avec tout itérateur qui prend en charge l'incrémentation (qui inclut des pointeurs simples). Nous pourrions utiliser la mêmecopy
fonction sur une chaîne C simple:Nous pourrions utiliser
copy
sur unstd::map
ou unstd::set
ou tout conteneur personnalisé prenant en charge les itérateurs.Notez que les pointeurs sont un type spécifique d'itérateur: itérateur à accès aléatoire , ce qui signifie qu'ils prennent en charge l'incrémentation, la décrémentation et l'avancement avec l' opérateur
+
et-
. D'autres types d'itérateurs ne prennent en charge qu'un sous-ensemble de sémantique de pointeur: un itérateur bidirectionnel prend en charge au moins l'incrémentation et la décrémentation; un itérateur direct prend en charge au moins l'incrémentation. (Tous les types d'itérateurs prennent en charge le déréférencement.) Lacopy
fonction nécessite un itérateur qui prend au moins en charge l'incrémentation.Vous pouvez lire sur les différents concepts de iterator ici .
Ainsi, l'incrémentation de pointeurs est une façon idiomatique C ++ d'itérer sur un tableau C ou d'accéder à des éléments / décalages dans un tableau C.
la source
L'arithmétique du pointeur est en C ++ parce qu'elle était en C. L'arithmétique du pointeur est en C parce que c'est un idiome normal dans l' assembleur .
Il existe de nombreux systèmes où "increment register" est plus rapide que "load constant value 1 and add to register". De plus, plusieurs systèmes vous permettent de "charger DWORD dans A à partir de l'adresse spécifiée dans le registre B, puis d'ajouter sizeof (DWORD) à B" dans une seule instruction. De nos jours, vous pourriez vous attendre à ce qu'un compilateur d'optimisation trie cela pour vous, mais ce n'était pas vraiment une option en 1973.
C'est essentiellement la même raison pour laquelle les tableaux C ne sont pas vérifiés et que les chaînes C n'ont pas de taille intégrée: le langage a été développé sur un système où chaque octet et chaque instruction comptent.
la source