Jochen schrieb:
> Bei der Struktur Structb sagt der Compiler er, dass die Größe von
> arrayVonA und arrayInts nicht bekannt sind.
Logisch.
Beantworte einfach mal, nur für dich selber, folgende Frage:
Deine ursprüngliche Strukturdefinition und gegeben dieser Code
1 | void foo( Structb* pObj )
|
2 | {
|
3 | pObj->arrayInts[0] = 5;
|
4 | }
|
von der Adresse in pObj an gezählt, wieviele Bytes nach Beginn dieses
Objektes beginnt denn das Array arrayInts im Speicher? Egal für welches
Structb Objekt.
Du bist millionenfach intelligenter als der Compiler und kannst die
Frage nicht beantworten. Wenn du die Frage nicht beantworten kannst, wie
soll das dann der Compiler können?
Du siehst in dem hier etwas, was es nicht ist.
1 | int werteArray[] = { 1, 2, 3, 4};
|
Das hier ist nicht irgendeine Form von magisch dynamischen Array.
Das steht eigentlich
1 | int werteArray[4] = { 1, 2, 3, 4};
|
nur dass die der Compiler als besonderen Service anbietet, dass du die 4
in diesem Fall weglassen kannst, indem der Compiler die Anzahl der
Initialisierungen zählt. Das geht aber nur deshalb, weil der Compiler
weiß, was ein int ist, und wieviel Speicherplatz ein einzelner int
belegt. Daher kann man hier in einem Rutsch ein Array von int anlegen
und den Compiler den dafür notwendigen Speicherplatz anhand der
Initialisierungen festlegen lassen.
Aber mehr steckt da nicht dahinter. Da wird nicht irgendwo magisch
Information abgelegt, dass dieses Array jetzt mit 4 Elementen erzeugt
wurde und dieses hier
1 | int andereWerte[] = { 42, 27, 19, 15, -8 };
|
mit 5. In beiden Arrays ist jeder einzelne int immer gleich gross. Nur
die Größe der kompletten Arrays unterscheidet sich. In
wobei T für irgendeinen beliebigen Datentyp steht (also auch
Strukturen!) muss die Größe für T bekannt sein! Und es muss für jeden
Datentyp (also auch für selbstgeschriebene Strukturen!) möglich sein auf
diese Art ein Array zu erzeugen. Daher kann deine Strukturdefinition
nicht akzeptiert werden, weil sie eben genau diese Voraussetzung, eine
bekannte und konstante Größe zu haben, nicht erfüllt.
In
1 | struct s
|
2 | {
|
3 | int a;
|
4 | int b;
|
5 | int c[5];
|
6 | int d;
|
7 | };
|
muss jeder Member eine eindeutige Adresslage in Bezug auf den Anfang des
Arrays haben und auch eine eindeutig festgelegte Größe. Und zwar
unabhängig davon, was dann konkret in einem struct s Objekt abgelegt
wird. Ob du im c Member dann nur 3 int speicherst anstelle der 5, die
möglichen wären, das bleibt dir überlassen, aber JEDES struct s Objekt
hat erst mal ein Array von 5 int im c-Member. Und das muss auch so sein,
weil der Compiler ja abgesehen von der eigentlichen Variablendefinition
bei der Verwendung der Struktur ja nicht wissen kann, wieviele Array
Elemente du dann wirklich angelegt hast - an dieser Stelle muss das
konstant und für alle struct s Objekte gleich sein.
Was du natürlich tun kannst, du kannst dann ein Array von struct s
Obekten anlegen und dort dann wieder den Compiler die Initialisierungen
zählen lassen
1 | struct s Mys[] = {
|
2 | { 1, 2, { 0, 1, 2, 3, 4 }, 42 },
|
3 | { 8, 0, { 6, 7, 3, 0, 0 }, 23 }
|
4 | };
|
Aber jedes einzelne der struct s Objekte in diesem Array hat den
gleichen Aufbau und muss ihn auch haben, damit man bei
errechnen kann, welches Bytes ab Beginn des Mys Arrays an gerechnet bei
dieser Zuweisung betroffen sind. Und das geht nur, wenn alle Objekte im
Array die gleiche Größe haben. (Denn das muss ja auch möglich sein, wenn
man die Variablendefinition nicht sieht! Nur aus der Strukturdefinition,
der Anweisung und der Startadresse des Arrays im Speicher muss man
errechnen können, wo im Speicher die Manipulation stattfindet. Denn was
anderes hast du in Funktionen meistens nicht)
Denk dir einfach immer: Der Compiler kann nicht zaubern. Wenn du etwas
nicht errechnen kannst, dann kann es der Compiler auch nicht.
Einfach mal ein wenig darüber nachdenken, warum die Dinge so sind wie
sie sind. Dann wird vieles klarer und einiges verliert diesen
Geheimnisvoll-Nimbus.