1. Einführung
Wer von der Java-Programmierung kommt, wird sich in C++ sehr schnell mit einem Konzept konfrontiert sehen, dass er so vorher noch nicht kannte, nämlich das der Pointer. Ein Pointer ist zunächst einmal nichts anderes als ein Zeiger.
Doch worauf zeigt ein Pointer?
2. Speicheradressen und Werte
Ganz einfach! Ein Pointer zeigt auf eine Speicheradresse im Arbeitsspeicher. Du musst wissen, dass dein Programm zur Laufzeit in den Arbeitsspeicher (also den RAM) geladen wird und Variablen dort über eine Speicheradresse erreicht werden können. Betrachte den folgenden Ausschnitt eines Arbeitsspeichers:
Jeder dieser Blöcke besitzt eine Größe von einem Byte (also 8 Bit). Möchtest du eine Variable vom Typ Integer in C++ definieren, wird für sie ein bestimmter Platz im Arbeitsspeicher reserviert:
int die_antwort = 42;
Wie viel Platz genau hängt von deinem Betriebssystem ab. Entweder 16-, 32- oder 64-Bit. Wir betrachten ein 32-Bit-System, d. h. eine Integer-Variable nimmt 32-Bits bzw. 4 Bytes (also 4 Blöcke) ein:
Die einzelnen Blöcke werden mit einer Speicheradresse versehen, die dann wiederum mit Pointern angesprochen werden können:
Wenn du also einen Pointer definierst, zeigt er auf eine dieser Speicheradressen, wie z. B. 0xdeadbeef. Um einen Pointer auf die bereits definierte Integer-Variable zu machen, musst du lediglich einen Stern entweder direkt vor den Variablennamen oder hinter das Keyword int setzen. Die Adresse, auf die der Pointer zeigen soll, erhältst du durch Zuweisung der Variable mit vorangestelltem & an den Pointer:
int* pointer_auf_die_antwort = &die_antwort;
Der Pointer "pointer_auf_die_antwort" zeigt nun auf die Speicheradresse 0xdeadbeef. Mit dem Befehl std::cout kannst du dir diese Speicheradresse auch ausgeben lassen:
std::cout << pointer_auf_die_antwort; // liefert die Speicheradresse, auf die der Pointer zeigt.
Als Ergebnis wird (in diesem Fall) die Adresse 0xdeadbeef auf der Konsole ausgegeben.
Mit Pointern sind viele spannende Dinge möglich. Man kann mit ihnen u. a. auch rechnen, was wir in einem anderen Tutorial zur Pointer-Arithmetik auch machen werden.
Bislang weißt du allerdings nur, wie du einen Pointer definieren kannst, der dann auf eine bestimmte Speicheradresse zeigt. Was ist aber, wenn du den Wert, der an der besagten Adresse gespeichert ist, auslesen oder verändern willst? Du würdest doch auch nicht zur Adresse von einem deiner Freunde fahren und dann vor der Haustüren warten und nichts machen. Das wäre genauso spannend wie Pointer zu definieren und diese nicht zu nutzen.
Um auf den Wert an der Speicheradresse des Pointers zugreifen zu können, musst du vor dem Pointer wieder den Stern notieren. Damit hast du lesenden und schreibenden Zugriff auf den an der Adresse 0xdeadbeef gespeicherten Inhalt. Der Stern fungiert an dieser Stelle quasi als eine Art Schlüssel zum Inhalt an der Speicheradresse. Du kannst den Wert entweder ausgeben, verändern oder an anderer Stelle nutzen:
std::cout << *pointer_auf_die_antwort; // Gibt 42 aus.
*pointer_auf_die_antwort = *pointer_auf_die_antwort + 2; // Ändert den Wert an der Speicheradresse auf 44
int twentytwo = *pointer_auf_die_antwort / 2; // Weist twentytwo den Wert 22 zu.
Wenn du den Stern weglässt, änderst du die Adresse, auf die der Pointer zeigst, wodurch der Pointer ggf. „ins Leere“ zeigt. Das kann man übrigens in manchen Fällen auch wollen. Am Anfang deiner Entwicklerkarriere wirst du aber vermutlich primär an den Werten hinter den jeweiligen Adressen interessiert sein. Hierzu dann aber mehr im Video zur Pointer-Arithmetik.
3. Welchen Vorteil haben Pointer?Du kannst mit einem Pointer im Vergleich zu anderen Programmiersprachen einiges an Performance herausholen. Neben diesem doch etwas schwammig klingenden Vorteil gibt es noch einen, den du recht leicht einsehen wirst. Wenn du z. B. den Wert einer Variable, die du von einer Methode verändert haben möchtest, dann ist dieser nur innerhalb der Methode gültig. Innerhalb der Methode ist dieser neue Wert gültig, außerhalb jedoch nicht. Die Rede ist hier übrigens nicht von Objektvariablen! Übergibst du der Methode hingegen einen Pointer auf die Variable, dann kannst du auf die gezeigte Art und Weise den dahinterstehenden Wert auch für außerhalb der Methode gültig ändern.
Betrachte dazu das folgende Programm zum verändern von Kontoständen. In der main( ) wird zuerst eine Variable "kontostand" definiert. Dieser Kontostand soll dann durch die Funktion geld_verdienen( ) erhöht werden. Diese Funktion nimmt eine Variable vom Typ int entgegen und rechnet 100€ drauf.
int main() {
int kontostand = 20;
geld_verdienen(kontostand)
}
void geld_verdienen(int kontostand){
kontostand = kontostand + 100;
}
Wenn du dir den Kontostand nach dem Aufruf ausgeben lässt, wirst du keine Veränderung feststellen:
std::cout << "Ohne Pointer: " << kontostand << "€\n"; // Liefert 20€.
Da war die ganze Arbeit völlig umsonst. Du könntest natürlich auch einfach ein Return-Statement am Ende der Funktion einbauen, doch an dieser Stelle geht es darum, die Eigenschaften von Pointern zu verstehen.
Also auf ein Neues! Die Funktion geld_verdienen( ) erhält nun einen Zwilling, der einen Pointer statt eines Integer-Werts erhält. Mit dem Stern-Operator wird der Wert, der an der Adresse, auf die der übergebene Pointer zeigt, gespeichert ist, direkt zugegriffen und 100€ draufgerechnet:
void geld_verdienen(int* kontostand){
*kontostand = *kontostand + 100;
}
Diesmal wird statt des Kontostands als Integer ein Pointer auf die Adresse, wo der Kontostand gespeichert ist, übergeben. Mit dem vorangestellten &, kannst du dem Pointer diese Adresse zuweisen und den Aufruf vornehmen:
int* kontostand_pointer = &kontostand;
geld_verdienen(kontostand_pointer);
Bei der Ausgabe des Kontostands wird nun das gewünschte Ergebnis angezeigt:
std::cout << "Nach Pointer: " << kontostand << "€\n"; // Liefert 120€.
Dieser Artikel hat 50 Bonuspunkte erhalten. Schreib auch du einen Artikel.
Autor: Florian André Dalwigk