Ein Pointer (Zeiger) ist eine Variable wie jede andere auch. Ihr Inhalt
ist eine Speicheradresse.
Ein int ist eine Variable, welche eine ganze Zahl enthält
Ein double ist eine Variable, welche eine Gleitkommazahl enthält
EIn Pointer ist eine Variable, welche eine Speicheradresse enthält.
Das ist im Grunde schon fast alles :-)
Allerdings muss man in C immer auch dazu sagen: Wenn ein Pointer eine
Speicheradresse enthält, was finde ich dann genau an dieser Stelle im
Speicher vor.
Wenn ich also einen int-Pointer habe
int* PtrA;
dann enthält PtrA eine Adresse im Speicher. Schau ich genau an dieser
Stelle im Speicher nach, dann finde ich dort einen int vor. Ein double
Pointer
double* PtrX;
enthält dann folgerichtig eine Speicherstelle unter der ein double im
Speicher abgelegt wurde, etc. etc.
Nun zeigt so ein Pointer nicht von alleine auf irgendeine Speicherzelle,
sondern das muss der Programmierer erst mal festlegen. Auch wird der
int, auf den der Pointer zeigt, nicht einfach aus dem Nichts generiert,
sondern irgendjemand muss im Speicher erst mal Platz für so einen int
reservieren. Auch das macht so ein Pointer nicht eigenständig.
zb so
1 | int main()
|
2 | {
|
3 | int a = 5; // Platz für einen int wird geschaffen
|
4 |
|
5 | int* PtrA; // Platz für den Pointer wird geschaffen
|
6 |
|
7 |
|
8 | PtrA = &a; // und jetzt wird der Pointer eingerichtet. Der Inhalt des
|
9 | // Pointers ist die Speicheradresse von a
|
10 | }
|
Oder als Grafik ausgedrückt
PtrA a
+---------+ +----+
| o-------------------------->| 5 |
+---------+ +----+
So wie a als Inhalt den Zahlenwert 5 hat, so hat PtrA als Inhalt die
Speicheradresse von a. Ausgedrückt durch einen Pfeil von PtrA nach a.
So ist das natürlich ein wenig witzlos, wenn man nicht mit dem Pointer
auch arbeiten könnte. Wird der Pointer 'dereferenziert', so wird
gedanklich dem Pfeil gefolgt und der angegebene Wert von der
entsprechenden Speicherstelle geladen/geschrieben. Deshalb ist es auch
notwendig, dass der verwiesene Datentyp Teil des Datentyps des Pointers
ist ( ein int-Pointer zeigt auf einen int, ein double Pointer zeigt auf
einen double etc.)
1 | int main()
|
2 | {
|
3 | int a = 5; // Platz für einen int wird geschaffen
|
4 |
|
5 | int* PtrA; // Platz für den Pointer wird geschaffen
|
6 |
|
7 |
|
8 | PtrA = &a; // und jetzt wird der Pointer eingerichtet. Der Inhalt des
|
9 | // Pointers ist die Speicheradresse von a
|
10 |
|
11 | *PtrA = 7; // lege die 7 dort ab, wohin der Pointer zeigt
|
12 | }
|
PtrA a
+---------+ +----+
| o-------------------------->| 7 |
+---------+ +----+
oder umgekehrt:
1 | int main()
|
2 | {
|
3 | int a = 5; // Platz für einen int wird geschaffen
|
4 | int b = 0;
|
5 |
|
6 | int* PtrA; // Platz für den Pointer wird geschaffen
|
7 |
|
8 |
|
9 | PtrA = &a; // und jetzt wird der Pointer eingerichtet. Der Inhalt des
|
10 | // Pointers ist die Speicheradresse von a
|
11 |
|
12 | *PtrA = 7; // lege die 7 dort ab, wohin der Pointer zeigt
|
13 |
|
14 | b = *Ptra; // hole den aktuellen Wert von dort, wohin der Pointer zeigt
|
15 | // und speichere ihn in b ab
|
16 | }
|
PtrA a
+---------+ +----+
| o-------------------------->| 7 |
+---------+ +----+
b
+----+
| 7 |
+----+
Und jetzt kommen Arrays ins Spiel.
Arrays sind in C so halbe Datentypen. Man kann ein Array zwar definieren
und kann auch auf einzelne Elemente eines Arrays zugreifen, aber man
kann zb nicht ein Array an eine Funktion übergeben. Allgemeiner kann man
sagen: Immer dann, wenn der Name eines Arrays ohne Indizierung vorkommt
(also nur der Name alleine), dann wird anstelle des Arrays an sich, die
Adresse des ersten Arrayelements genommen. Und diese Adresse kann man
wiederrum an eine Funktion übergeben, wobei sie innerhalb der Funktion
in einer Pointervariablen aufgefangen wird und zur Verfügung steht.
1 | int main()
|
2 | {
|
3 | int Werte[5];
|
4 |
|
5 | Werte[0] = 1;
|
6 | Werte[2] = 8;
|
7 | }
|
Dies generiert erst mal das Array
Werte
+---+---+---+---+---+
| 1 | 8 | | | |
+---+---+---+---+---+
Versucht man nun dieses Array an eine Funktion zu übergeben
1 | int main()
|
2 | {
|
3 | int Werte[5];
|
4 |
|
5 | Werte[0] = 1;
|
6 | Werte[2] = 8;
|
7 |
|
8 | foo( Werte );
|
9 | }
|
so wird anstelle des Arrays, die Adresse des ersten Array Elements
übergeben
Werte
+---+---+---+---+---+
| 1 | 8 | | | |
+---+---+---+---+---+
^
|
|
|
und diese Adresse wiederrum, wird von der aufgerufenen Funktion in einer
Pointer-Variablen empfangen, die der Funktion während ihrer Ausführung
zur Verfügung steht (und nach Beendigung der Funktion wieder
verschwindet)
1 | void foo( int* Passed )
|
2 | {
|
3 | ...
|
4 | }
|
5 |
|
6 | int main()
|
7 | {
|
8 | int Werte[5];
|
9 |
|
10 | Werte[0] = 1;
|
11 | Werte[2] = 8;
|
12 |
|
13 | foo( Werte );
|
14 | }
|
Werte
+---+---+---+---+---+
| 1 | 8 | | | |
+---+---+---+---+---+
^
| Passed
| +--------+
+-------------------o |
+--------+
Die Funktion kann über diesen Pointer, auf den Inhalt des Arrays
zugreifen und auch verändern
1 | void foo( int* Passed )
|
2 | {
|
3 | int k = *Passed;
|
4 | }
|
Werte
+---+---+---+---+---+
| 1 | 8 | | | |
+---+---+---+---+---+
^
| Passed k
| +--------+ +---+
+-------------------o | | 1 |
+--------+ +---+
Oder aber auch auf irgendein anderes Arrayelement, indem sie den
übergebenen Pointer als Anfang benutzt und einfach angibt, auf das
wievielte Element zugegriffen werden soll.
1 | void foo( int* Passed )
|
2 | {
|
3 | int k = *Passed;
|
4 |
|
5 | *( Passed + 2 ) = 4;
|
6 | }
|
Werte
+---+---+---+---+---+
| 1 | 8 | 4 | | |
+---+---+---+---+---+
^
| Passed k
| +--------+ +---+
+-------------------o | | 1 |
+--------+ +---+
Nun ist aber die Syntax *( Pointer + Offset ) eine ekelhafte. In C hat
man dem Abhilfe geschaffen, indem man den Arrayzugriff mittels Index so
definiert hat, dass
*( Pointer + Offset ) identisch ist zu
Pointer[ Offset ]
anstelle von *( Pointer + 3 ) = 2 kann und wird man auch oft schreiben:
1 | void foo( int* Passed )
|
2 | {
|
3 | int k = *Passed;
|
4 |
|
5 | *( Passed + 2 ) = 4;
|
6 | Passed[ 3 ] = 2;
|
7 | }
|
Werte
+---+---+---+---+---+
| 1 | 8 | 4 | 2 | |
+---+---+---+---+---+
^
| Passed k
| +--------+ +---+
+-------------------o | | 1 |
+--------+ +---+
Es gibt noch mehr über Pointer zu sagen und vor allen Dingen zu
entdecken. Aber im Grunde folgt alles andere aus dem bisher Gesagten,
auch wenn einem das so nicht bewusst ist. Daher: Literatur, Literatur,
Literatur. Denn ich hab ehrlich gesagt auch keine Lust, dir hier all das
was in einem vernünftigen Buch auf 30 oder mehr Seiten erklärt ist, in
ein paar Positings nahezubringen.