Ich habe gerade erst angefangen, C ++ zu lernen, und wie die meisten Leute (nach dem, was ich gelesen habe) habe ich mit Zeigern zu kämpfen.
Nicht im herkömmlichen Sinne verstehe ich, was sie sind und warum sie verwendet werden und wie sie nützlich sein können. Ich kann jedoch nicht verstehen, wie nützlich das Inkrementieren von Zeigern ist. Kann jemand eine Erklärung liefern, wie das Inkrementieren eines Zeigers a ist? sinnvolles Konzept und idiomatisches C ++?
Diese Frage kam, nachdem ich angefangen hatte, das Buch A Tour of C ++ von Bjarne Stroustrup zu lesen. Mir wurde dieses Buch empfohlen, weil ich mit Java ziemlich vertraut bin, und die Jungs von Reddit sagten mir, dass es ein gutes "Umstellungsbuch" wäre .
Antworten:
Wenn Sie über ein Array verfügen, können Sie einen Zeiger einrichten, der auf ein Element des Arrays verweist:
Hier
p
zeigt auf das erste Element vona
, welches ista[0]
. Jetzt können Sie den Zeiger inkrementieren, um auf das nächste Element zu zeigen:Zeigt nun
p
auf das zweite Elementa[1]
. Hier können Sie mit auf das Element zugreifen*p
. Dies unterscheidet sich von Java, bei dem Sie eine ganzzahlige Indexvariable verwenden müssten, um auf Elemente eines Arrays zuzugreifen.Das Inkrementieren eines Zeigers in C ++, bei dem dieser Zeiger nicht auf ein Element eines Arrays zeigt, ist undefiniertes Verhalten .
quelle
Das Inkrementieren von Zeigern ist idiomatisch in C ++, da die Zeigersemantik einen grundlegenden Aspekt der Designphilosophie hinter der C ++ - Standardbibliothek widerspiegelt (basierend auf der STL von Alexander Stepanov ).
Das wichtige Konzept hierbei ist, dass die STL auf Containern, Algorithmen und Iteratoren basiert. Zeiger sind einfach Iteratoren .
Natürlich geht die Fähigkeit, Zeiger zu inkrementieren (oder zu subtrahieren), auf C zurück. Viele C-String-Manipulationsalgorithmen können einfach unter Verwendung von Zeigerarithmetik geschrieben werden. Betrachten Sie den folgenden Code:
Dieser Code verwendet Zeigerarithmetik, um eine nullterminierte C-Zeichenfolge zu kopieren. Die Schleife wird automatisch beendet, wenn sie auf die Null stößt.
In C ++ wird die Zeigersemantik auf das Konzept der Iteratoren verallgemeinert . Die meisten Standard-C ++ - Container bieten Iteratoren, auf die über die Funktionen
begin
undend
member zugegriffen werden kann. Iteratoren verhalten sich wie Zeiger, da sie inkrementiert, dereferenziert und manchmal dekrementiert oder erweitert werden können.Um über eine zu iterieren
std::string
, würden wir sagen:Wir erhöhen den Iterator genauso, wie wir einen Zeiger auf einen einfachen C-String erhöhen würden. Der Grund für die Leistungsfähigkeit dieses Konzepts liegt darin, dass Sie Vorlagen zum Schreiben von Funktionen verwenden können, die für jeden Iteratortyp geeignet sind, der die erforderlichen Konzeptanforderungen erfüllt. Und das ist die Kraft der STL:
Dieser Code kopiert eine Zeichenfolge in einen Vektor. Die
copy
Funktion ist eine Vorlage, die mit jedem Iterator funktioniert , der Inkrementierung unterstützt (einschließlich einfacher Zeiger). Wir könnten die gleichecopy
Funktion für einen einfachen C-String verwenden:Wir könnten
copy
einenstd::map
oder einenstd::set
oder einen beliebigen benutzerdefinierten Container verwenden, der Iteratoren unterstützt.Beachten Sie, dass Zeiger eine bestimmte Art von Iterator sind: Iterator mit wahlfreiem Zugriff. Dies bedeutet, dass sie das Inkrementieren, Dekrementieren und Vorrücken mit dem Operator
+
und unterstützen-
. Andere Iteratortypen unterstützen nur eine Teilmenge der Zeigersemantik: Ein bidirektionaler Iterator unterstützt mindestens das Inkrementieren und Dekrementieren. Ein Forward-Iterator unterstützt mindestens das Inkrementieren. (Alle Iteratortypen unterstützen die Dereferenzierung.) Für diecopy
Funktion ist ein Iterator erforderlich, der zumindest das Inkrementieren unterstützt.Sie können über verschiedene Iterator Konzepte lesen hier .
Das Inkrementieren von Zeigern ist also eine idiomatische C ++ - Methode, um über ein C-Array zu iterieren oder auf Elemente / Offsets in einem C-Array zuzugreifen.
quelle
Zeigerarithmetik ist in C ++, weil es in C war. Zeigerarithmetik ist in C, weil es eine normale Redewendung in Assembler ist .
Es gibt viele Systeme, in denen "Inkrementregister" schneller ist als "Konstantenwert 1 laden und zum Register hinzufügen". Darüber hinaus können Sie in einigen Systemen mit einem einzigen Befehl "DWORD von der in Register B angegebenen Adresse in A laden und anschließend sizeof (DWORD) zu B hinzufügen". Heutzutage könnte man erwarten, dass ein optimierender Compiler dies für Sie regelt, aber das war 1973 eigentlich keine Option.
Dies ist im Grunde der gleiche Grund, warum C-Arrays nicht gebunden sind und in C-Strings keine Größe eingebettet ist: Die Sprache wurde auf einem System entwickelt, auf dem jedes Byte und jeder Befehl gezählt wurde.
quelle