Forum: PC-Programmierung C: Zeiger auf Array mit struct Elementen


von Hacker (Gast)


Lesenswert?

Hi Leute


Ich code gerade einen Parser für GIF89a Header und will die optionale 
Palette verarbeiten. Dazu habe ich folgende Deklarationen vorbereitet:
1
struct rgbtriple {
2
   uint8_t r,g,b;
3
};
4
5
struct rgbtriple (*palette)[];   // Zeiger auf Array mit unbestimmter Groesse

So versuche ich auf die Palette zuzugreifen:
1
   if (gct_size) {
2
      palette = calloc(gct_size, sizeof(struct rgbtriple));
3
      if (palette == NULL) {
4
         printf("calloc() failed!\r\n");
5
         return -1;
6
      }
7
      fread(palette, gct_size, sizeof(struct rgbtriple), fp);
8
      for (c=0; c < gct_size; c++) {
9
         printf("%03d %02X:%02X:%02X\r\n",
10
            c, palette[c]->r, palette[c]->g, palette[c]->b);
11
      }
12
      free(palette);
13
   }

GCC meckert mir an:
 error: invalid use of array with unspecified bounds


Wie mach ich das korrekt? Ich kann natürlich tricksen:
1
struct rgbtriple (*palette)[1000];   // Zeiger auf Array

...aber das ist doch nicht der Sinn der Sache?

von (prx) A. K. (prx)


Lesenswert?

Probiers mal so:
1
struct rgbtriple *palette[];

von Peter II (Gast)


Lesenswert?

Hacker schrieb:
> struct rgbtriple (*palette)[];

sieht merkwürdig aus.

teste mal mit:

struct rgbtriple *palette;

von (prx) A. K. (prx)


Lesenswert?

Yep, klar. Er will ja kein Array von Pointern...

von Stefan E. (sternst)


Lesenswert?

Und im Zugriff dann "palette[c]." und nicht "palette[c]->".

von Stefan E. (sternst)


Lesenswert?

Und so nebenbei:
Für die ursprüngliche Deklaration von palette sieht der Zugriff dann so 
aus:
(*palette)[c].

von Hacker (Gast)


Lesenswert?

Uff mit dem Pointern tu' ich mir immer noch/wieder etwas schwer.

Wie gesagt, palette ist ein Zeiger auf ein Aaray, dessen Grösse erst zur 
Laufzeit ermittelt wird, also:
1
struct rgbtriple (*palette)[];   // Zeiger auf Array mit unbestimmter Groesse

Pointer auf Array deferenzieren, dann Index, dann Element aus struct, 
also:
1
(*palette)[c].r

Das ist doch dasselbe wie
1
palette[c]->r

???

von Hacker (Gast)


Lesenswert?

Wohl doch nicht? Wenn ich wie eben hergeleitet so dereferenziere:
1
(*palette)[c].r

funzt das prima mit dieser Deklaration von /palette/:
1
struct rgbtriple (*palette)[];   // Zeiger auf Array mit unbestimmter Groess

Okay. Gut. Weiter. ;)
Danke für eure Zeit.

von (prx) A. K. (prx)


Lesenswert?

Hacker schrieb:

> Uff mit dem Pointern tu' ich mir immer noch/wieder etwas schwer.

Vielleicht hilft dir die Erkenntnis, dass bei
  int a[10];
der Name "a" vom Typ her nicht für ein Array steht, sondern für einen 
Pointer auf das erste Element. Das ist ein bischen schräg, aber so ist C 
eben.

Infolgedessen ist bei
1
   int a[];
2
   int *p;
von den Datentypen her dies beides gleich:
1
   a[i];
2
   p[i];

von (prx) A. K. (prx)


Lesenswert?

Hacker schrieb:

> Wohl doch nicht? Wenn ich wie eben hergeleitet so dereferenziere:

Funktioniert auch, ist aber ein ausgesprochen unüblicher Weg und sieht 
auch recht hässlich aus.

von Stefan E. (sternst)


Lesenswert?

Hacker schrieb:
> Wie gesagt, palette ist ein Zeiger auf ein Aaray, dessen Grösse erst zur
> Laufzeit ermittelt wird, also:

Ja, aber ein simples "struct rgbtriple *palette;" erledigt das gleiche, 
und ist weniger kompliziert, sowohl bei der Deklaration, wie auch beim 
Zugriff.

> Das ist doch dasselbe wie
>
> palette[c]->r

Nein. Wenn palette ein Pointer auf ein Array ist, dann ist palette[c] 
das c-te Array in einem Array solcher Arrays.

Merke dir: "x[y]" ist immer das Gleiche wie "*(x+y)".

von (prx) A. K. (prx)


Lesenswert?

Wenn er jetzt noch verstanden hat, dass er deshalb in seiner Version 
genauso gut
   c[*palette].r
schreiben kann, dann hat er das Thema Arrays&Pointer durch. ;-)

von Hacker (Gast)


Lesenswert?

A. K. schrieb:

> Funktioniert auch, ist aber ein ausgesprochen unüblicher Weg und sieht
> auch recht hässlich aus.

Somit ist das dasselbe?
1
(*palette)[c].r
2
// und
3
palette[c].r

von (prx) A. K. (prx)


Lesenswert?

Hacker schrieb:

> Somit ist das dasselbe?

Nein. Nur taucht in C der von dir so verzweifelt geklammerte Datentyp 
"Array" eher selten auf. Meist hat man es mit Pointern auf die Elemente 
zu tun, auch wenns nur der auf das erste Element ist.

> (*palette)[c].r

