>um nun auf ein element dieses array über den pointer zuzugreifen benutze>ich folgende schreibweise:>>ptr[2];
Da kannste ja gleich das Array selbst nehmen.
>was mich allerdings etwas verwirrt ist, dass man hier gar keinen>dereferenzierungsoperator benötigt.>ich hätte eher mit sowas wie>>(*ptr)[2];
Versuch mal *ptr+2
@Paul Hamacher
Ich habe mich mit der C-Notation auch nie wohl gefühlt.
C ist wie einen Plattenbausiedlung -- aus den siebziger Jahren, weit
verbreitet, hässlich, aber erfüllt ihren Zweck, mehr oder weniger.
>> was mich allerdings etwas verwirrt ist, dass man hier gar keinen> dereferenzierungsoperator benötigt.
Wieso? Du brauchst einen Dereferenzierungsoperator. Aber nicht den
Stern, sondern die eckigen Klammern. Die dereferenzieren genau so wie
der Stern (nur mit bestimmten Offset). Der Stern dereferenziert immer
nur das erste Element.
> ich hätte eher mit sowas wie>>
1
(*ptr)[2];
Das wären ja zwei Dereferenzierungen.
Durch "*ptr" erhälst du eine Variable vom Typ char (Durch die
Dereferenzierung).
Und kannst du folgendes mit einer char-Variable machen?
1
chara,b;
2
b=a[2];
Nein, kannst du nicht. Also macht es doch überhaupt keinen Sinn ;)
hm..
aber ich habe ja sowas:
array:
Adresse Wert
+-----------+-----------+
| 0x0001 + 1 +
+-----------+-----------+
| 0x0002 + 2 +
+-----------+-----------+
| 0x0003 + 3 +
+-----------+-----------+
| 0x0004 + 4 +
+-----------+-----------+
| 0x0005 + 5 +
+-----------+-----------+
dann den pointer *ptr:
+-----------+-----------+
| 0x0006 + 0x0001 +
+-----------+-----------+
ist array im grundegenommen nicht auch ein pointer auf den anfang eines
datenfeldes oder ist ein array im sinne von C eben ein array und kein
pointer?
auf das array greife ich per array[2] zu. Dabei wird von der
Anfangsadresse mit einem offset von 2 auf den Wert dereferenziert also
lande ich beim wert der speicherstelle 0x0003, also 3.
der pointer *ptr enthält als wert ja auch wieder eine adresse, nämlich
0x0001, die anfangsadresse des arrays.
theoretisch müsste ich ja nun zweimal dereferenzieren. einmal um von der
pointeradresse 0x0006 auf dessen Wert 0x0001 zu kommen, und dann nochmal
um von der Adresse 0x0001 mit dem offset 2 auf den Wert der
speicherstelle 0x0003, also 3 zu kommen.
Daher dachte ich an (*ptr)[2];
lg Powl
Du verwirrst dich selber indem du dir den Speicheraufbau vorstellst.
Ein Array ist eigentlich ein stink normaler Pointer mit ein paar kleinen
Unterschieden:
Er(der Pointer) braucht keinen Speicher im Ram.
Es wird für Elemente auf die gezigt wird Speicher reserviert.
Man kann nicht den Stern zum dereferenzieren benutzen.
Deshalb kannst du ja auch schreiben
1
ptr=array;
aber nicht
1
array=ptr;
Und wie Simon bereits gesagt hat ist [] bereits eine dereferenzierung.
>Ein Array ist eigentlich ein stink normaler Pointer mit ein paar kleinen>Unterschieden:>Ein Array ist ein nicht manipulierbarer Pointer ;-)
Gefällt mir nicht!
Ich würde eher sagen: Ein Array ist eine Abfolge von Elementen gleichen
Typs, die aufeinander folgend irgendwo im Speicher angeordnet sind.
I_ H. wrote:
> Der Arrayoperator für x[y] ist identisch zu:>> *(x+sizeof(*x)*y)>> Nix Plattenbauweise, sondern völlig logisch und nachvollziehbar.
das ist ja auch logisch, aber hier ist x direkt ein array; mit dem
pointer auf ein array ist es ja genau so.
wie lautet dann die schreibweise wenn b ein pointer auf einen pointer a
ist, welcher wiederum auf das array zeigt? ist das dann auch b[y]
wodurch ich das gleiche ergebnis wie durch a[y] oder array[y] erhalte?
Auch wenn mich wahrscheinlich gleich einer überholt,
meine Erklärung Array für Dummys ;)
Du hast ein Array
char array[] = { 1, 2, 3, 4, 5 };
Das liegt an einer bestimmten Adresse fest im Speicher.
Es ist kein Pointer, es ist ein Datenfeld.
&array[0] oder array kannst du an einen Pointer übergeben.
Also wie oben
ptr = array;
oder
ptr = &array[0];
Ist beides gleichwertig.
ptr wird dabei mit der Startadresse des Arrays geladen.
Er enthält die Adresse des Arrays und nicht das Array selbst.
Wenn man über ptr auf das erste Element im Array zugreifen
möchte kann man a=*ptr; oder a=ptr[0]; schreiben.
Wenn man auf ein anderes Element zugreifen möchte muss man
zu ptr (wo die Startadresse des Arrays steht) einen Offset addieren.
Das geht mit a=ptr[offset]; oder mit (der besseren Version von I_H)
a = *(ptr + sizeof(Datentyp vom Array) * offset);
Der Offset ist abhängig vom Datentyp.
Deshalb muss man auch immer im Auge behalten
was passiert wenn man ptr z.B. hochzählt.
ptr++ zählt bei einem Byte als Datentyp eins hoch.
Bei int (sagen wir hier einfach 2 Byte, das gibts auch anders)
zählt er 2 höher.
@Paul Hamacher
>theoretisch müsste ich ja nun zweimal dereferenzieren. einmal um von der>pointeradresse 0x0006 auf dessen Wert 0x0001 zu kommen, und dann nochmal>um von der Adresse 0x0001 mit dem offset 2 auf den Wert der>speicherstelle 0x0003, also 3 zu kommen.>Daher dachte ich an (*ptr)[2];
Du musst unterscheiden zwischen "dereferenzieren" und Offset
hinzuaddieren:
ptr[2];
macht beides gleichzeitig. Wie Simon K. schrieb wirkt [] als
Dereferenzieroperator, zusätzlich wird entsprechend dem Index (hier 2)
die Position noch um 2*Elementgröße verschoben.
Paul Hamacher wrote:
> I_ H. wrote:>> Der Arrayoperator für x[y] ist identisch zu:>>>> *(x+sizeof(*x)*y)>>>> Nix Plattenbauweise, sondern völlig logisch und nachvollziehbar.>> das ist ja auch logisch, aber hier ist x direkt ein array; mit dem> pointer auf ein array ist es ja genau so.>> wie lautet dann die schreibweise wenn b ein pointer auf einen pointer a> ist, welcher wiederum auf das array zeigt? ist das dann auch b[y]> wodurch ich das gleiche ergebnis wie durch a[y] oder array[y] erhalte?
Dann schreibst du einfach (*b)[123] statt a[123] (oder alternativ
b[0][123], ist aber etwas unsauber). Schau dir an was du für Typen hast.
Wenn die Elemente im Array vom Typ T sind, ist a vom Typ T* und b vom
Typ T**. (*b) ist wieder T* und (*b)[0] ist dann T ( (**b) ist auch T
und das erste Element im Array).
D.h.
array[2] oder a[2] oder (*b)[2].
Tut mir leid also ich finde das verwirrend dass beim direkten zugriff
auf array mittels array[2] einmal dereferenziert wird und bei einem
zeiger, der nicht wie das array selbst auf dessen wert sondern auf
dessen adresse zeigt, trotzdem auch nur einmal.
lg PoWl
Och mensch, es wird doch 2mal dereferenziert... *b ist das erste mal,
und der Array Operator das 2. mal.
Arrays gibt es in C nicht als Variablentyp, ein Array wird durch einen
Pointer beschrieben, der auf das erste Element des Arrays zeigt. Bei
"int array[123];" wird array als eine Variable vom Typ int* deklariert.
Oh, tut mir leid ich hab mich vielleicht unklar ausgedrückt. Ich meinte
gerade array[2] und a[2] (a ist ein pointer auf array), nicht (*b)[2];
wenn array als pointer auf das erste array-element anzusehen ist, dann
ist a also ein pointer auf einen pointer;
> wenn array als pointer auf das erste array-element anzusehen ist, dann> ist a also ein pointer auf einen pointer;
Nein (bzw. nur wenn das Array ein Array von Pointern ist).
Ein Array ist eine Anzahl von Werten gleichen Typs (meinentwegen T), die
im Fall von C linear im Speicher angeordnet sind. Ein Array in C wird
repräsentiert durch einen Zeiger auf das erste Element, ist also vom Typ
T*.
Da wird genau 1mal dereferenziert, allerdings nicht array sondern
array+offset. Such in Wikipedia mal nach 'dereferenzieren'. Du kannst in
C ohme Umwege ein Array nicht über den ersten Wert angeben! Nur über
einen Zeiger auf den ersten Wert.
Nur mal so als Hinweis - a = *(ptr + sizeof(Datentyp vom Array) *
offset); ist falsch, richtig wäre a = *(ptr + offset); Das "echte"
Offset rechnet sich der Compiler selbst aus.
Mal zum Mitmeißeln:
Ein "Array", oder "Vektor" oder "Datenfeld" oder nur "Feld", ganz
allgemein, ist eine Liste aus gleichartigen Einträgen. Nicht mehr, und
auch nicht weniger. Wenn du auf Speicher stehst:
Ein "Zeiger" ist eine Adresse in diesem Speicher, z.B. die 3. Kannst
auch mehrere Zeiger nehmen, die auf die gleiche Adresse "zeigen", oder
auch nicht, wie du möchtest:
Mit den Zeigern kannst du machen, was du möchtest, das sind einfach nur
Hausnummern.
"Dereferenzieren" heißt jetzt, an einem Haus mit einer bestimmten
Hausnummer anzuklopfen, um an den Bewohner (also die Daten) zu kommen.
Dereferenzieren ich jetzt z.B. Y, dann klopfe ich an Haus Nummer 5 und
ein "e" kommt raus. Genausogut kann ich an Haus Nummer X (=3) klopfen,
dann kommt halt das "c" raus.
Ich kann aber mit den Hausnummern noch rechnen (sind ja nur Nummern).
Z.B. kann ich die Hausnummer X um eins erhöhen, bevor ich anklopfe. Dann
klopfe ich also an "3+1", also an Haus Nummer 4 an, da kommt dann das
"d" raus.
So, jetzt um eine Ecke mehr. Dein Zeiger (also die Hausnummer) muss
natürlich auch irgendwo im Speicher stehen. Also mal so:
Ich hab die Hausnummer "X" jetzt mal an Speicherstelle 8 abgelegt. Wenn
ich jetzt im Quelltext irgendwo "X" schreibe, dann weiß der Computer
genau, dass mit "X" die Speicherstelle 8 gemeint ist: Du musst
unterscheiden zwischen deinem Zeiger als Nummer (als Hausnummer) zum
Einen: Das ist ne Nummer, die - wie jede andre auch - einfach in eine
Variable abgelegt wird. Zum Anderen aber hast du auch das, wodrauf dein
Zeiger zeigt: Das ist das Haus, auf das der Zeiger zeigt, also dessen
Nummer in der Variable steht.
An den Wert von "X" kommt der Computer logischerweise ran, er weiß ja,
wo er "X" vorher abgelegt hat - dadrauf hast du als Programmierer keinen
Einfluss. Interessant wirds dann aber, wenn der Computer nicht auf "X"
selbst (also auf die Variable mit der Hausnummer) zugreifen soll,
sondern auf das Haus, dessen Hausnummer in dieser Variable steht (also
um eine Ecke weiter). Dann nämlich kommt es zu einer "Dereferenzierung".
Jetzt verstanden? (Zugegeben, einiges hab ich vereinfacht, aber das
Prinzip kommt hin)
Danke, jetzt hab ich nen schlechtes Gewissen da du dir so ne Mühe
gemacht hast obwohl ich das Prinzip eigentlich prima verstanden habe,
jedoch nur mit der Notation nicht so zurechtgekommen bin.
Für Die Laien kann man sowas aber ja mal als Link im Tutorial
hinzufügen.
lg Paul
Gehen wir mal davon aus, dass die Werte hintereinander im Speicher
liegen. Dann entspricht
1
int*array1=&a
einem Array mit 4 Einträgen, genauso wie
1
intarray2[4];
array1 und array2 sind exakt vom selben Typ (das const mal außen vor
gelassen). array[1] wird dann zB. auf b dereferenziert, genauso wie
*(array1+1).
Wäre array2 nicht ein konstanter Zeiger (dh. die Adresse auf die er
zeigt darf nicht verändert werden, wohl aber der Inhalt der Adresse)
könnte man auch schreiben "array2=array1".
In jedem Fall geht "array1=array2", damit zeigen dann beide Zeiger auf
den selben Speicher. Sprich nach "array1[0]=123;" gilt "array2[0]==123".
I_ H. wrote:
> Gehen wir mal davon aus, dass die Werte hintereinander im Speicher> liegen. Dann entspricht> ...> einem Array mit 4 Einträgen, genauso wie
Aber bitte nur, wenn diese Variablen auch im Arbeitsspeicher existieren.
Wenn sie in Registern liegen gibt die Ganze Suppe eher Müll. Auch müssen
diese nicht zwangsläufig hintereinander liegen. Aber zum Glück hast du
das ja dabei geschrieben. Nicht dass sich unser Array-Anfänger sowas
aneignet.
> array1 und array2 sind exakt vom selben Typ (das const mal außen vor> gelassen).
Auf gar keinen Fall! array1 ist vom Typ int* und array2 ist vom Typ
int[4]. Einfacher Beweis:
sizeof (array2) == 4 * sizeof(int)
sizeof (array1) == 1 * sizeof(int*)
Und je nach Maschine ist dies unterschiedlich.
> array[1] wird dann zB. auf b dereferenziert, genauso wie> *(array1+1).
Ja, unter oben genannten Voraussetzungen aber nur.
> Wäre array2 nicht ein konstanter Zeiger (dh. die Adresse auf die er> zeigt darf nicht verändert werden, wohl aber der Inhalt der Adresse)> könnte man auch schreiben "array2=array1".
array2 ist kein Zeiger. array2 ist ein Array. array2 kann aber bei
Bedarf in einen Zeiger implizit konvertiert werden. Der Arrayname darf
ohne Indirektion bzw. Dereferenzierung kein LValue sein (also ihm darf
nichts zugewiesen werden), schlicht und einfach deswegen, weil es in
dieser Repräsentation einfach kein Pointer ist.