Zeiger sind das Herz von C. Wenn Sie dieses Konzept verstanden haben, ist der schwierigste Teil geschafft. Bevor Sie sich mit Zeigern beschäftigen, sollten Sie einen Überblick zu den Grundkonzepten von C und zu Arrays haben.
Um Zeiger zu verstehen, ist es nützlich zu wissen, wie einfache Variablen abgespeichert werden. Wenn Sie das anders sehen, klicken Sie
hier um den Teil zu überspringen.Was passiert im folgenden Programm?
main()
{
int Length;
}
|
Es wird ausreichend viel Speicherplatz reserviert, um eine Integervariable anzulegen. Der Variablen wird der Bezeichner 'Length' zugeordnet. Der Inhalt dieses Speicherplatzes ist undefiniert. Grafisch ergibt sich folgendes Bild:
(Adresse) (Daten)
---- ----
<------- Length------>
|F1|----|----|F2|----|----|F3|----|----|F4|--
Um in 'Length' einen Wert abzulegen, schreibt man:
main()
{
int Length;
Length = 20;
}
|
Der Dezimalwert 20 (Hex 14) wird auf dem Speicherplatz abgelegt.
(Adresse) (Daten)
---- ----
<------- Length------>
|F1| 00 | 00 |F2| 00 | 20 |F3|----|----|F4|--
Jetzt wird das Programm etwas erweitert zu:
main()
{
int Length;
Length = 20;
printf("Length is %d\n", Length);
printf("Address of Length is %p\n", &Length);
}
|
Die Ausgabe sieht etwa so aus ....
Length is 20
Address of Length is 0xF1
Beachten Sie '&Length' in der zweiten printf-Anweisung. Das & steht für Adresse von Length. Wenn das klar ist, kann's weitergehen.
Ein Zeiger enthält eine Adresse die auf Daten verweist.
Ein Beispielprogramm, in dem ein Zeiger definiert wird könnte so aussehen ...
main()
{
int *Width;
}
|
Grafisch dargestellt ergibt sich ...
(Adresse) (Daten)
---- ----
<------- Width------>
|F1|----|----|F2|----|----|F3|----|----|F4|-- Bis hierhin gibt es keinen Unterschied zur Grafik weiter oben, -der Wert, der in 'Width' abgespeichert wird ist unbekannt. Um 'Width' einen Wert zuzuweisen kann man schreiben.
main()
{
int *Width;
*Width = 34;
}
|
(Adresse) (Daten)
---- ----
<------- Width ------>
|F1| 00 | 00 |F2| 00 | D1 |---
|F3| 00 |
(Adresse) (Daten)
*Width ---- ----
| < --- die Zahl 34 --->
-------> |D1| 00 | 00 |D2| 00 | 34 |---
Im Gegensatz zum Length = 20 Beispiel weiter oben, enthält der Speicherplatz 'Width' NICHT die Zahl 34 sondern die Adresse, unter der man die Zahl 34 findet (in der Grafik die Adresse D1). Im folgenden Programm wird das nochmal zusammengefaßt:
main()
{
char *Width;
*Width = 34;
printf(" Data stored at *Width is %d\n", *Width);
printf(" Address of Width is %p\n", &Width);
printf("Address stored at Width is %p\n", Width);
}
|
Die Ausgabe sieht etwa so aus.
Data stored at *Width is 34
Address of Width is 0xF1
Address stored at Width is 0xD1
|
Ein Zeiger kann auf jeden Datentyp zeigen, z.B. int, float, char. Um einen Zeiger zu definieren, schreibt man das Zeichen * (asterisk) zwischen Datentyp und Variable, hier einige Beispiele.
main()
{
int count; /* an integer variable */
int *pcount; /* a pointer to an integer variable */
float miles; /* a floating point variable. */
float *m; /* a pointer */
char ans; /* character variable */
char *charpointer; /* pointer to a character variable */
}
|
Als wir uns
Arrays angesehen haben, hatten wir das folgende Programm verwendet, um auf ein zweidimensionales Arrays zuzugreifen.
main()
{
char colours[3][6]={"red","green","blue"};
}
Mit diesem Programm werden drei Arrays vereinbart, wobei jedes Feld 6 Zeichen enthält. Man könnte das aber auch so schreiben.
main()
{
char *colours[]={"red","green","blue"};
}
Das Programm macht genau das gleiche.
printf("%s \n", colours[1]);
printf("%s \n", *(colours+1))
Es wird zweimal green ausgegeben.
What is the difference between these two lumps of code?
main()
{
char colour[]="red";
printf("%s \n",colour);
}
|
main()
{
char *colour="red";
printf("%s \n",colour);
}
|
The answer is, NOTHING! They both print the word red because in both cases 'printf' is being passed a pointer to a string.
An array of 4 bytes is reserved and the text 'red' placed into the storage array. The contents of the array can be chaged later BUT on the left, the size of the array is fixed.
Here is a picture of the example on the right. The 'r' of 'red' is stored at address 10, the 'e' is at address 11 etc.
At this point it maybe worth looking at the malloc Funktion.
There are times when you write a Funktion but do not know the datatype of the returned value. When this is the case, you can use a void pointer.
int func(void *Ptr);
main()
{
char *Str = "abc";
func(Str);
}
int func(void *Ptr)
{
printf("%s\n", Ptr);
}
|
Please note, you cant do pointer arithmatic on void pointers.
So far we have looked at pointers to data, but there is no reason why we should not define a pointer to a pointer. The syntax looks like this.
main()
{
char **DoublePtr;
}
|
A common use for these is when you want to return a pointer in a Funktion parameter.
#include |
Pointers to functions can be used to create 'callback' functions. An example of these pointers can be seen in theqsort Funktion.
Simple example passing a Funktion pointer.
Example passing 'int' variables.
Example passing 'char' and 'char *' variables.
VOID keyword.
Funktion
arguments.