palette ist array und passt zu
  struct rgbtriple (*palette)[];

> palette[c].r

pallete ist pointer auf erstes Element und passt zu
  struct rgbtriple *palette;

von Hacker (Gast)


Lesenswert?

A. K. schrieb:

> Nein. Nur taucht in C der von dir so verzweifelt geklammerte Datentyp
> "Array" eher selten auf. Meist hat man es mit Pointern auf die Elemente
> zu tun, auch wenns nur der auf das erste Element ist.

Ahhh jetzt ist klar, dankeschön.

von Martin (Gast)


Lesenswert?

Hacker schrieb:
> Ahhh jetzt ist klar, dankeschön.

Das glaubst du nur. Denn hier sieht man mal wieder sehr schön, daß man 
nicht alles glauben darf, was im Internet steht.

Dieser Thread ist eine Ansammlung von Halb- und Unwahrheiten, zum Haare 
raufen.

Wenigstens sind die Leute hilfsbereit gewesen.

Dennoch an dich den ernstgemeinten Rat: Lerne C. Richtig. Nicht auf 
dieser Ebene von "wir fummeln das mal so hin, daß irgendwas tut und 
erfinden uns dann eine Begründung, warum es tut".

Zur Sache:

Peter II schrieb (und wurde bereits korrigiert):
| struct rgbtriple *palette;

Das ist natürlich großer Käse. C-Deklarationen sind auf den ersten Blick 
sehr kompliziert, auf den zweiten aber gar nicht.

Lesetipp: 
http://www.ericgiguere.com/articles/reading-c-declarations.html
Zum schnellen Anwenden in der Praxis: http://www.cdecl.org

Du selbst schriebst:

| Pointer auf Array deferenzieren, dann Index, dann Element aus struct,
| also:
|
| (*palette)[c].r
|
| Das ist doch dasselbe wie
|
| palette[c]->r

Nein, palette[c] ist offensichtlich schon Käse, denn palette ist kein 
Array, sondern ein Zeiger auf ein Array.

Dann schrieb A.K.:

| Vielleicht hilft dir die Erkenntnis, dass bei
|   int a[10];
| der Name "a" vom Typ her nicht für ein Array steht, sondern für einen
| Pointer auf das erste Element. Das ist ein bischen schräg, aber so ist C
| eben.

Das wäre tatsächlich ein bißchen schräg. Glücklicherweise ist die 
Behauptung schon Unfug.

a ist in der Deklaration ein Array. Kein Zeiger. Und damit auch kein 
"Zeiger auf das erste Element".

| Infolgedessen ist bei
|
|    int a[];
|    int *p;
|
| von den Datentypen her dies beides gleich:
|
|    a[i];
|    p[i];

ist daher auch falsch.

A.K. kommt gleich nochmal:

| Wenn er jetzt noch verstanden hat, dass er deshalb in seiner Version
| genauso gut
|    c[*palette].r
| schreiben kann, dann hat er das Thema Arrays&Pointer durch. ;-)

und bringt damit das am häufigsten genannte "Herr Lehrer, ich weiß 
was!"-Gimmick aller Sprachen. Außerhalb von http://www.ioccc.org/ hat in 
den Jahrzehnten, in denen nun schon C programmiert wird, noch niemand 
einen Anwendungszweck für diese Kommutativität gefunden.

Und schließlich nochmal A.K.:

| Nein. Nur taucht in C der von dir so verzweifelt geklammerte Datentyp
| "Array" eher selten auf. Meist hat man es mit Pointern auf die Elemente
| zu tun, auch wenns nur der auf das erste Element ist.

Wie oben bereits erwähnt: C hat im Gegensatz zum Irrglauben vieler sehr 
wohl Arrays. Und sie tauchen keineswegs selten auf.

Lediglich in ganz bestimmten Kontexten "zerfallen" Arrays ("decays") zu 
Zeigern auf ihr erstes Element. In formalen Parametern beispielsweise.

Zuguterletzt noch ein Lesetipp: http://www.c-faq.com
Speziell Kapitel sechs.

Schönen Abend und noch viel Freude mit C.

von (prx) A. K. (prx)


Lesenswert?

Martin schrieb:

> a ist in der Deklaration ein Array. Kein Zeiger. Und damit auch kein
> "Zeiger auf das erste Element".

"a" ist vor der Deklaration her ein Array, aber nicht, wenn der Name 
unverziert in einem Ausdruck steht. Dann ist es vom Datentyp her ein 
Pointer, ausser wenn es in sizeof steht.

> |    a[i];
> |    p[i];
>
> ist daher auch falsch.

Auch hier war die Verwendung gemeint, nicht die Deklaration.

> und bringt damit das am häufigsten genannte "Herr Lehrer, ich weiß
> was!"-Gimmick aller Sprachen.

Das war halb Jux halb ernst, denn wie schon davon vom jemanden skizziert 
wird ist a[i] identisch mit *(a+i) und es hilft sehr, wenn man sich das 
gelegentlich vor Augen führt. Die Kommutativität ist nur eine kuriose 
Folge davon, die von mir auch sprachlich nicht den Fragesteller 
adressierte.

> Wie oben bereits erwähnt: C hat im Gegensatz zum Irrglauben vieler sehr
> wohl Arrays. Und sie tauchen keineswegs selten auf.

Hättest du ein repräsentatives Beispiel für C Expressions, in dem der 
Datentyp(!) Array ausserhalb sizeof/cast auftaucht? Grad sizeof ist auch 
nicht unbedingt sehr logisch, denn in sizeof(a) ist a ein Array, in p=a 
oder *a aber ein Pointer.

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.