Zeiger sind symbolische Darstellungen von Adressen. Sie ermöglichen es Programmen, Call-by-Reference zu simulieren sowie dynamische Datenstrukturen zu erstellen und zu manipulieren. Das Durchlaufen von Elementen in Arrays oder anderen Datenstrukturen ist eine der Hauptanwendungen von Zeigern.
Die Adresse der Variablen, mit der Sie arbeiten, wird der Zeigervariablen zugewiesen, die auf denselben Datentyp zeigt (z. B. int oder string).
Python neue Zeile
Syntax:
datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
Wie verwende ich einen Zeiger?
- Definieren Sie eine Zeigervariable
- Zuweisen der Adresse einer Variablen zu einem Zeiger mithilfe des unären Operators (&), der die Adresse dieser Variablen zurückgibt.
- Zugriff auf den in der Adresse gespeicherten Wert mithilfe eines unären Operators (*), der den Wert der Variablen zurückgibt, die sich an der durch ihren Operanden angegebenen Adresse befindet.
Der Grund, warum wir den Datentyp einem Zeiger zuordnen, ist dass es weiß, in wie vielen Bytes die Daten gespeichert sind . Wenn wir einen Zeiger erhöhen, erhöhen wir den Zeiger um die Größe des Datentyps, auf den er zeigt.
C++ // C++ program to illustrate Pointers #include using namespace std; void geeks() { int var = 20; // declare pointer variable int* ptr; // note that data type of ptr and var must be same ptr = &var; // assign the address of a variable to a pointer cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at var = ' << var << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; } // Driver program int main() { geeks(); return 0; }> Ausgabe
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>
Referenzen und Hinweise
Es gibt drei Möglichkeiten, C++-Argumente an eine Funktion zu übergeben:
- Call-By-Value
- Call-By-Reference mit einem Zeigerargument
- Call-By-Reference mit einem Referenzargument
// C++ program to illustrate call-by-methods #include using namespace std; // Pass-by-Value int square1(int n) { // Address of n in square1() is not the same as n1 in // main() cout << 'address of n1 in square1(): ' << &n << '
'; // clone modified inside the function n *= n; return n; } // Pass-by-Reference with Pointer Arguments void square2(int* n) { // Address of n in square2() is the same as n2 in main() cout << 'address of n2 in square2(): ' << n << '
'; // Explicit de-referencing to get the value pointed-to *n *= *n; } // Pass-by-Reference with Reference Arguments void square3(int& n) { // Address of n in square3() is the same as n3 in main() cout << 'address of n3 in square3(): ' << &n << '
'; // Implicit de-referencing (without '*') n *= n; } void geeks() { // Call-by-Value int n1 = 8; cout << 'address of n1 in main(): ' << &n1 << '
'; cout << 'Square of n1: ' << square1(n1) << '
'; cout << 'No change in n1: ' << n1 << '
'; // Call-by-Reference with Pointer Arguments int n2 = 8; cout << 'address of n2 in main(): ' << &n2 << '
'; square2(&n2); cout << 'Square of n2: ' << n2 << '
'; cout << 'Change reflected in n2: ' << n2 << '
'; // Call-by-Reference with Reference Arguments int n3 = 8; cout << 'address of n3 in main(): ' << &n3 << '
'; square3(n3); cout << 'Square of n3: ' << n3 << '
'; cout << 'Change reflected in n3: ' << n3 << '
'; } // Driver program int main() { geeks(); }> Ausgabe
address of n1 in main(): 0x7fffa7e2de64 address of n1 in square1(): 0x7fffa7e2de4c Square of n1: 64 No change in n1: 8 address of n2 in main(): 0x7fffa7e2de68 address of n2 in square2(): 0x7fffa7e2de68 Square of n2: 64 Change reflected in n2: 64 address of n3 in main(): 0x7fffa7e2de6c address of n3 in square3(): 0x7fffa7e2de6c Square of n3: 64 Change reflected in n3: 64>
In C++ werden Argumente standardmäßig als Wert übergeben und die in der aufgerufenen Funktion vorgenommenen Änderungen werden nicht in der übergebenen Variablen widergespiegelt. Die Änderungen werden in einen Klon übernommen, der von der aufgerufenen Funktion vorgenommen wird. Wenn Sie die Originalkopie direkt ändern möchten (insbesondere bei der Übergabe großer Objekte oder Arrays) und/oder den Aufwand des Klonens vermeiden möchten, verwenden wir die Übergabe per Referenz. Pass-by-Reference mit Referenzargumenten erfordert keine umständliche Syntax zum Referenzieren und Dereferenzieren.
- Funktionszeiger in C
- Zeiger auf eine Funktion
Array-Name als Zeiger
Ein Array name enthält die Adresse des ersten Elements des Arrays, das wie ein konstanter Zeiger fungiert. Das bedeutet, dass die im Array-Namen gespeicherte Adresse nicht geändert werden kann. Wenn wir zum Beispiel ein Array mit dem Namen val haben, dann val Und &val[0] austauschbar verwendet werden können.
C++ // C++ program to illustrate Array Name as Pointers #include using namespace std; void geeks() { // Declare an array int val[3] = { 5, 10, 20 }; // declare pointer variable int* ptr; // Assign the address of val[0] to ptr // We can use ptr=&val[0];(both are same) ptr = val; cout << 'Elements of the array are: '; cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2]; } // Driver program int main() { geeks(); }> Ausgabe
Elements of the array are: 5 10 20>
Wenn der Zeiger ptr als Argument an eine Funktion gesendet wird, kann auf ähnliche Weise auf das Array val zugegriffen werden. Zeiger vs. Array
Zeigerausdrücke und Zeigerarithmetik
Eine begrenzte Anzahl von Arithmetik Operationen können auf folgende Zeiger ausgeführt werden:
- inkrementiert ( ++ )
- dekrementiert ( — )
- Eine Ganzzahl kann zu einem Zeiger hinzugefügt werden ( + oder += )
- eine Ganzzahl kann von einem Zeiger subtrahiert werden ( – oder -= )
- Differenz zwischen zwei Zeigern (p1-p2)
( Notiz: Zeigerarithmetik ist bedeutungslos, es sei denn, sie wird auf einem Array durchgeführt.)
C++ // C++ program to illustrate Pointer Arithmetic #include using namespace std; void geeks() { // Declare an array int v[3] = { 10, 100, 200 }; // declare pointer variable int* ptr; // Assign the address of v[0] to ptr ptr = v; for (int i = 0; i < 3; i++) { cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; // Increment pointer ptr by 1 ptr++; } } // Driver program int main() { geeks(); }> Ausgabe
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
Erweiterte Zeigernotation
Betrachten Sie die Zeigernotation für die zweidimensionalen numerischen Arrays. Betrachten Sie die folgende Erklärung
int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>Im Allgemeinen entspricht nums[ i ][ j ] *(*(nums+i)+j)
Pyspark SQL
Zeiger und String-Literale
String-Literale sind Arrays, die nullterminierte Zeichenfolgen enthalten. Zeichenfolgenliterale sind Arrays vom Typ „Zeichen“ plus abschließendem Nullzeichen, wobei jedes Element vom Typ „const char“ ist (da Zeichen einer Zeichenfolge nicht geändert werden können).
>
Dadurch wird ein Array mit der Literaldarstellung für geek deklariert, und dann wird ptr ein Zeiger auf sein erstes Element zugewiesen. Wenn wir uns vorstellen, dass geek an den Speicherorten gespeichert wird, die bei Adresse 1800 beginnen, können wir die vorherige Deklaration wie folgt darstellen:

