What the array?!?



  • CStoll schrieb:

    (man kann es auch übertreiben mit den metasyntaktischen Variablen :D)

    Nö, man bekommt nur Probleme wenn man mal 4 Namen braucht 😃

    CStoll schrieb:

    Das heißt, baz ist kein Zeiger auf int-Zeiger, sondern ein Zeiger auf (fünf-elementige) int-Arrays - und der Compiler weiß das auch.

    Ok, find ich zwar doof, aber na gut.
    Warum geht das dann hier nicht? (Bzw. warum ist die Ausgabe nicht 20?)

    void foo(int bar[5])
    {
      printf("%i\n", sizeof(bar)); // ausgabe 4
      bar[0] = 5;
    }
    
    int main()
    {
      int baz[5];
      baz[0] = 7;
      foo(baz);
      printf("%i\n", baz[0]);
    


  • Siehe oben, Regel 2 - ein Array zerfällt an der Stelle in einen Zeiger, allerdings nur auf der äußersten Ebene.

    PS: Hat die Frage einen tieferen Sinn?



  • Dieser Thread hat mein Vertrauen auf meine Einschätzungsfähigkeit anderer User zutiefst erschüttert.



  • CStoll schrieb:

    Siehe oben, Regel 2 - ein Array zerfällt an der Stelle in einen Zeiger, allerdings nur auf der äußersten Ebene.

    Ach so, das ist in der Bar/Baz Verwirrung jetzt irgendwie untergegangen.

    CStoll schrieb:

    PS: Hat die Frage einen tieferen Sinn?

    Na ja, mehr oder weniger^^
    Ich finde C eigentlich äußerst intuitiv, soll heißen man muss sich doch eigentlich kaum etwas merken, und kann sich fast alles aus einfachen Grundregeln herleiten. Manche Dinge finde aber irgendwie nicht so logisch, und die will ich natürlich aufarbeiten.

    Da wäre z.B. noch die Deklaration von Pointern. Wäre es nicht logischer wenn man duch
    int* a, b;
    2 Pointer bekommen würde? Der * gehört für mich irgendwie zum Datentypen dazu.

    Und halt noch diese Array/Pointer Geschichte. Welchen Sinn hat es, ein Array beim übergeben zwangsläufig zu einem Pointer zu "degradieren"?

    Dieser Thread hat mein Vertrauen auf meine Einschätzungsfähigkeit anderer User zutiefst erschüttert.

    😃



  • cooky451 schrieb:

    CStoll schrieb:

    PS: Hat die Frage einen tieferen Sinn?

    Na ja, mehr oder weniger^^
    Ich finde C eigentlich äußerst intuitiv, soll heißen man muss sich doch eigentlich kaum etwas merken, und kann sich fast alles aus einfachen Grundregeln herleiten. Manche Dinge finde aber irgendwie nicht so logisch, und die will ich natürlich aufarbeiten.

    Da wäre z.B. noch die Deklaration von Pointern. Wäre es nicht logischer wenn man duch
    int* a, b;
    2 Pointer bekommen würde? Der * gehört für mich irgendwie zum Datentypen dazu.

    Das sieht der Standard anscheinend anders - int ist der Typ und Ergänzungen wie * oder [] sind Erweiterungen, die sich auf die jeweilige Variable beziehen. Da haben imho beide Sichtweisen ihre Existenzberechtigung und die Macher von C haben sich für eine Version entschieden.

    Und halt noch diese Array/Pointer Geschichte. Welchen Sinn hat es, ein Array beim übergeben zwangsläufig zu einem Pointer zu "degradieren"?

    Ich würde auf Effizienz tippen - so ein Array ständig zu kopieren kostet nur Zeit und ist in 99% der Fälle auch unnötig.
    (andere Sprachen arbeiten grundsätzlich mit Zeigern und übergeben gar keine reinen Werte)



  • CStoll schrieb:

    Ich würde auf Effizienz tippen - so ein Array ständig zu kopieren kostet nur Zeit und ist in 99% der Fälle auch unnötig.
    (andere Sprachen arbeiten grundsätzlich mit Zeigern und übergeben gar keine reinen Werte)

    Mir ging es ja auch nicht darum, alle Werte des Arrays zu kopieren (wird oben ja auch nicht gemacht), sondern z.B. die Arraygrenzen mitziehen zu können. Wie oben halt. Warum kann man das nur "innerhalb" eines Arrays machen?



  • Vermutlich weil die Größenangaben bereits zur Compilezeit ausgewertet werden - und der Compiler an der Stelle nicht weiß, wie groß das Array wird, mit dem die Funktion später aufgerufen werden soll (wenn sie überhaupt mit einem "regulären" Array aufgerufen wird):

    int func(int values[]);
    
    ...
    int var1[100], var2[50], var3;
    func(var1);
    func(var2);
    func(&var3);
    

    Darum verwendet man in C++ auch lieber Containerklassen, die wissen, wieviele Elemente sie haben.

    PS: Wobei - mit C++ Mitteln kommst du afaik auch an die Größe eines Array heran, mir fällt nur die richtige Syntax dafür nicht mehr ein.



  • CStoll schrieb:

    Vermutlich weil die Größenangaben bereits zur Compilezeit ausgewertet werden - und der Compiler an der Stelle nicht weiß, wie groß das Array wird, mit dem die Funktion später aufgerufen werden soll

    Leuchtet mir nicht ein. Er kann innen doch auch zwischen Pointer und Array unterscheiden. Warum geht das außen nicht? Dass das bei einem [] schwieriger sein könnte, ist klar. Aber nicht bei einem [5]. Die Größe regelt die Deklaration, welche gleichzeitig auch die Regeln zum aufrufen der Funktion regelt. Genauso wie auch innen. Fertig, das wäre logisch - so wie es momentan ist, ist es nicht logisch. Bei void foo(int bar[5]) wird das [5] einfach ignoriert, während es bei void foo(int bar[][5]) auf einmal beachtet wird. Das ist doch alles nicht optimal 😕


  • Mod

    cooky451 schrieb:

    CStoll schrieb:

    Vermutlich weil die Größenangaben bereits zur Compilezeit ausgewertet werden - und der Compiler an der Stelle nicht weiß, wie groß das Array wird, mit dem die Funktion später aufgerufen werden soll

    Leuchtet mir nicht ein. Er kann innen doch auch zwischen Pointer und Array unterscheiden. Warum geht das außen nicht? Dass das bei einem [] schwieriger sein könnte, ist klar. Aber nicht bei einem [5]. Die Größe regelt die Deklaration, welche gleichzeitig auch die Regeln zum aufrufen der Funktion regelt. Genauso wie auch innen. Fertig, das wäre logisch - so wie es momentan ist, ist es nicht logisch. Bei void foo(int bar[5]) wird das [5] einfach ignoriert, während es bei void foo(int bar[][5]) auf einmal beachtet wird. Das ist doch nicht logisch 😕

    😕 Das ist doch total logisch. Bei Übergabe an eine Funktion zerfällt ein Array in einen Zeiger auf sein erstes Element. Bei deinem einen Fall ist es vom Typ int, beim anderen Fall ist es vom Typ int[5]. Ist doch 100% konsequent.
    Wenn das int[5] jetzt auch zu einem Zeiger auf sein erstes Element würde, das wäre unlogisch. Schließlich wird es nicht an die Funktion übergeben. Es wird schließlich nur mit einem Zeiger darauf verwiesen.

    Die Hintergründe für die Geschichte dürften übrigens technischer Art sein: Die Größe der Funktionsparameter muss fix sein. Nun könnte man entweder sagen, dass die Funktion nur ein Array der Größe X annehmen kann, dann wäre man extrem inflexibel oder man macht es eben mit den Zeigern (was zudem noch performanter ist). Die Sprache Pascal macht es beispielsweise anders und man kann an eine Funktion nur Arrays bestimmter Größe übergeben. Du kannst dir sicherlich vorstellen, wie lustig es ist, eine Sortierfunktion zu schreiben und zu benutzen.



  • Der Compiler merkt sich nur das, was er zur korrekten Arbeit benötigt - und bei einem Array benötigt er nur die Größe eines Array-Elements um die Index-Zugriffe korrekt abbilden zu können.
    Bei einem flachen Array sind die Elemente einfache int's (mit einer Größe von 4 Byte) - bei einem mehrdimensionalen Array sind die Elemente wieder kleinere Arrays.
    Dadurch daß er die Gesamtgröße des Arrays nicht mit übergibt, werden die Funktionen flexibler einsetzbar (es reicht schon, wenn du für jeden Datentyp eine eigene Funktion schreiben mußt, aber nicht auch noch für jede mögliche Array-Größe). Bestimmt gab es da auch noch einige weitere Vorteile, die mir auf Anhieb nicht einfallen wollen.

    PS: Und bei deinem int foo(int bar[][]) wird die Gesamtgröße des Arrays genauso unter den Tisch fallen gelassen.



  • SeppJ schrieb:

    Bei Übergabe an eine Funktion zerfällt ein Array in einen Zeiger auf sein erstes Element.

    Wenn man das schon als Grundregel annimmt, ist es natürlich logisch. Meine frage war ja, ob an dieser Grundregel schon etwas nicht stimmt.

    SeppJ schrieb:

    Die Größe der Funktionsparameter muss fix sein.

    Das wäre bei void foo(int v[5]) ja gegeben. Bei void foo(int v[][]) bekommt man ja auch keine Arrays mehr.

    SeppJ schrieb:

    ..dass die Funktion nur ein Array der Größe X annehmen kann, dann wäre man extrem inflexibel..

    Ist man bei void foo(int v[][5]) ja auch. Einem würde ja nicht verboten void foo(int *v) zu nutzen.

    SeppJ schrieb:

    Du kannst dir sicherlich vorstellen, wie lustig es ist, eine Sortierfunktion zu schreiben und zu benutzen.

    Na zum Glück ist das schon an mir vorbei gegangen 😃

    Da mich hier ja alle vom Gegenteil überzeugen wollen, muss ich einfach mal davon ausgehen, dass ich "falsch" liege. Da ich aber immer noch nicht verstehe warum, vielleicht mal ein Ansatz von einer anderen Seite.
    Was wäre schlechter an folgender Regelung:

    void foo(int *v); // Funktioniert wie gewohnt
    void foo(int v[]); // Entweder verboten oder wie Zeiger
    void foo(int v[5]); // Es können nur Arrays der Größe 5 übergeben werden, sizeof(v) ergibt auch 5 * sizeof(int)
    void foo(int v[5][5]); // .. nur [5][5] Arrays.
    


  • kastrollux schrieb:

    Dieser Thread hat mein Vertrauen auf meine Einschätzungsfähigkeit anderer User zutiefst erschüttert.

    Dir gilt mein tiefstes Mitgefühl. Fühl' Dir von mir eine Kerze der Hoffnung entzündet. Wen meintest Du eigentlich?
    Meine kleine C-Forum-Welt ist die Tage auch beinahe zusammengebrochen, als ich den ein oder anderen Post mancher "alter Hasen" gelesen habe...



  • SeppJ schrieb:

    Die Hintergründe für die Geschichte dürften übrigens technischer Art sein: Die Größe der Funktionsparameter muss fix sein. Nun könnte man entweder sagen, dass die Funktion nur ein Array der Größe X annehmen kann, dann wäre man extrem inflexibel oder man macht es eben mit den Zeigern (was zudem noch performanter ist). Die Sprache Pascal macht es beispielsweise anders und man kann an eine Funktion nur Arrays bestimmter Größe übergeben. Du kannst dir sicherlich vorstellen, wie lustig es ist, eine Sortierfunktion zu schreiben und zu benutzen.

    Da es aber eigentlich die impliziete Konvertierung in Zeiger gibt, und man Arrays so über den Zeiger auf das erste Element und einen Zusatzparameter für die Länge übergeben kann, ist die impliziete Umwandlung von Array-Parametern mit Längenangabe in Pointer eigentlich überflüssig wie ein Kropf. Ich fände es besser (und logischer), wenn ein int[5] auch als Funktionsparameter ein int[5] bleiben würde. Wenn man es generisch haben will, nimmt man halt ein int* .



  • kastrollux schrieb:

    alte[.] Hasen

    Die hängen zu viel im C++ Forum rum.

    @Tachyon Ein Lichtblick, ein Mitstreiter, Wohoo! 😃



  • PrettyP schrieb:

    Meine kleine C-Forum-Welt ist die Tage auch beinahe zusammengebrochen, als ich den ein oder anderen Post mancher "alter Hasen" gelesen habe...

    Selbst die "alten Hasen" machen mal Fehler, sei es aus Flüchtigkeit oder Unwissenheit. Egal, wie viele Jahre man sich schon mit etwas beschäftigt, man lernt nie aus 😉

    Tachyon schrieb:

    SeppJ schrieb:

    Die Hintergründe für die Geschichte dürften übrigens technischer Art sein: Die Größe der Funktionsparameter muss fix sein. Nun könnte man entweder sagen, dass die Funktion nur ein Array der Größe X annehmen kann, dann wäre man extrem inflexibel oder man macht es eben mit den Zeigern (was zudem noch performanter ist). Die Sprache Pascal macht es beispielsweise anders und man kann an eine Funktion nur Arrays bestimmter Größe übergeben. Du kannst dir sicherlich vorstellen, wie lustig es ist, eine Sortierfunktion zu schreiben und zu benutzen.

    Da es aber eigentlich die impliziete Konvertierung in Zeiger gibt, und man Arrays so über den Zeiger auf das erste Element und einen Zusatzparameter für die Länge übergeben kann, ist die impliziete Umwandlung von Array-Parametern mit Längenangabe in Pointer eigentlich überflüssig wie ein Kropf. Ich fände es besser (und logischer), wenn ein int[5] auch als Funktionsparameter ein int[5] bleiben würde. Wenn man es generisch haben will, nimmt man halt ein int* .

    Ja, logischer fände ich das auch.



  • kastrollux schrieb:

    Dieser Thread hat mein Vertrauen auf meine Einschätzungsfähigkeit anderer User zutiefst erschüttert.

    👎 Damit kannst du sicher mit leben oder beantworte doch selbst eine solche Frage hinreichend zuverlässig, nachvollziehbar, und jederzeit gebrauchsfähig einsetzbar! 🕶
    Nur unqualifiziert hier motzen ist nicht so erwünscht, weil es nichts bringt! 😃

    daddeldu! :p



  • Das ist doch Erbsenzählerei.
    K&R hatten einen konkreten (und vor allem praktischen) Hintergrund bei ihrem Vorgehen: sie brauchten ein Werkzeug für ihr (auch heutzutage noch wohl nicht ganz unbekanntes) Betriebssystem, nämlich Unix.
    Stroustrup ist Professor und somit Anti-Praktiker, der brauchte etwas, womit er in seinen Vorlesungen bei den Studenten durch Eleganz/Plausibilität aus Akademikersicht glänzen konnte.
    C ist in erster Linie von Programmierern/Entwicklern/Praktikern für Programmierer/Entwickler/Praktiker konzipiert worden und nicht primär als Lernsprache.
    Die offensichtliche Tatsache, dass heute die Professoren ihre Studenten mit C konfrontieren, obwohl sie nachweislich (ich hatte schon mal einen Link zu einem passenden Herrn an der HTW Berlin genannt) selbst die Grundlagen nicht verstanden haben, finde ich einerseits schlecht (sie lehren ihren Studenten oft Fehler), andererseits gut (die Studenten kennen C, wenn auch nur bruchstückhaft und mit vielen Fehlern, aber dazu sind wir ja hier da;-).



  • Die ganze Sache wäre ohnehin einfacher, wenn Arrays richtige Wertsemantik hätten. So dass man ganze Arrays kopieren und zuweisen kann und nicht immer diese impliziten Pointer-Decays hat. Für Low-Level-Programmierung mag das zwar ein nützliches Feature sein, aber in C++ hat man zum Beispiel mit der array -Klasse etwas abstrahiert.



  • Wutz schrieb:

    Das ist doch Erbsenzählerei.
    K&R hatten einen konkreten (und vor allem praktischen) Hintergrund bei ihrem Vorgehen: sie brauchten ein Werkzeug für ihr (auch heutzutage noch wohl nicht ganz unbekanntes) Betriebssystem, nämlich Unix.
    Stroustrup ist Professor und somit Anti-Praktiker, der brauchte etwas, womit er in seinen Vorlesungen bei den Studenten durch Eleganz/Plausibilität aus Akademikersicht glänzen konnte.

    Bjarne Stroustrup war bei Bell Labs, als er C++ entwickelte - genau der selben Einrichtung, in der Brian Kernighan und Dennis Ritchie C entwarfen. Vorlesungen und Studenten hatte er zu dieser Zeit keine.


  • Mod

    cooky451 schrieb:

    Was wäre schlechter an folgender Regelung:

    void foo(int *v); // Funktioniert wie gewohnt
    void foo(int v[]); // Entweder verboten oder wie Zeiger
    void foo(int v[5]); // Es können nur Arrays der Größe 5 übergeben werden, sizeof(v) ergibt auch 5 * sizeof(int)
    void foo(int v[5][5]); // .. nur [5][5] Arrays.
    

    Dass es inkompatibel zu bestehendem Code wäre.


Anmelden zum Antworten