Ummm, alle scheinen hier den armen Kerl verwirren zu wollen...Hierarhie? Kami-sama...
An dieser Stelle muss ich Bemerkung machen, dass C oft als "middle-level" language bezeichnet wird, dass heisst, dass C zwar nicht direkt mit dem Prozessor umgeht, wie Assembler, ist aber ohne Rücksicht auf die Ideale der "high-level"-Sprachen für den Prozessor optimiert. Deswegen gibt es hier oft Situationen, wo 2 thematisch verschiedene Dinge zusammengefasst werden, nur weil aus der Sicht des Prozessors die vollkommen gleich sind.
Beispiele dafür sind zum Beispiel: es gibt keine bool'schen Variablen oder werte, weil int dass genausogut machen kann, char kann man sowohl für einen Buchstaben benutzen, aber auch für eine Zahl -128..127 usw.
Dazu gehören auch Pointer, die unter C so ziemlich dasselbe sind wie Arrays. Ich werde gleich beschreiben wieso, da kannst du dir aber gleich merken - C ist nicht kompliziert, C ist eher primitiv gebaut - hättest du dich zuvor mit ASM beschäftigt, wird dir die ganze Struktur "von unten gesehen" vollkommen klar.
Also:
Also, was ist ein Pointer? das ist eine Variable, ist 4 Byte gross (auf 32-bit Platformen) und enthält eine Adresse auf den Speicher.
mit "Type" * "Name" definierst du einen Pointer, der auf eine Variable von Typ "Type" zeigt bzw. (wichtig!) auf eine Liste von hintereinander folgenden solchen Variablen (auch bekannt als Array)
Dereferenzieren bedeutet nichts anderes als "den Wert der Variable, auf die der Pointer zeigt, rauszuholen"
Beispiel:
int a; // Normale Variable int
int *p; // Pointer auf eine int-Variable
zu diesem Zeitpunkt ist p irgendwo schon vorhanden, und enthält irgendeinen sinnlosen Wert, also zeigt schon mal irgendwohin
p = &a; // &a bedeutet "Adresse von der Speicherstelle, wo der Wert von a abgelegt ist", nun wird diese adresse in der Variable p gespeichert
*p = 3; // *p bedeutet "Speicherstelle, wohin p zeigt, darein wird nun 3 geschrieben.
Das wäre die einfache Beschreibung von den Pointern.
Nun zur Pointerarithmetik:
Pointer ist im prinzip eine bestimmte Zahl (Adresse), also verbietet uns nichts auch arithmetische Operationen damit zu durchführen, allerdings kommen nur + und - in frage.
p+1 - was hätte das für Bedeutung? Das ist die Adresse, die gleich nach der Adresse folgt, auf die p zeigt. Allerdings is hier wichtig, von welchen Typ dieser Pointer ist. In unserem Fall ist es "int *p", also zeigt er auf int's, und diese sind 4 Byte gross (auf 32-bit Systemen), also ist p+1 die Adresse, die um 4 Byte von der Adresse entfernt ist, wohin p zeigt.
Da können wir zum Beispiel schreiben:
int *r = p+1; // nun haben wir noch einen Pointer auf int namens "r", der auf die "4-Byte-nächste" Adresse zeigt als p.
Was ist denn nun mit Arrays? - Man kann schreiben:
*(p+1) = 4; // da haben wir diese nächste Speicherstelle mit 4 beschrieben
aber man kann es auch so schreiben:
p[1] = 4; // glaubst du oder nicht, aber es hat nichts mit Arrays zu tun, es ist nur die andere Schreibweise.
Es ist Zeit, "Array" zu definieren:
Array ist ein reservierter Speicherbereich, der genug Platz für eine bestimmte Anzahl von Variablen eines Typs bietet.
Arrays kann man aber im Programm auf 2 verschiedene Weisen definieren:
int feld[10]; // ein statischer Array
int *ding = (int *)malloc(10*sizeof(int)); // ein dynamischer array
Beide bieten Platz für 10 ints, beide befinden sich nun irgendwo im Speicher, deswegen kann man ihre Position durch die Adresse vom ersten, er... nullten Element angeben. Wie erfährt man diese Adresse? Ganz einfach: im ersten Fall heisst die "feld", im zweiten - "ding".
Ja, das heist, die Namen von den beiden Arrays alleine bedeuten int-pointer auf den nullten Element. Die beiden sind int-pointer, obwohl man im ersten Fall nicht so genau sieht. Für die beiden kannst du schreiben:
feld[2] = 3; // der 2. Element = 3
ding[1] = 5; // der 1. el = 1
aber auch:
*(feld+2)=3; // dasselbe!
*(ding+1)=5; // dasselbe!
Wie du siehst in der allgemeinen Benutzung (also einzelne Elemente setzen und abfragen) gibt es keinerlei unterschiede zwischen den Beiden. Ansonsten gibt es doch Unterschiede, nämlich: während "ding" eine richtige Variable ist, und im Speicher gelagert wird, ist "feld" fest definiert während kompilation. Da "feld" sich nicht im Speicher befindet, sondern nur im Code, kann man "feld" auch nicht verändern, man kann auch feld-Array nicht etwa vergrössern. &feld ergibt einen Compiler-Fehler, da kein Sinn hat - "feld" ist nicht im Speicher gelagert, hat daher keine Adresse, während &ding ist ok. (Wenn das jetzt verwirrend wirkt, mach dir keine Sorgen, einfach von den Worten "Ansonsten gibt es doch Unterschiede..." bis hierhin erstmals alles vergessen - es ist "advanced wissen".
Puuh... das war lang... ^_^
Frag weiter wenn du lust hast...