Adreßarithmetik in C
Zeiger-Rechnung
Wird eine Zahl zu einem Zeiger addiert, so wird dem Speicherplatzbedarf entsprechend vieler Objekte des Basisdatentyps weitergezählt. Wird beispielsweise eine Zahl i zu einem Zeiger vom Datentyp "int *" addiert, so wird um i Objekte des Datentyps "int" weitergezählt. Die Möglichkeit, auf diese Weise mit Zeigern zu „rechnen“, nennt man Zeiger-Rechnung (engl. “pointer arithmetic ”).
Der Ausdruck "a + 1" oder der gleichwertige Ausdruck "1 + a" bezeichnet also den Zeiger des dem Objekte "*a" folgenden Objektes, da er durch die Addition gerade so weit erhöht wird, wie "*a" groß ist. Es wird also bei der Addition einer Zahl zu einem int-Zeiger um die Größe eines Objektes vom Datentyp "int" weitergegangen. Wir können dank der Zeiger-Arithmetik daher die Zeiger der zweiten und dritten Komponente der Reihung berechnen und mit dem Inhalts-Operator schließlich auch den Inhalt dieser Zeiger erreichen.
»a+1« ist die Adresse der zweiten Komponente. Der Typ von »a + 1« ist wie der Typ von »a + 0«, der Adresse der ersten Komponente. »a + 0« ist im allgemeinen gleichbedeutend zu »a«.
»a + 1« ist „die Adresse des Objekts direkt hinter dem Objekt »a«“ („Adreßarithmetik“, „Zeiger-Arithmetik“).
»*( a + 1 )« ist das Objekt direkt hinter dem Objekt »*a«.
Man beachte, daß es mit Reihungen nun möglich ist, zur Laufzeit auszurechnen, welches Objekt verwendet werden soll. Es kann also ein Zugriff auf ein bestimmtes Objekt in Abhängigkeit von einer Zahl erfolgen, wobei zu Schreibzeit noch nicht feststeht, auf welches Objekt zugegriffen wird.
Da die Unterobjekte einer Reihung keine Namen haben, wäre es ohne eine Möglichkeit, wie die hier geschilderte, gar nicht möglich, sie zu erreichen (zu verwenden, auf sie zuzugreifen).
Das Objekt "a" nach der Definition "int a[ 3 ];"
Zeiger Objekt
.------------.
a + 0 -----> | *( a ) |---
|------------| |
a + 1 -----> | *( a + 1 ) | | 2 x int
|------------| V
a + 2 -----> | *( a + 2 ) |---
'------------'main.c
#include <stdio.h> int main( void )
{ int a[ 3 ];
printf( "%d\n", *( a + 0 )= 41 );
printf( "%d\n", *( a + 1 )= 18467 );
printf( "%d\n", *( a + 2 )= 6334 );
printf( "%d\n", *( a + 2 ));
printf( "%d\n", *( a + 1 ));
printf( "%d\n", *( a + 0 )); }stdout
41
18467
6334
6334
18467
41
Fehlerhafte Zugriffe
Ein Zeiger darf nur auf ein Objekt zeigen, bei einer Reihung oder einem einzelnen Objekt auch noch auf die nächste Position direkt hinter der letzten Komponente der Reihung oder dem einzelnen Objekt.
Ein Zeiger darf nur dereferenziert werden, wenn er auch auf ein Objekt zeigt.
main.txt
#include <stdio.h> int main( void )
{ int a[ 1 ];
printf( "%d\n", *( a + 1 )= 41 );
printf( "%d\n", *( a + 1 ) ); }stdout
41
41
Durchlaufen einer Reihung in einer Schleife
Aufgrund der Regeln für die Priorität von Operatoren, bedeutet »*p++« dasselbe wie »*(p++)«.
main.txt
#include <stdio.h> int main( void )
{ int const a[ 4 ]={ 27, 40, 27, 30 }; int const * p = a;
while( p < a + 4 )printf( "%d\n", *p++ ); }stdout
27
40
27
30