Einführung
Zeigerarithmetik ist ein leistungsstarkes Feature in C, das es Ihnen ermöglicht, Speicheradressen durch Addition oder Subtraktion von Werten zu manipulieren. Eine der häufigsten Anwendungen der Zeigerarithmetik ist das Durchlaufen von Arrays. Mit Zeigern können wir effizient durch Arrays sowohl in Vorwärts- als auch in Rückwärtsrichtung navigieren.
In diesem Lab (Praktikum) werden Sie lernen, wie Sie Arrays erstellen und initialisieren, Zeiger einrichten, um auf Arrayelemente zuzugreifen, und die Zeigerarithmetik nutzen, um Arrays zu durchlaufen. Diese Technik ist grundlegend in der C-Programmierung und bildet die Grundlage für viele fortgeschrittene Datenmanipulationsoperationen.
Erstellen eines einfachen C-Programms
Beginnen wir damit, eine neue C-Datei im VSCode-Editor zu erstellen. Diese Datei wird unser Hauptprogramm für das Durchlaufen von Arrays mit Zeigern enthalten.
Im WebIDE suchen Sie das Explorer-Panel auf der linken Seite und navigieren Sie zum Verzeichnis
~/project.Klicken Sie mit der rechten Maustaste auf den Ordner
projectund wählen Sie "Neue Datei". Benennen Sie die Dateimain.c.Kopieren Sie die folgende einfache C-Programmstruktur in die Datei:
#include <stdio.h>
int main() {
printf("Array Traversal using Pointers\n");
return 0;
}
Speichern Sie die Datei, indem Sie Strg+S drücken oder über das Menü "Datei > Speichern" wählen.
Kompilieren und führen wir dieses Programm aus, um sicherzustellen, dass alles korrekt eingerichtet ist. Öffnen Sie im WebIDE ein Terminal, indem Sie über das Menü "Terminal > Neues Terminal" wählen, und führen Sie aus:
cd ~/project
gcc main.c -o main
./main
Sie sollten die folgende Ausgabe sehen:
Array Traversal using Pointers
Dies bestätigt, dass Ihre C-Entwicklungsumgebung ordnungsgemäß funktioniert. In den nächsten Schritten werden wir dieses Programm so ändern, dass es mit Arrays und Zeigern arbeitet.
Deklarieren und Initialisieren von Arrays und Zeigern
In diesem Schritt werden wir lernen, wie man ein Array und einen Zeiger deklariert, die die grundlegenden Bestandteile für das Durchlaufen von Arrays mit Zeigern sind.
Grundlagen von Arrays und Zeigern
Ein Array in C ist eine Sammlung von Elementen gleichen Typs, die in aufeinanderfolgenden Speicherstellen gespeichert werden. Beispielsweise reserviert ein Integer-Array mit 5 Elementen im Speicher Platz für 5 aufeinanderfolgende Ganzzahlen.
Ein Zeiger ist eine Variable, die die Speicheradresse einer anderen Variable speichert. Mit Zeigern können wir indirekt auf den Wert zugreifen, der an einer bestimmten Speicheradresse gespeichert ist.
Ändern wir unsere main.c-Datei, um ein Array und einen Zeiger einzufügen:
#include <stdio.h>
int main() {
printf("Array Traversal using Pointers\n\n");
// Declare and initialize an array of 5 integers
int arr[5] = {10, 20, 30, 40, 50};
// Declare a pointer of integer type
int *ptr;
// Print the array elements using array notation
printf("Array elements using array notation:\n");
for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
In diesem Code:
- Wir haben ein Integer-Array
arrmit 5 Elementen deklariert und es mit den Werten 10, 20, 30, 40 und 50 initialisiert. - Wir haben einen Integer-Zeiger
ptrdeklariert, der später verwendet wird, um auf die Array-Elemente zu verweisen. - Wir haben die Array-Elemente mit der herkömmlichen Array-Schreibweise ausgegeben.
Kompilieren und führen Sie das Programm aus, um die Array-Elemente zu sehen:
gcc main.c -o main
./main
Sie sollten die folgende Ausgabe sehen:
Array Traversal using Pointers
Array elements using array notation:
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
Im nächsten Schritt werden wir den Zeiger mit dem Array verbinden und die Array-Elemente über den Zeiger zugreifen.
Verknüpfen von Zeigern mit Arrays und Vorwärtsdurchlauf
In diesem Schritt werden wir die Verbindung zwischen unserem Zeiger und dem Array herstellen und dann den Zeiger nutzen, um das Array in Vorwärtsrichtung zu durchlaufen.
Verknüpfen eines Zeigers mit einem Array
In C repräsentiert der Name eines Arrays ohne Index die Adresse des ersten Elements des Arrays. Das bedeutet, dass wir diese Adresse direkt einer Zeigervariablen zuweisen können.
Ändern wir unsere main.c-Datei, um den Zeiger mit dem Array zu verknüpfen und es zu durchlaufen:
#include <stdio.h>
int main() {
printf("Array Traversal using Pointers\n\n");
// Declare and initialize an array of 5 integers
int arr[5] = {10, 20, 30, 40, 50};
// Declare a pointer of integer type
int *ptr;
// Assign the address of the first element of the array to the pointer
ptr = arr; // This is equivalent to ptr = &arr[0]
// Print the array elements using array notation
printf("Array elements using array notation:\n");
for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// Print the array elements using pointer notation
printf("\nArray elements using pointer notation (forward traversal):\n");
for(int i = 0; i < 5; i++) {
printf("*(ptr + %d) = %d\n", i, *(ptr + i));
}
return 0;
}
In diesem aktualisierten Code:
- Wir haben die Adresse des ersten Elements des Arrays
arrdem Zeigerptrzugewiesen. - Wir haben eine neue Schleife hinzugefügt, die das Array mithilfe von Zeigerarithmetik durchläuft.
- Der Ausdruck
*(ptr + i)greift auf den Wert an der Speicheradresseptr + izu. Wenni0 ist, handelt es sich um das erste Element des Arrays; wenni1 ist, um das zweite Element, und so weiter.
Kompilieren und führen Sie das Programm aus, um die Ergebnisse zu sehen:
gcc main.c -o main
./main
Sie sollten die folgende Ausgabe sehen:
Array Traversal using Pointers
Array elements using array notation:
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
Array elements using pointer notation (forward traversal):
*(ptr + 0) = 10
*(ptr + 1) = 20
*(ptr + 2) = 30
*(ptr + 3) = 40
*(ptr + 4) = 50
Beachten Sie, dass beide Methoden die gleiche Ausgabe erzeugen. Dies zeigt, dass Zeigerarithmetik verwendet werden kann, um auf Array-Elemente zuzugreifen, genauso wie die herkömmliche Array-Indizierung.
Implementierung der Zeigerinkrementierung für das Array-Durchlaufen
Im vorherigen Schritt haben wir auf Array-Elemente über den Ausdruck *(ptr + i) zugegriffen. Obwohl dies einwandfrei funktioniert, bietet C eine kompaktere Möglichkeit, ein Array mit Zeigern zu durchlaufen: den Inkrementoperator (++).
Wenn wir einen Zeiger inkrementieren, bewegt er sich an die nächste Speicheradresse, wobei die Größe des Datentyps, auf den er zeigt, berücksichtigt wird. Bei einem Integer-Zeiger bewegt sich der Zeiger beim Inkrementieren auf das nächste Ganzzahl-Element im Speicher.
Ändern wir unsere main.c-Datei, um die Zeigerinkrementierung für das Array-Durchlaufen zu verwenden:
#include <stdio.h>
int main() {
printf("Array Traversal using Pointers\n\n");
// Declare and initialize an array of 5 integers
int arr[5] = {10, 20, 30, 40, 50};
// Declare and initialize a pointer to the first element of the array
int *ptr = arr; // Same as ptr = &arr[0]
// Print the array elements using pointer incrementation
printf("Array elements using pointer incrementation:\n");
for(int i = 0; i < 5; i++) {
printf("*ptr = %d\n", *ptr);
ptr++; // Move the pointer to the next element
}
// Reset the pointer to the beginning of the array
ptr = arr;
// Print all elements in a single line using pointer incrementation
printf("\nAll elements in a single line: ");
for(int i = 0; i < 5; i++) {
printf("%d ", *ptr++); // Print and then increment
}
printf("\n");
return 0;
}
In diesem aktualisierten Code:
- Wir initialisieren den Zeiger
ptrdirekt bei seiner Deklaration. - Innerhalb der ersten Schleife verwenden wir
*ptr, um auf das aktuelle Element zuzugreifen, und dannptr++, um zum nächsten Element zu gelangen. - Nach der ersten Schleife setzen wir
ptrwieder auf den Anfang des Arrays zurück. - In der zweiten Schleife verwenden wir den Post-Inkrementoperator
*ptr++, der zunächst den aktuellen Wert vonptrverwendet und dann inkrementiert.
Kompilieren und führen Sie das Programm aus, um die Ergebnisse zu sehen:
gcc main.c -o main
./main
Sie sollten die folgende Ausgabe sehen:
Array Traversal using Pointers
Array elements using pointer incrementation:
*ptr = 10
*ptr = 20
*ptr = 30
*ptr = 40
*ptr = 50
All elements in a single line: 10 20 30 40 50
Dies zeigt, wie man die Zeigerinkrementierung verwendet, um ein Array zu durchlaufen. Der wichtigste Punkt ist, dass ptr++ automatisch die Größe des Datentyps berücksichtigt, wenn es zum nächsten Element wechselt.
Implementierung des Rückwärtsdurchlaufs mit Zeigerdekrementierung
In den vorherigen Schritten haben wir das Array in Vorwärtsrichtung durchlaufen. Jetzt lernen wir, wie man das Array in umgekehrter Richtung mithilfe der Zeigerdekrementierung durchläuft.
Für den rückwärtsen Durchlauf müssen wir:
- Den Zeiger so initialisieren, dass er auf das letzte Element des Arrays zeigt.
- Den Zeiger dekrementieren, um rückwärts durch das Array zu navigieren.
Ändern wir unsere main.c-Datei, um den rückwärtsen Durchlauf zu implementieren:
#include <stdio.h>
int main() {
printf("Array Traversal using Pointers\n\n");
// Declare and initialize an array of 5 integers
int arr[5] = {10, 20, 30, 40, 50};
// Forward traversal using pointer increment
int *ptr = arr;
printf("Forward traversal using pointer increment:\n");
for(int i = 0; i < 5; i++) {
printf("%d ", *ptr);
ptr++;
}
printf("\n\n");
// Backward traversal using pointer decrement
// Point to the last element of the array
ptr = &arr[4]; // or ptr = arr + 4
printf("Backward traversal using pointer decrement:\n");
for(int i = 0; i < 5; i++) {
printf("%d ", *ptr);
ptr--; // Move the pointer to the previous element
}
printf("\n\n");
// Alternative approach: Start from the last element and decrement in the loop condition
printf("Alternative backward traversal approach:\n");
for(ptr = &arr[4]; ptr >= arr; ptr--) {
printf("%d ", *ptr);
}
printf("\n");
return 0;
}
In diesem aktualisierten Code:
- Wir führen zunächst einen Vorwärtsdurchlauf mithilfe der Zeigerinkrementierung durch.
- Für den rückwärtsen Durchlauf setzen wir den Zeiger auf das letzte Element des Arrays mit
ptr = &arr[4]. - Innerhalb der Schleife geben wir das aktuelle Element aus und dekrementieren dann den Zeiger mit
ptr--. - Wir zeigen auch eine alternative Methode, bei der die Dekrementierung Teil der Aktualisierungsanweisung der for-Schleife ist.
Kompilieren und führen Sie das Programm aus, um die Ergebnisse zu sehen:
gcc main.c -o main
./main
Sie sollten die folgende Ausgabe sehen:
Array Traversal using Pointers
Forward traversal using pointer increment:
10 20 30 40 50
Backward traversal using pointer decrement:
50 40 30 20 10
Alternative backward traversal approach:
50 40 30 20 10
Dies zeigt, wie man ein Array sowohl in Vorwärts- als auch in Rückwärtsrichtung mithilfe von Zeigerarithmetik durchläuft. Die Möglichkeit, Zeiger zu inkrementieren und zu dekrementieren, erleichtert es, in beliebiger Richtung durch Arrays zu navigieren.
Zusammenfassung
In diesem Lab haben Sie gelernt, wie man Arrays in der C-Programmierung mithilfe von Zeigern durchläuft. Hier sind die wichtigsten Konzepte, die wir behandelt haben:
Grundlagen von Arrays und Zeigern:
- Arrays in C speichern Elemente in aufeinanderfolgenden Speicheradressen.
- Zeiger speichern Speicheradressen und können verwendet werden, um auf diese Adressen zuzugreifen.
Beziehung zwischen Zeigern und Arrays:
- Der Arrayname (ohne Index) repräsentiert die Adresse des ersten Elements.
- Wir können diese Adresse einem Zeiger zuweisen, um eine Verbindung mit dem Array herzustellen.
Techniken für den Vorwärtsdurchlauf:
- Mithilfe von Zeigerarithmetik:
*(ptr + i) - Mithilfe der Zeigerinkrementierung:
*ptrgefolgt vonptr++ - Kombination von Dereferenzierung und Inkrementierung:
*ptr++
- Mithilfe von Zeigerarithmetik:
Techniken für den Rückwärtsdurchlauf:
- Initialisieren Sie den Zeiger auf das letzte Element:
ptr = &arr[size-1] - Verwenden Sie die Zeigerdekrementierung:
ptr--, um rückwärts zu navigieren. - Die Schleifenbedingung kann prüfen, wann der Zeiger den Anfang des Arrays erreicht hat.
- Initialisieren Sie den Zeiger auf das letzte Element:
Zeigerarithmetik ist ein leistungsstarkes Feature in C, das eine effiziente Speichermanipulation ermöglicht und Flexibilität bei der Arbeit mit Arrays und anderen Datenstrukturen bietet. Diese Technik bildet die Grundlage für fortgeschrittenere Programmierkonzepte wie dynamische Speicherzuweisung, verkettete Listen und andere komplexe Datenstrukturen.



