Kerli hat geschrieben:Xin hat geschrieben:Ein char bla[2]; ist ein Primitiv aus zwei chars. Das kann man so aber nicht übergeben. Man muss die Adresse übergeben. Die Adresse dieses Primitivs mit den zwei Chars ist?
&bla oder bla?
&bla[0]

Nein, hier hast du wohl recht. Da ist das ganze zwar genau festgelegt, aber wohl teilweise mit sehr vielen alternativen Schreibweisen bzw. teilweise wohl etwas unintuitivem Verhalten wie zb bei der Übergabe von bla[n], wo es eigentlich logischer wäre das per Value und nicht nur per Reference zu übergeben. Vermutlich hat hier wohl die Effizienz ihren Einfluss auf diese Entscheidung gehabt...
Definitiv, aber die Semantik ist falsch. Performance hin oder her, das ganze ist etwas schwammig. Möchte ich eine Koordinate übergeben, dann kann das ein double[2] sein. Wenn ich nun einen Zeiger übergebe und in der Funktion viel damit arbeite, dann wäre es performanter die zwei Doubles - wie es die Semantik aussagt - auf den Stack zu packen und gut, statt einen Zeiger zu generieren, diesen auf den Stack zu legen und bei jedem Zugriff erst zu dereferenzieren.
Du musst entweder ein typedef nachreichen oder das Array, dass die Koordinate bezeichnet in zwei doubles aufteilen. Alternativ kopierst Du vor der Verwendung die beiden Elemente in neue Variablen auf den Stack, um die Dereferenzierung zu vermeiden.
An der Stelle hat man teilweise - und je nach Kompiler - etwas merkwürdiges Verhalten.
Kerli hat geschrieben:Man könnte Array ja eigentlich auch anstatt ein Primitiv als eine Schreibweise zur Verwaltung von Speicher auf dem Stack betrachten und somit mit char bla[2]; eine Zeiger auf einen Speicherbereich für zwei chars zu erhalten. Bei dieser Ansicht passt dann aber das Verhalten von sizeof nicht mehr so ganz hinein.
Wenn das Verhalten von sizeof nicht passt, dann passt die Ansicht nicht. Oder das ganze ist an der Stelle schwammig? ^^
Kerli hat geschrieben:Xin hat geschrieben:Und wenn ein char bla[2] ein Primitiv bestehend aus zwei chars ist, dann ist bla[0] ein char. Aber wenn bla ein char * ist, dann ist bla[0] ein char. Was, wenn bla ein char [] ist? Passiert bei char bla[2] und char * bla das gleiche wenn man bla[0] schreibt? Wenn ja - sind sie gleich? Wenn nein, warum kann man sie aufeinander zuweisen? Und kann man sie überhaupt aufeinander zuweisen?
Sie sind nicht gleich, da bei char* bla im Gegensatz zu char bla[2] kein Speicherplatz für chars reserviert wird. Die Zuweisung kann man zb auch in Anlehnung an die Objektorientierte Programmierung erklären. Du kannst ja auch einem Zeiger der Basisklasse einen Zeiger eines abgeleiteten Objekts zuweisen. Genauso kannst du bei einem Array die Anfangsadresse einem Zeiger auf den Typ dieses Arrays zuweisen.
Die Ansicht passt schon besser. Kombiniert mit der Möglichkeit, einen Zeiger implizit mit operator[] verwenden zu dürfen, fällt die semantische Schwachstelle gar nicht mehr richtig auf. Der Punkt ist nunmal, dass ein Zeiger kein Array ist, sondern genau eine bestimmte Position in einem Array (dem Speicher) beschreibt.
Mir fiel das auch erst auf, als ich das im Compiler umsetzen musste, dass ich etwas, was ich als eine Operation ansah, auf einmal an zwei vollkommen verschiedenen Baustellen einbauen musste. Die Sprache gibt diese Unterscheidung nicht offensichtlich her, also wird die Unterscheidung auch nicht für den Sprecher (Programmierer) offensichtlich. Der Compiler kommt aber in beiden Fällen mit einer Adresse an (wo liegt die Variable auf dem Stack?), aber mit unterschiedlichen Datentypen an und muss auch unterschiedliche Reaktionen zeigen: Beim char * muss erst dereferenziert werden, beim char[2] darf nicht dereferenziert werden, weil die Daten auf dem Stack liegen.
Xin hat geschrieben:Kerli hat geschrieben:Xin hat geschrieben:Ich bin mir hingegen sicher, dass feld[3][5] was anderes ist als feld[3*5].
Ja, aber nur was den Zugriff betrifft, im Speicher schauen Beide gleich aus. Beim zweiten Feld wäre zb. feld[1][1] nicht erlaubt...
Und ist im ersten Fall feld[1] erlaubt und wenn ja, was kommt als Datentyp raus? Ein Primitiv oder ein Pointer?
feld ist ein Array mit drei Elementen, die wieder selbst Arrays sind mit je 5 Elementen. Mit feld[1] nimmst erhältst du also ein Array bestehend aus 5 Elementen (Das zweite) und dieses kann wieder implizit in einen Zeiger des selben Typs konvertiert werden, der dann auf das erste Feld des Arrays zeigt.
Mit feld[1] erhältst du also einen Zeiger auf den Anfang des zweiten Elements im Array mit drei Elementen. Im Gegensatz dazu würdest du mit ((char*)feld)[1] das zweite Element des ersten Arrays erhalten.[/quote]
Man bekommt also als Datentyp einen char[5], was quasi in ein char * umgewandelt werden kann.
Wenn man ein char bla[1][2][3] hat und auf auf bla[1] zugreife, dann bekomme ich welchen Daten zurück, wenn ich auf bla[1] zurückgreife?
Wir haben ja festgestellt, dass sich ein char[1][2] wie ein char * verhält, und sich ein Array eines Typs auf ein Typ * automatisch casten lässt. Dann ist ein bla[1][2][3] doch in ein char **... oder?
(Wir drehen uns im Kreis und mir ist das bewusst. Das ist, was ich als schwammig bezeichne ^^)
Kerli hat geschrieben:Xin hat geschrieben:Noch nicht ganz, aber Du machst das bisher gut

Dann hoffe ich, dass es mir auch weiterhin gut gelingt

Yepp, nur hast Du mich noch nicht überzeugt, dass der Umgang in C mit Arrays semantisch sauber durchformuliert ist.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.