
3. Pointer & Felder
3.1 Pointer mit eindimensionalen Feldern
Eine große Bedeutung haben Pointer auch im Zusammenspiel mit Feldern / Arrays. Die
Anwendung ist ähnlich wie bei den, in der ersten Einheit behandelten, Variablen. Die Deklaration und
Initialisierung von Feld und Pointer sieht folgendermaßen aus.
int feld[5] = {4, 2, 6, 7, 1}; /* int-Feld deklarieren und initialisieren*/
int *pt_feld; /* Pointer deklarieren */
pt_feld = &feld[0]; /* Pointer auf Anfang des Feldes setzen */
Wie die Speicherzuordnung dafür aussehen könnte, zeigt folgendes Bild:

pt_feld = feld; /* entspricht pt_feld = &feld[0]) */
da der Feldname ohne Index die Anfangsadresse des ersten Feldelements ist. Zu Beachten ist, dass jedes deklarierte
Feld mit dem Feldindex "0" beginnt.
Um auf die Elemente des Feldes zuzugreifen gibt es wieder zwei Möglichkeiten. Entweder der direkte Feldzugriff über den Index
oder indirekt über den Pointer. Wie der Zugriff auf das erste Feldelement aussehen kann zeigt folgendes Beispiel:
printf("1. Element von feld über Feldzugriff: %d", feld[0]);
printf("1. Element von feld über Pointerzugriff: %d", *pt_feld);
Bei der ersten Möglichkeit wird der Inhalt des ersten Feldelements zurückgegeben. Die zweite Möglichkeit gibt den Inhalt der
Adresse wieder, auf die der Pointer zeigt, welche in diesem Fall ebenfalls die Adresse des ersten Feldelements ist.
Die Bildschirmausgabe belegt, dass bei zwei unterschiedlichen Methoden der selbe Wert zurückgegeben wird.

printf("3. Element von feld über Feldzugriff: %d", feld[2]);
Wie aber ist dies über den Pointer möglich, der ja nur auf die Anfangsadresse des Feldes zeigt? Die erste Möglichkeit
ist, den Pointer durch das Feld "wandern" zu lassen. Dabei wird die Adresse, auf die der Pointer zeigt, dem Zugriff angepasst und jeweils
um den entsprechenden Wert erhöht (Diese Methode ist auch sehr gut für Schleifen geeigent). Wie folgendes Beispiel
zeigt wird der Inhalt des Pointers um die entsprechende Anzahl erhöht.
pt_feld = pt_feld + 2;
printf("3. Element von feld über Pointerzugriff: %d", *pt_feld);
Da dem Compiler der Datentyp bekannt ist (bei der Deklaration festgelegt) weiß er wie viele Bytes im Speicher er
weiter "wandern" muss um das nächste oder übernächste Feldelement zu adressieren.Wie das "Wandern" des Pointers im Speicher aussehen kann, zeigt folgende Animation:

Eine weitere Möglichkeit ist, den Pointer zu "verbiegen". Dabei behält der Pointer die Anfangsadresse bei und der so genannte Offset wird um die entsprechende Anzahl an Feldelementen erhöht. Angewendet wird diese Möglichkeit folgendermaßen:
printf("3. Element von feld über Pointerzugriff: %d", *(pt_feld+2));
Auch hier ist es wieder der bekannte Datentyp der angibt, um wie viele Bytes der Pointer "verbogen" werden muss, um ein
bestimmtes Feldelement zu adressieren. Der Vorteil dieser Methode ist, dass der Pointer immer seine Anfangsadresse
behält und somit nicht darauf geachtet werden muss, diese zurück zu setzten. Das "Verbiegen" des Pointers kann im
Speicher folgendermaßen aussehen:

Speziell bei eindimensionalen Feldern ist auch ein Pointerzugriff über den Index möglich. Wie dieser aussehen kann zeigt folgendes Beispiel:
printf("1. Element von feld über Pointerzugriff mit Index: %d", pt_feld[0]);
3.2 Pointer mit mehrdimensionalen Feldern
Wie Pointer auf mehrdimensionale Felder angewendet werden, wird am Beispiel eines zweidimensionalen Feldes erklärt. Angenommen es werden an 3 Tagen jeweils 4 Messwerte z.B. die Temperatur aufgenommen, so können diese in einer Tabelle dargestellt werden, in der die Tage die Zeilen und die Messwerte die Spalten sind.

int messwerte [3][4]; /* 3 Zeilen, 4 Spalten */
Um die Elemente des Feldes nun mit Werten zu füllen, werden üblicherweise Schleifenstrukturen benutzt die Spalte für Spalte und Zeile für Zeile ablaufen und einen Wert ablegen. Der Programmcode zeigt ein Beispiel bei dem jedes Feldelement mit einer 0 initialisiert wird:
01 #include <stdio.h>
02
03 int main(void)
04 {
05 int messwerte [3][4];
06 int i, j = 0;
07
08 /* Initalisierung der Feldelemente mit 0 */
09 for (i=0; i<3; i++)
10 {
11 for (j=0; j<4; j++)
12 {
13 messwerte [i][j] = 0;
14 }
15 }
16 /* Ausgabe der Feldelemente */
17 for (i=0; i<3; i++)
18 {
19 for (j=0; j<4; j++)
20 {
21 printf ("Tag -> %d Messwert -> %2d: %d \n", i+1, j+1, messwerte [i][j]);
22 }
23 }
24 fflush(stdin);
25 getchar();
26 return 0;
27 }
Im Speicher ergibt sich für das angelegte Feld messwerte folgendes Bild:

01 #include <stdio.h>
02
03 int main(void)
04 {
05 int messwerte [3][4];
06 int i, j = 0;
07 int *pt_messwerte = &messwerte [0][0];
08
09 /* Initalisierung der Feldelemente mit 0 */
10 for (i=0; i< 3*4; i++)
11 {
12 *(pt_messwerte + i)=0;
13 }
14 /* Ausgabe der Feldelemente */
15 for (i=0; i< 3*4; i++)
16 {
17 printf ("Messwert -> %2d: %d \n", i+1, *(pt_messwerte + i));
18 }
19 fflush(stdin);
20 getchar();
21 return 0;
22 }
Ebenso kann auch der sich „verschiebende“ Pointer angewendet werden, wobei zu beachten ist, dass dieser vor jeder Operation auf den Feldanfang zurückgesetzt werden muss. Analog zu den Beispielen mit zweidimensionalen Feldern können Pointer auch sehr einfach bei Feldern mit mehr als zwei Dimensionen angewendet werden, da die Elemente jeder weiteren Dimension im Speicherbild an die vorhandenen Elemente angehängt werden.