Forum: PC-Programmierung Frage zu Pointern


von pointer (Gast)


Lesenswert?

Hallo, kann ich auf ein Array statt mit Array[m][n]
auch so darauf zugreifen:  *(*(array+m)+n)?
Also ich meine, ist die dereferenzierung ao korrekt?

danke

von troll (Gast)


Lesenswert?

ja

von troll2 (Gast)


Lesenswert?

nein, Array =|= array  ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wenn du den den Array-Zugriff noch unleserlicher machen möchtest, kannst
du auch n[m[array]] schreiben ;-)

von DirkB (Gast)


Lesenswert?

Wie ist denn das Array definiert?

von XTerminator (Gast)


Lesenswert?

DirkB schrieb:
> Wie ist denn das Array definiert?

Das ist völlig egal.

von horst (Gast)


Lesenswert?

Du derefenzierst 2x, nimmst also den Inhalt einer Speicherzelle als 
Adresse. Das würde funktionieren, wenn du ein Feld von 
Pointern/Referenzen hast. Bei einem zweidimensionalen Feld ist das wohl 
kaum das, was du willst.
Schon einen Schritt näher wäre
*((array+m)+n).
Jetzt hast du das nächste Problem:
Du hast ein Feld von Feldern. Bei m soll also m*(Feldgröße der 
2.Dimension)*(Speichergöße der einzelnen Elemente) addiert werden. Bei n 
aber nur n*(Speichergöße der einzelnen Elemente). Das müßte mit dem 
richtigen casten auf ein Feld von Feldern bzw. ein Feld von Elementen 
gehen. (Wann du wo und wie casten mußt damit das ganze funktioniert, das 
entnimmst du dem C-Standard oder du castest im Zweifelsfall immer. Und 
das dann bitte richtig. ;-p )

Bonusaufgabe:
array wurde als Referenz einer Funktion übergeben. Der Compiler hat dort 
keine Ahnung, wie das Feld organisiert ist sondern sieht nur ein 
eindimensionales Feld unbekannter Größe. Was machst du dort, außer dich 
aufzuhängen?

Ich hoffe, du versuchst nur, C besser zu verstehen und willst ein 
derartiges Konstrukt nicht ernsthaft einsetzen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

horst schrieb:
> Jetzt hast du das nächste Problem:
> Du hast ein Feld von Feldern. Bei m soll also m*(Feldgröße der
> 2.Dimension)*(Speichergöße der einzelnen Elemente) addiert werden. Bei n
> aber nur n*(Speichergöße der einzelnen Elemente). Das müßte mit dem
> richtigen casten auf ein Feld von Feldern bzw. ein Feld von Elementen
> gehen. (Wann du wo und wie casten mußt damit das ganze funktioniert, das
> entnimmst du dem C-Standard oder du castest im Zweifelsfall immer. Und
> das dann bitte richtig. ;-p )

Und um das nicht ganz so kompliziert zu machen, wie du es beschrieben
hast, gibt es die Schreibweise *(*(array+m)+n). Das funktioniert sehr
wohl auch bei Array von Arrays, nicht nur bei Pointer-Arrays.
:)

von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:

> Und um das nicht ganz so kompliziert zu machen, wie du es beschrieben
> hast, gibt es die Schreibweise *(*(array+m)+n). Das funktioniert sehr
> wohl auch bei Array von Arrays, nicht nur bei Pointer-Arrays.
> :)

Dann sind wir aber wieder bei einer Zwischenfrage von weiter oben:
Wie genau ist array definiert?

Denn bei

  char array[5][4];

ist *(*(array+m)+n) ein Syntaxfehler: 'Dereferencing a non pointer 
entity'. Oder auch 'Derferencation makes pointer from integer without a 
cast'. Je nach Compiler.

   *(array + m*sizeof(*array) + n)

wäre korrekt. Anstelle des sizeof könnte man auch einfach 5 schreiben.

