6. Zeiger www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 1 von 6 6. 1. Allgemeines Zeiger spielen in der Programmierung eine wichtige Rolle. Sie sind wichtig, bei der Arbeit mit Arrays und Funktionen. Ein Zeiger ist eine Variable, deren Inhalt die Adresse einer anderen Variable im Hauptspeicher des Computers ist. Mit dieser Adresse kann man auf die Variable zugreifen. Die folgende Abbildung soll dies noch einmal verdeutlichen: Der Zeiger z zeigt hierbei im Hauptspeicher auf die Variable b. Bei der Arbeit mit Zeigern benötigen wir 2 Operatoren: & * Adreßoperator, wird vor die Variable geschrieben und liefert die Adresse der Variable zurück (siehe Funktion scanf!) Verweisoperator, wird vor den Zeiger geschrieben und liefert den Wert der Variable zurück, auf die der Zeiger gerichtet ist. 6. 2. Definition eines Zeigers Ein Zeiger wird folgendermaßen definiert: datentyp *zeigername; Zu beachten ist dabei, daß der Zeiger immer nur auf Variablen vom angegebenen Datentyp zugreifen kann. Hat der Zeiger beispielsweise den Datentyp int, so kann er nicht auf Variablen vom Datentyp float zeigen. Es besteht wiederum die Möglichkeit, daß mehrere Zeiger vom gleichen Datentyp hintereinander definiert werden. Das kennst Du aber schon von der Definition von einfachen Variablen.
6. 3. Zugriff auf Zeiger www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 2 von 6 6. 3. 1. Adresse zuweisen Auf einen Zeiger kann auf 3 Arten zugegriffen werden. Man kann dem Zeiger die Adresse einer Variablen zuweisen, man kann die Adresse, auf die der Zeiger zeigt, auslesen und den Wert der Variablen, auf die der Zeiger zeigt, auslesen. Man weist einem Zeiger folgendermaßen eine Adresse zu: zeiger = &variablen; Dem Zeiger wird also die Adresse der Variablen zugewiesen. 6. 3. 2. Adresse auslesen Um die Adresse, auf die der Zeiger zeigt, auszulesen, gibt man einfach nur den Zeigernamen an. Um die Adresse auszugeben, benötigst Du in der Funktion printf() den Formatstring %p (p = pointer, engl. Zeiger). Die Adresse wird in hexadezimaler Form ausgegeben. Hexadezimale Zahlen werden folgendermaßen in das duale Zahlensystem umgerechnet: 0 = 0 1 = 1 2 = 2 3 = 3 4 = 4 5 = 5 6 = 6 7 = 7 8 = 8 9 = 9 A = 10 B = 11 C = 12 D = 13 E = 14 F = 15 Die Zahlen werden von rechts nach links betrachtet. Die erste Zahl wird mit 1 multipliziert, die zweite mit 16, die dritte mit 16*16 usw. Die Produkte werden miteinander addiert und damit hat man die hexadezimale Zahl in eine Zahl zur Basis 2 umgerechnet. Bei einer Zahl FF32D wird also folgendermaßen gerechnet: 15*65536 + 15*4096 + 3*256 + 2*16 + 13*1 = 1045293 Wenn der Zeiger also die Adresse FF32D hat, so zeigt er auf die Adresse 1045293.
6. 3. 3. Wert der Adresse auslesen www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 3 von 6 Wenn Du den Wert der Variablen, auf deren Adresse der Zeiger gerichtet ist, auslesen möchtest, so mußt Du den Verweisoperator vor den Zeigernamen setzen: *zeigername Diese Zeichenkette kannst Du wiederum in eine printf() - Anweisung einbinden. Du hast außerdem die Möglichkeit, den Wert der Variablen zu ändern. Wenn beispielsweise der Zeiger z auf die Variable v zeigt, so kann man den Wert der Variablen auch folgendermaßen ändern: *z = neuerwert; Der Variable v wurde also ein neuer Wert zugewiesen. 6. 4. Zeiger in Funktionen Wie schon in Kapitel 5.5 erwähnt, werden die Werte von Parametern in Funktionen nicht geändert, auch wenn man es scheinbar tut. Hat man dies aber vor, so kann man statt der Variablen, Zeiger auf diese Variablen übergeben. Dann ist es möglich, die Werte der Parameter zu ändern. Bei der Definition der Funktion muß der Zeiger in der Parameterliste eingetragen werden: rückgabewert funktionsname(datentyp *zeigername) In der Funktion kann man auf den Wert der Variable mittels Verweisoperator * zugreifen. Im Hauptprogramm sieht der Aufruf der Funktion dann folgendermaßen aus: funktionsname(zeigername); Du hast auch die Möglichkeit, gleich die Adresse der Variablen zu übergeben. Du benötigst dann nicht extra einen Zeiger.Der Aufruf sieht dann folgendermaßen aus: funktionsname(&variablenname); Es wird also die Adresse übergeben, was ja einem Zeiger entspricht.
6. 5. Zeiger auf Arrays www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 4 von 6 In Kapitel 4 wurden für die einzelnen Feldelemente von Arrays Indizes benutzt. Alternativ dazu kann man auch Zeiger benutzen. Dazu wird zuerst ein Feld definiert: datentyp feldname[groesse]; Zusätzlich wird ein Zeiger definiert, der auf den gleichen Datentyp zeigen kann: datentyp *zeigername; Dieser Zeiger wird nun auf das Array gesetzt: zeigername = feldname; Diese Zeile bewirkt, daß der Zeiger auf das 1. Feldelement zeigt, also feldname[0]. Will man nun auf eines der Feldelemente zugreifen, so mußt man einfach den Index zum Zeiger hinzu addieren. *(zeigername + 3) = 10; würde dann also bewirken, daß feldname[3] den Wert 10 zugewiesen bekommen würde. 6. 6. Anwendung von Zeigern: dynamische Speicherplatzzuweisung Bei Feldern hatten wir bisher nur die Möglichkeit, die Größe am Beginn des Programms festzulegen. Dies bringt Nachteile mit sich, wenn man nicht so viele Feldelemente benötigt, oder noch schlimmer, wenn man mehr benötigt, als man vorher festgelegt hat. Dazu benutzt man die Funktion malloc(). Diese Funktion legt die Größe während des Programmablaufs fest. Wenn man beispielsweise eine Variable vom Typ Integer definiert, so wird im Hauptspeicher Platz in der Größe von 2 Byte reserviert. Genau dies macht auch die Funktion malloc(). Als erstes wird ein Zeiger definiert: datentyp *zeigername; Die Funktion malloc() wird dann wie folgt aufgerufen: zeigername = (datentyp *) malloc (groesse * sizeof(datentyp));
www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 5 von 6 Die Funktion sizeof() liefert den benötigten Speicherplatz für den jeweiligen Datentyp zurück. Im Fall Integer wäre dies also 2. Den Zeiger zeigername kannst Du nun wie einen normalen Zeiger auf ein Array benutzen. Das hast Du ja schon in Kapitel 6.5 gelernt. Wenn Du mit der Verarbeitung fertig bist, so mußt Du den Speicher wieder freigeben. Dies tust Du mit der Funktion free(). Sie wird folgendermaßen aufgerufen: free(zeigername); Wichtig! Um die Funktion malloc() benutzen zu können, mußt Du die vordefinierte Bibliothek malloc.h mit #include einbinden. 6. 7. Aufgaben 1. Schreib ein Programm, das eine beliebige Anzahl von Noten einliest. Die Anzahl soll bei Programmstart vom Nutzer abgefragt werden. Das Programm soll folgende Aufgaben erfüllen: Einlesen der Noten Bestimmen von Minimum und Maximum Berechnung des Durchschnittswertes Anzeigen einer Liste aller Noten mit Durchschnitt, Minimum und Maximum Realisiere das ganze Programm mit einem Zeiger und dynamischer Speicherplatzzuweisung. Lösungsvorschlag: lsg_6_1.c 1330 Byte 04. 06. 2001 2. Schreib eine Funktion tausch, welche zwei übergebene ganze Zahlen vertauscht. Schreib ein dazugehöriges Hauptprogramm zum testen. Hinweis: Übergib statt der beiden ganzen Zahlen die Adressen der beiden Zahlen und arbeite dann mit den Zeigern. Lösungsvorschlag: lsg_6_2.c 479 Byte 04. 06. 2001
3. Gegeben sind 2 Integervariablen: www.c-programme.de Stefan Thiemert Kapitel 6 - Seite 6 von 6 Name: zahl1 Name: zahl2 Wert: 5 Wert: 10 Adresse: FD00 Adresse: FD02 Schreib nach jedem Schritt auf, welche Werte sich ändern: a) zeiger1 = &zahl1; b) zeiger2 = &zahl2; c) *zeiger1+=20; d) *zeiger2-=3; e) *zeiger1 = *zeiger2 + 5; f) *zeiger2 = *zeiger1 - zahl2; Lösung: lsg_6_3.txt 182 Byte 04. 06. 2001