What the array?!?
-
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 einint[5]
bleiben würde. Wenn man es generisch haben will, nimmt man halt einint*
.
-
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 einint[5]
bleiben würde. Wenn man es generisch haben will, nimmt man halt einint*
.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.
-
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.
-
camper schrieb:
Dass es inkompatibel zu bestehendem Code wäre.
Wieso wusste ich dass das jetzt kommt?
Das ist ja kein Argument, solange wir nicht den ISO Standard schreibenDie Frage war ja, was logischer ist.
(Abgesehen davon finde ich eh die sollten lieber die Sprache schön halten, als mit Typen wie _bool anzukommen. Compiler die aktuellen Code kompilieren können gibt's doch genug. Aber das ist ein ganz anderes Thema.)
-
_Bool ist eigentlich nicht dazu gedacht, direkt benutzt zu werden. IdR bindet man stdbool.h ein und benutzt dann bool, true und false.
Was die Arrays angeht, so ist es schwierig, diese Dinge zur Compilezeit festzustellen. Wenn ich jetzt
void foo(int arr[5]); ... size_t i; int *ptr = malloc(7 * sizeof(int[5])); for(i = 0; i < 7; ++i) { foo(ptr + i * 5); }
schreibe, ist es für einen Compiler schon schwer herauszufinden, ob das, was ich da mache, auch korrekt ist. Er muss es dementsprechend durchlassen, denn nichts ist nutzloser als ein Compiler, der nicht tut, was man ihm sagt.
Es gibt in C99 ein Sprachmittel, dass es einem Compiler erlauben würde, in einfachen Fällen zu warnen:
void foo(int arr[static 5]);
Allerdings verhält sich gcc 4.6 (andere C99-Compiler habe ich nicht zur Hand) bei
int a[3]; foo(a); /* Undefiniert nach 6.7.5.3 (7) */
selbst mit -Wall -Wextra -pedantic ruhig. Womöglich ändert sich das aber in zukünftigen Versionen.
Der Vollständigkeit halber:
ISO/IEC 9899:1999 6.7.5.3 (6) schrieb:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
-
seldon schrieb:
Was die Arrays angeht, so ist es schwierig, diese Dinge zur Compilezeit festzustellen. Wenn ich jetzt
void foo(int arr[5]); ... size_t i; int *ptr = malloc(7 * sizeof(int[5])); for(i = 0; i < 7; ++i) { foo(ptr + i * 5); }
schreibe, ist es für einen Compiler schon schwer herauszufinden, ob das, was ich da mache, auch korrekt ist. Er muss es dementsprechend durchlassen, denn nichts ist nutzloser als ein Compiler, der nicht tut, was man ihm sagt.
Das wäre natürlich verboten, dafür gibt's ja int*. Folgendes ist ja auch nicht erlaubt:
void foo(int bar[][5]); int main() { int **baz = malloc(..); for (..;..;..) baz[i] = malloc(..); foo(baz); }
-
Moment, jetzt bringst du Zeiger und Arrays durcheinander. Ein zweidimensionales Array enthält keinerlei Zeiger - die Dimensionierung ist nur eine Frage der Indexumrechnung.
Es ist ohne Weiteres möglich,
void foo(int a[][5]); ... int (*ptr)[5] = malloc(7 * sizeof(int[5])); foo(ptr);
zu schreiben. Es geht sogar mit
int arr[20]; foo(arr);
Dann entspricht a[2][2] in foo arr[12] außerhalb. Allerdings dürfte das ohne Cast eine Compilerwarnung auslösen.