Denn das 'Problem' besteht darin, dass je nach exakter 
Variablebdefinition, die simple Schreibweise

   i = array[m][n];

in mehrere grundverschiedene Operationen umgewandelt werden muss, je 
nachdem ob man es mit einem

  char array[5][4];

oder einem

  char* array[5];

oder gar einem

  char ** array;

zu tun hat, trotzdem aber in allen Fällen identische Array-Syntax 
benutzen kann.

von AND (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> *(array + m*sizeof(*array) + n)
>
> wäre korrekt. Anstelle des sizeof könnte man auch einfach 5 schreiben.

Das sizeof(*array) würde 1 liefern, da *array vom Typ char ist. Also 
besser 5 schreiben :)

von Karl H. (kbuchegg)


Lesenswert?

AND schrieb:
> Karl Heinz Buchegger schrieb:
>> *(array + m*sizeof(*array) + n)
>>
>> wäre korrekt. Anstelle des sizeof könnte man auch einfach 5 schreiben.
>
> Das sizeof(*array) würde 1 liefern, da *array vom Typ char ist. Also
> besser 5 schreiben :)

No.

Bei

  char array[5][4]

ist *array vom Typ char[5];

Wenn du ein 2D Array einmal 'dereferenzierst', landest du bei einem 1D 
Array.

von AND (Gast)


Lesenswert?

Ok. Stimmt.

von Mike M. (mikeii)


Lesenswert?

*(array + m*sizeof(*array) + n) verstehe ich nicht ganz

wenn ich z.b. das mache:

char array[][5] = {"Das","Ist","Ein","Test"};

dann kann ich sowohl mit

array[m][n] als auch mit *(*(array+m)+n)

fehlerfrei drauf zu greifen.
Ich hatte dazu auch mal ne Frage, und ich glaube du hattest mir auch 
eine ähnliche Antwort gegeben.

Kannst du das erklären? Ich habe es bei mir so nicht zum laufen 
gebracht.

*(*(array+m)+n)
Das hier erkläre ich mir so:
Mit dem anlegen des arrays, lege ich ja nacheinander die Zeichen in den 
Speicher.
Also Das\0xxIst\0xEin\0xTest\0 wobei x ja zufällig ist, habe ich ja 
nicht festgelegt.

Wenn ich jetzt *(array+m) mache, habe ich doch meinen Pointer auf das 
erste Zeichen jeweils, also D, I, E, T
wenn ich den Pointer dereferenziere und evtl. davor noch vergrößere, 
also
*(*(array+m)+n) , dann habe ich doch mein Zeichen wieder?

Oder verstehe ich da was falsch? Ich habe es ausgiebig so getestet und 
die Adressen geprüft, und die waren alle gleich?

Danke

von Mike M. (mikeii)


Lesenswert?

Hab das mal als C Programm gefasst:
1
#include <stdio.h>
2
3
int main(void)
4
{
5
6
    int i,j;
7
    char array[][5] = {"Das","Ist","Ein","Test"};
8
9
    for(i=0;i<4;i++)
10
    {
11
        for(j=0;j<5;j++)
12
        {
13
            printf("%c",array[i][j]);
14
        }
15
16
    }
17
18
    printf("\n");
19
    //Das gleiche mit der Pointerversion
20
    for(i=0;i<4;i++)
21
    {
22
        for(j=0;j<5;j++)
23
        {
24
            printf("%c",*(*(array+i)+j));
25
        }
26
27
    }
28
29
    //Liefert exact die gleiche Ausgabe
30
31
    //Adressen vergleichen
32
    printf("\n");
33
    for(i=0;i<4;i++)
34
    {
35
        for(j=0;j<5;j++)
36
        {
37
            printf("%p,%p\n",(*(array+i)+j),&array[i][j]);
38
        }
39
40
    }
41
42
    return 0;
43
}


