1. Einführung
2. Pointer Grundlagen
2.1 Fragen
2.2 Aufgaben
3. Pointer & Felder
3.1 Fragen
3.2 Aufgaben
4. Pointer & Funktionen
4.2 Fragen
4.3 Aufgaben
5. Lösungen
6. Download

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:
Eine weitere Möglichkeit den Pointer auf den Anfang des Feldes zu setzten wäre
	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.
Um das nächste Element des Feldes anzusprechen wird beim Feldzugriff über den Variablennamen einfach der Index erhöht.
	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:
Natürlich kann der Pointer auch kreuz und quer durch das Feld wandern. Dabei sollte unbedingt darauf geachtet werden die Feldgrenzen einzuhalten und den Pointer evtl. vor einer Operation auf die Anfangsadresse des Feldes zurück zu setzen.

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:
Hier kann der Pointer ebenfalls über entprechende Operationen kreuz und quer "verbogen" werden. Wichtig ist auch hier die Einhaltung der Feldgrenzen. Die Möglichkeiten des "verschiebens" und "verbiegens" des Pointers werden häufig als Pointerarithmetik bezeichnet.

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.
Ein für diese Tabelle erstelltes Feld kann folgendermaßen deklariert werden.
	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:
Wie an den unterschiedlichen Farben zu erkennen ist, werden die einzelnen Zeilen der Tabelle nacheinander im Speicher abgelegt. Diese Eigenschaft hat für den Pointer eine sehr große Bedeutung, da dieser den Zugriff auf das zweidimensionale Feld sehr stark vereinfacht. Der Pointer wird mit der Anfangsadresse des Feldes initialisiert und durch „verschieben“ oder „verbiegen“ des Pointers kann dieser vom Anfang bis zum Ende des Feldes "wandern" um z.B. die Werte der Elemente auszugeben oder sie zu initialisieren. Folgender Programmcode zeigt ein Beispiel bei dem jedes Feld über einen sich „verbiegenden“ Pointer mit 0 initialisiert wird:
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.