Da sich Zeiger und Arrays in Ausdrücken gleich verhalten, kann ptr verwendet werden, um auf die Zeichen eines String-Literals zuzugreifen. Zum Beispiel:
char ptr = 0; char x = *(ptr+3); char y = ptr[3];>
Hier enthalten sowohl x als auch y k, gespeichert bei 1803 (1800+3).
Sortieralgorithmen für Einfügungen
Zeiger auf Zeiger
In C++ können wir einen Zeiger auf einen Zeiger erstellen, der wiederum auf Daten oder einen anderen Zeiger zeigen kann. Die Syntax erfordert beim Deklarieren des Zeigers einfach den unären Operator (*) für jede Indirektionsebene.
char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>
Hier zeigt b auf ein Zeichen, das „g“ speichert, und c zeigt auf den Zeiger b.
Leere Zeiger
Dies ist ein spezieller Zeigertyp, der in C++ verfügbar ist und das Fehlen eines Typs darstellt. Leere Hinweise sind Zeiger, die auf einen Wert verweisen, der keinen Typ hat (und damit auch eine unbestimmte Länge und unbestimmte Dereferenzierungseigenschaften). Das bedeutet, dass Void-Zeiger eine große Flexibilität haben, da sie auf jeden Datentyp verweisen können. Diese Flexibilität zahlt sich aus. Diese Zeiger können nicht direkt dereferenziert werden. Sie müssen zunächst in einen anderen Zeigertyp umgewandelt werden, der auf einen konkreten Datentyp zeigt, bevor sie dereferenziert werden.
C++ // C++ program to illustrate Void Pointer #include using namespace std; void increase(void* data, int ptrsize) { if (ptrsize == sizeof(char)) { char* ptrchar; // Typecast data to a char pointer ptrchar = (char*)data; // Increase the char stored at *ptrchar by 1 (*ptrchar)++; cout << '*data points to a char' << '
'; } else if (ptrsize == sizeof(int)) { int* ptrint; // Typecast data to a int pointer ptrint = (int*)data; // Increase the int stored at *ptrchar by 1 (*ptrint)++; cout << '*data points to an int' << '
'; } } void geek() { // Declare a character char c = 'x'; // Declare an integer int i = 10; // Call increase function using a char and int address // respectively increase(&c, sizeof(c)); cout << 'The new value of c is: ' << c << '
'; increase(&i, sizeof(i)); cout << 'The new value of i is: ' << i << '
'; } // Driver program int main() { geek(); }> Ausgabe
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>
Ungültige Zeiger
Ein Zeiger sollte auf eine gültige Adresse zeigen, aber nicht unbedingt auf gültige Elemente (wie bei Arrays). Diese werden als ungültige Zeiger bezeichnet. Nicht initialisierte Zeiger sind ebenfalls ungültige Zeiger.
int *ptr1; int arr[10]; int *ptr2 = arr+20;>
Hier ist ptr1 nicht initialisiert, sodass es zu einem ungültigen Zeiger wird, und ptr2 liegt außerhalb der Grenzen von arr, sodass es ebenfalls zu einem ungültigen Zeiger wird. (Hinweis: Ungültige Zeiger führen nicht unbedingt zu Kompilierungsfehlern.)
NULL-Zeiger
A Null Zeiger ist ein Zeiger, der nirgendwo hinzeigt und nicht nur auf eine ungültige Adresse. Im Folgenden finden Sie zwei Methoden zum Zuweisen eines Zeigers als NULL.
int *ptr1 = 0; int *ptr2 = NULL;>
Vorteile von Zeigern
- Zeiger reduzieren den Code und verbessern die Leistung. Sie werden zum Abrufen von Zeichenfolgen, Bäumen, Arrays, Strukturen und Funktionen verwendet.
- Zeiger ermöglichen es uns, mehrere Werte von Funktionen zurückzugeben.
- Darüber hinaus ermöglichen uns Zeiger den Zugriff auf einen Speicherort im Arbeitsspeicher des Computers.
In Verbindung stehende Artikel:
- Undurchsichtiger Zeiger
- Nahe, ferne und riesige Zeiger
Quiz:
Namensverzeichnis Linux ändern
- Zeiger-Grundlagen
- Erweiterter Zeiger