Programmieren
 
 
 
 
 
C-Grundkurs
 
 
 
 
 
.. 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.

 

 

 

 

 
Bildschirmausgabe:
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

 

 

 

 

 

www..de