|
|
||
|
|
||
| .. Der Indirektionsoperator * | ||
|
|
||
|
Mit
dem Indirektions-Operator kann man auf den Inhalt einer
Speicherzelle zugreifen, wenn man deren Adresse kennt. Man kann
diese Speicherzelle lesen und beschreiben. Wie man an die
Adresse einer Speicherzelle gelangt wurde im Kapitel zum
Adressoperator & beschrieben.
Legt
man die durch den Adressoperator erhaltene Adresse ihrerseits in
einer Speicherzelle ab, so spricht man bei diesem Inhalt von
einem Zeiger oder Vektor. Die Begriffe sind durchaus
einleuchtend, denn die Adresse oder der Zeiger in der
Speicherzelle weist ja tatsächlich auf den Ort hin, wo sich
ein zweiter Speicherzelleninhalt befindet.
Der Mechanismus funktioniert wie folgt .. |
||
double *z; // Deklaration einer Variablen z, welche die
// Adresse eines zweiten Speichers aufnehmen
// kann. In diesem zweiten Speicher auf den *z
// zeigt, muss sich eine doppeltgenaue
// Fliesskommazahl befinden.
double x= 2.5; // Deklaration, Definition und Initialisation
double y= 5.3; // einer Variablen x und einer Variablen y
// deren Inhalte die doppeltgenauen Fliess-
// kommazahl 2.5 bzw. 5.3 bilden.
z= &x; // Definition und Initialisierung des Zeigers
// z, dem die Adresse der Variablen x
// zugewiesen wird.
|
||
|
Nach
diesen Zeilen weisen die Variable x und der Zeiger *z auf ein
und den gleichen Speicherzelleninhalt, nämlich die
Fliesskommazahl 2.5. Der Unterschied besteht darin, dass die
Variable x direkt den Ablageort von 2.5 bezeichnet und *z nur
indirekt, denn es muss erst der Inhalt von z ausgewertet werden,
bis man an den tatsächlichen Ablageort von 2.5 gelangt.
Zugegeben,
das ganze hört sich kompliziert an und man muss es sich
durch den Kopf ziehen lassen. Dann aber treten die Möglichkeiten
der indirekten Adressierung in den Vordergrund und die sind
durchaus vorteilhaft.
Ein Zeiger *z muss nämlich nicht wie die Variable x selber, immer auf den gleichen Speicherinhalt zeigen. Wenn man ihn auf eine andere oder eine dritte Variable richtet, kann er je nach gerade herrschender Programmbedingung den Zugriff auf eine, der Situation angepasste Zahl herstellen. Man müsste ja nur den Zeiger auf diese neue Zahl richten .. |
||
|
|
z= &y; // Neuinitialisierung des Zeigers
// z, dem jetzt die Adresse der Variablen y
// zugewiesen wird. Nun zeigt *z auf 5.3
|
|
| Zudem kann man mit Zeiger die lokalen Eigenschaften der Variablen innerhalb von Funktionen überwinden, aber davon im Beispiel des nächsten Kapitels. | ||
| Speicherbild C-intern belegen Zeiger im Real-Modus der 80x86 CPU und je nach verwendetem Speichermodell, 2 bis 4 Bytes des RAM-Speichers. Zur Darstellung im unteren Bild mögen es 2 Bytes sein. Von denen das erste Byte die Ablageadresse 2010h besitzen möge. In diesen beiden Speichern soll die Adresse 2000h abgelegt sein. | ||
|
|
|
Adr |
Inhalt der Bytes |
|
|
|
Speicherdarstellung des Zeigers z |
2011 |
Adresse einer |
|
|
|
&z = |
2010 |
anderen Speicherzelle |
|
|
|
Adresse von z: &z = 2010 |
200F |
z.B.: 2000 |
|
|
|
Inhalt von z: z = 2000 |
... |
|
|
|
|
z zeigt auf: *z = 2.5 |
.... |
|
|
|
|
|
2008 |
|
|
|
|
Speicherdarstellung der Fliesskommavariablen x |
2007 |
CDh |
|
|
|
x enthält die Zahl 2.5, die rechts in der |
2006 |
CCh |
|
|
|
Fliesskommacodierung dargestellt ist. |
2005 |
CCh |
|
|
|
|
2004 |
CCh |
|
|
|
Adresse von x: &x = 2000 |
2003 |
CCh |
|
|
|
Inhalt von x: x = 2.5 |
2002 |
CCh |
|
|
|
x zeigt auf: *x = gibt es nicht, ist kein Zeiger |
2001 |
14h |
|
|
|
&x = |
2000 |
40h |
|
| Der Inhalt von *z stellt eine Adresse im Hauptspeicher des Rechners dar und wird deswegen Zeiger genannt. Wird nun mit dem Indirektionsoperator * auf den Inhalt von z zugegriffen, benutzt das vom Compiler erstellte Maschinenprogramm diese Adresse um auf den Inhalt der Speicherzelle zuzugreifen, welche die genannte Adresse besitzt. Im Beispiel wären das die Speicherzellen 2000 und folgende. Angenommen in der Speicherzelle 2000 und 7 weiteren Speicherzellen stünde die Fliesskommazahl 2.5 und der Zeigerzugriff würde lauten .. | |||
*z = *z 1.5 // Benutzung des Zeigers z um auf die
// Fliesskommazahl ab 2000 zuzugreifen
|
|||
| dann würde die Variable, auf die der Zeiger zeigt (2.5) zunächst um 1.5 vermindert werden und das Resultat beginnend mit der Adresse 2000 abgelegt werden. Es würde also nun 1.0 in dem Fließkommaspeicher der bei 2000 beginnt, stehen. Dass es sich bei den Speicherzellen ab 2000 um einen Fließkommaspeicher handelt, wurde dem Compiler bei der Deklaration des Zeigers *z durch 'double' erklärt. | |||
|
|
Beispiel |
|
|
|
|
|
|
|
1 2 3 4 5 6 7 |
#include <conio.h> // für printf()
void main (void)
{
double x = 2.5, y = 5.3;
double *z;
z = &x;
printf ("Inhalt der Variablen: x = %f", x); // Wert x
printf ("Inhalt der Variablen: y = %f", y); // Wert y
printf ("Inhalt des Zeigers : z = %X", z);
printf ("Adresse von z: &z = %X", &z);
printf ("Zeiger zeigt auf x: *z = %f", *z);
z = &y;
printf ("Zeiger zeigt auf y: *z = %f", *z);
}
|
||
|
|
|
|
|
|
Zeile 1: |
Es wird der Zeiger *z deklariert. Dem Compiler wird mitgeteilt, dass dieser Zeiger auf die Anfangsadresse einer doppeltgenauen Fliesskommazahl zeigt. |
|
|
|
Zeile 2: |
Es wird der Zeiger *z definiert. Die Speicherzellen, die der Zeiger benötigt werden im Hauptspeicher angelegt, dann werden sie mit der Anfangsadresse der Variablen x gefüllt. |
|
|
|
Zeile 3: |
Da ein Zeiger wie eine Integer-Variable aufgebaut ist, kann man sich seinen Inhalt z (im Binärformat) ansehen, also die Adresse auf die er zeigt und .. |
|
|
|
Zeile 4: |
die Anfangsadresse &z bei der seine erste Speicherzelle im Hauptspeicher beginnt |
|
|
|
Zeile 5: |
In dieser Zeile wird die Wirkung des Zeigers ausprobiert. Es wird indirekt über den Inhalt der Speicherzellen des Zeigers auf die Fliesskommavariable x = *z zugegriffen. |
|
|
|
Zeile 6: |
Dem Zeiger wird die Anfangsadresse der Variablen y zugewiesen. |
|
|
|
Zeile 7: |
Es wird indirekt über den neuen Inhalt des Zeigers auf die Fliesskommavariable y = *z zugegriffen. |
|
|
|
|
|
|
|
|
Inhalt der Variablen: x = 2.5 |
|
|
|
|
Inhalt der Variablen: x = 5.3 |
|
|
|
|
|
|
|
|
|
Inhalt des Zeigers: z = 2000 |
|
|
|
|
Adresse von z: &z = 2010 |
|
|
|
|
Zeiger zeigt auf x: *z = 2.5 |
|
|
|
|
|
|
|
|
|
Zeiger zeigt auf y: *z = 5.3 |
|
|
|
|
|
|
.de