Als Ausgabe erhalte ich das was ich gesagt habe:
1
Das  Ist  Ein  Test
2
Das  Ist  Ein  Test
3
0022FEF4,0022FEF4
4
0022FEF5,0022FEF5
5
0022FEF6,0022FEF6
6
0022FEF7,0022FEF7
7
0022FEF8,0022FEF8
8
0022FEF9,0022FEF9
9
0022FEFA,0022FEFA
10
0022FEFB,0022FEFB
11
0022FEFC,0022FEFC
12
0022FEFD,0022FEFD
13
0022FEFE,0022FEFE
14
0022FEFF,0022FEFF
15
0022FF00,0022FF00
16
0022FF01,0022FF01
17
0022FF02,0022FF02
18
0022FF03,0022FF03
19
0022FF04,0022FF04
20
0022FF05,0022FF05
21
0022FF06,0022FF06
22
0022FF07,0022FF07

Der erste Pointer wird jeweils um 5 Inkrementiert, da das so mit dem 
Anlegen des Arrays wohl festgelegt wurde.

*(array + i*sizeof(*array) + j)

Liefert mir irgendwie einen Blödsinn.

von Mike M. (mikeii)


Lesenswert?

SO habe jetzt die Lösung zu dem Problem, und dazu, warum Karl Heinz 
seine Ansatz nicht stimmt (nicht böse gemeint ;) )

char array[][5] = {"Das","Ist","Ein","Test"};

array zeigt auf array[0] und array[0] zeigt auf array[0][0]

a ist damit also ein Zeiger der auf ein char Feld der Länge 5 Zeigt

Damit ist ein sizeof garnicht nötig, der Pointer weiß selber wieviele 
Adressen er weiterspringen muss.

von horst (Gast)


Lesenswert?

Mike Mike schrieb:
> char array[][5] = {"Das","Ist","Ein","Test"};

So erhältst du ein Feld mit Referenzen auf die Strings. Da ist die 
doppelte Dereferenzierung auch richtig.

Probiere es mal mit
char array[4][5] = 
{'D','a','s',0,0,'I','s','t',0,0,'E','i','n',0,0,'T','e','s','t',0};

Ich habe ja nichts dagegen, dass man auch mal gefinkelte Konstrukte 
verwendet. Aber als Mindestanforderung empfehle ich, dass man selbst 
wenigstens weiß, was man da tut, und nicht nur, dass es halt zufällig 
funktioniert.

von Mike M. (mikeii)


Lesenswert?

So funktioniert es für mich ebenfalls, und es geht nicht darum das es 
zufällig funktioniert (Danke übrigends für den Tipp, dass alles mit 
Binären Nullen gefüllt wird), sondern ich hatte im Hinterkopf, dass es 
so geht. Nur musste ich erst gucken wo das auch steht.

ISO/IEC 9899:TC3, WG14/N1256, Committee Draft — Septermber 7, 2007):
"An array type describes a contiguously allocated nonempty set of 
objects with a
particular member object type, called the element type. Array types are
characterized by their element type and by the number of elements in the 
array."

von Karl H. (kbuchegg)


Lesenswert?

Mike Mike schrieb:

> *(*(array+m)+n)


Du hast recht.
Da hab ich mich ins Boxhorn jagen lassen.
Wenn man es sich anhand der Datentypen überlegt, kommt raus, das man 
tatsächlich eine doppelte Dereferenzierung braucht.


    array                 char[][]
    array + m             char[][]
    *(array + m)          char[]
    *(array + m) + n      char[]
    *(*(array + m) + n)   char


> Wenn ich jetzt *(array+m) mache, habe ich doch meinen Pointer auf das
> erste Zeichen

Genau genommen hast du einen Pointer auf den Anfang des Strings. Der 
Datentyp nach dieser Dereferenzierung ist immer noch char[], also ein 
Arraytyp.

von mikeii (Gast)


