Zeiger sind zur Manipulation von Speicherblöcken gedacht, wobei theoretisch jede beliebige Adresse manipuliert werden kann (praktisch wird dies natürlich von den momentan auf dem Markt erhältlichen Betriebsystemen, die im "Safe-Mode" laufen, überwacht und ggf. verhindert).
Ein gutes Beispiel ist wenn du einen Integer hast (lokal vereinbart) und diesen in einer Funktion verwenden willst und danach die Variable mit dem Inhalt haben willst, den er am Ende der Funktion A (nennen wir sie einfach mal A) besaß.
Für einen "normalen" Funktionsaufruf werden die Parameter (meißtens in umgekehrter Reihenfolge) auf den Stack "gepusht" ([Intel-]ASM: push <WERT/REGISTER/ADRESSE> : legt <WERT/...> auf den Stack) und dann von den Funktionen "gepopt" ([Intel-]ASM: pop <REGISTER/ADRESSE> : holt den nächsten Wert vom Stack, größe wird durch die größe des Parameters bestimmt).
Das wiederum führt dazu, dass die Funktionen einen Lokalen wert erhalten -> eine Änderung des Integers I, in Funktion A, hat keine Änderung des Integers I in der Funktion main zu folge.
Beispiel 1; Code:
Code:
#include <stdio.h>
void A(int i)
{
i++;
}
int main(void)
{
int i = 1;
printf("I besitzt den Wert %d\n", i);
A(i);
printf("I besitzt den Wert %d\n", i);
return 0;
}
Beispiel 1; Ausgabe:
Code:
blackberry@system:~/Desktop$ gcc a.c -o a; ./a
I besitzt den Wert 1
I besitzt den Wert 1
Nun sagen wir mal, wir übergeben anstelle des Integers I einen "Zeiger auf I".
Beispiel 2; Code:
Code:
#include <stdio.h>
void A(int *i)
{
(*i)++;
}
int main(void)
{
int i = 1;
printf("I besitzt den Wert %d\n", i);
A(&i);
printf("I besitzt den Wert %d\n", i);
return 0;
}
Beispiel 2; Ausgabe:
Code:
blackberry@system:~/Desktop$ gcc a.c -o a; ./a
I besitzt den Wert 1
I besitzt den Wert 2
Die Klammern bei "(*i)++;" sind in dem Fall notwendig, weil der Inkrementationsoperator in der Hirarchie höher steht als der unäre Operator, was ohne Klammern (also so: "*i++;") eine Inkrementation des Zeigers und anschießende Anwendung des unären Operatoren zur Folge hätte -> keine Wertänderung. Mit den Klammern wird zuerst auf den Speicherwert von I zugegriffen und dieser dann um eins erhöht.
Zu bemerken ist dementsprechend auch, dass Zeiger wiederum Variablen sind und eine Änderung des Zeigers, ähnlich wie bei Beispiel 1, keinen Effekt auf den Zeiger in einer anderen Funktion hat (dafür wäre ein Zeiger auf einen Zeiger auf ... notwendig).
Also ein sehr großer nutzen von Zeigern besteht darin, dass du bei einer Funktion *indirekt* mehr als einen Wert, mit verschiedenen Datentypen zurückgeben kannst.
Als Praxisbeispiel schau dir doch mal MSDN an (zB. http://msdn.microsoft.com/en-us/library/aa364992(VS.85).aspx ) - du wirst bei den Parametern sicher sehr viele "_out DWORD ..." finden. (DWORD ist ein typedef für "unsigned long int")
Zum Thema "Java kommt auch ohne aus": Java kommt im Vergleich zu C++ mit sehr wenig aus (und hat meiner Meinung nach die Objektorientierung ein bisschen zu weit in den Hals bekommen). Nicht umsonst wird deshalb auch bei der Programmierung von Computerspielen und Ähnlichem C++, Java vorgezogen.
mfG. BlackBerry