Lesenswert?

Passiert halt mal ;) Aber so wie du es vorher geschrieben hast, wäre es 
wenn man die Adresse selber berechnen möchte (also ohne Pointer 
Arithmetik)

von Karl H. (kbuchegg)


Lesenswert?

mikeii schrieb:
> Passiert halt mal ;) Aber so wie du es vorher geschrieben hast, wäre es
> wenn man die Adresse selber berechnen möchte (also ohne Pointer
> Arithmetik)


Schon mit Pointer Arithmetik.

Das lustige ist, dass eine der beiden Dereferenzierungen nur dazu da 
ist, damit die Datentypen stimmen. Tatsächlich wird dabei aber nichts 
aus dem Speicher geholt.

  **(array + m*sizeof(*array) + n)   <==>   array[m][n]

von Yalu X. (yalu) (Moderator)


Lesenswert?

Karl Heinz Buchegger schrieb:
>   **(array + m*sizeof(*array) + n)   <==>   array[m][n]

Nein, das stimmt wieder nicht ;-)

Die Multiplikation mit m macht die Pointerarithmetik automatisch.

Ich habe mal die diskutierten Array-Zugriffsmethoden zusammengestellt
und noch eine hinzugefügt:
1
#include <stdio.h>
2
3
unsigned char array[15][4] = {
4
  {  11,  12,  13,  14 },
5
  {  21,  22,  23,  24 },
6
  {  31,  32,  33,  34 },
7
  {  41,  42,  43,  44 },
8
  {  51,  52,  53,  54 },
9
  {  61,  62,  63,  64 },
10
  {  71,  72,  73,  74 },
11
  {  81,  82,  83,  84 },
12
  {  91,  92,  93,  94 },
13
  { 101, 102, 103, 104 },
14
  { 111, 112, 113, 114 },
15
  { 121, 122, 123, 124 },
16
  { 131, 132, 133, 134 },
17
  { 141, 142, 143, 144 },
18
  { 151, 152, 153, 154 }
19
};
20
21
int main(void) {
22
  int m=3, n=2;
23
  unsigned char c;
24
25
  c = array[m][n];                              //  43, richtig
26
  printf("%d\n", (int)c);
27
28
  c = *(*(array+m)+n);                          //  43, richtig
29
  printf("%d\n", (int)c);
30
31
  c = **(array + m*sizeof(*array) + n);         // 151, falsch
32
  printf("%d\n", (int)c);
33
34
  c = *((char *)array + m*sizeof(*array) + n);  //  43, richtig
35
  printf("%d\n", (int)c);
36
  return 0;
37
}

von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:
> Karl Heinz Buchegger schrieb:
>>   **(array + m*sizeof(*array) + n)   <==>   array[m][n]
>
> Nein, das stimmt wieder nicht ;-)
>
> Die Multiplikation mit m macht die Pointerarithmetik automatisch.

Ich sollte mich zur Ruhe setzen :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Der Ausdruck
1
 **(array + m*sizeof(*array) + n)

entspräche übrigens
1
  array[m*sizeof(*array) + n][0]

Karl Heinz Buchegger schrieb:
> Ich sollte mich zur Ruhe setzen :-)

Nein, nein, auf keinen Fall =8-o

Nur vielleicht heute mal etwas früher ins Bett gehen :)

von mikeii (Gast)


Lesenswert?

Sizeof brauchst du z.b. wenn du Speicher allokierts, da gehts nicht 
automatisch. Hab mal meinen ganzen C Kram nachgeholt, und hab da 
eigentlich nix mit sizeof gefunden, auser eben Allokation betreffend.

von DirkB (Gast)


Lesenswert?

Das ist mal ein super Beispiel für den Unterschied zwischen Arrays und 
Pointern.

von Paule (Gast)


Lesenswert?

>Ich sollte mich zur Ruhe setzen :-)

Na, aber nur für heute!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.