Ich frage mich, warum es nicht möglich ist, Array in C zurückzugeben?
Schließlich ist Array nur ein Zeiger, der durch Größeninformationen unterstützt wird (um sizeof
work zu machen). Zuerst dachte ich, dass dies getan wurde, um zu verhindern, dass ich das auf meinem Stack definierte Array zurücksende, aber nichts hindert mich daran, den Zeiger auf etwas auf meinem Stack zurückzugeben (gcc warnt mich, aber Code kompiliert). Und ich kann auch String-Literal zurückgeben, das ein statisch gespeichertes Array von Zeichen ist. Übrigens, in lunux ist es in .rodata
gespeichert, und const array ist dort auch gespeichert (überprüfe es mit objdump
), also kann ich Array zurückgeben (es zum Zeiger umwandeln) und es funktioniert, aber AFAIK das ist nur implementierungsspezifisch (ein anderer OS / Compiler kann const auf Stack speichern).
Ich habe zwei Ideen, wie man das Array returning implementiert: Man kopiert es einfach als Wert (wie es für die Struktur getan wird. Ich kann sogar ein Array zurückgeben, das es in die Struktur einwickelt !!), und den Zeiger automatisch erzeugen oder dem Benutzer erlauben zurückzukehren const array und create contract, dass ein solches Array eine statische Speicherdauer haben sollte (wie es bei Strings der Fall ist). Beide Ideen sind trivial! Also, meine Frage ist, warum K & amp; R so etwas nicht umgesetzt hat?
Ein Array ist nicht "nur ein Zeiger, der durch Größeninformationen unterstützt wird".
Ein Array ist ein Block zusammenhängender Elemente eines bestimmten Typs. Es gibt keinen Zeiger.
Da ein Array ein Objekt ist, kann ein Zeiger gebildet werden, der auf das Array oder auf eines der Elemente des Arrays zeigt. Ein solcher Zeiger ist jedoch nicht Teil des Arrays und wird nicht mit dem Array gespeichert. Es wäre genauso sinnvoll zu sagen "Ein int
ist nur ein Zeiger, der von einer Größe von 1
int" unterstützt wird.
Die Größe eines Arrays ist dem Compiler genauso bekannt wie die Größe eines Objekts. Wenn wir double d;
haben, ist es bekannt, dass sizeof d
sizeof(double)
ist, weil der Compiler daran erinnert, dass d
ein Objekt vom Typ double
ist.
Nichts hindert mich daran, den Zeiger auf etwas auf meinem Stapel zurückzugeben
Der C-Standard verhindert dies (und verwendet den zurückgegebenen Zeiger). Wenn Sie Code schreiben, der gegen den Standard verstößt, dann sind Sie allein.
Und ich kann auch String-Literal
zurückgeben
Ein String-Literal ist ein Array von Zeichen. Wenn Sie ein Array in einer return-Anweisung verwenden, wird es in einen Zeiger auf das erste Element konvertiert.
Damit Arrays nach Wert zurückgegeben (und zugewiesen) werden können, müsste die Regel bezüglich der Umwandlung von Array in Zeiger (manchmal "Verfall" genannt) geändert werden. Dies wäre möglich, aber K & R entschied sich dafür, den Zerfall bei der Entwicklung von C fast allgegenwärtig zu machen.
Tatsächlich wäre es möglich, eine Sprache wie C zu haben, aber ohne den Zerfall zu haben. Vielleicht hätte das im Nachhinein viel Verwirrung gespart. Sie haben sich jedoch dafür entschieden, C so zu implementieren, wie sie es getan haben.
In K & amp; R C war es auch nicht möglich, Strukturen als Wert zurückzugeben. Jede Kopieroperation, die kein primitiver Typ war, musste mit memcpy
oder einer äquivalenten iterativen Kopie durchgeführt werden. Dies scheint eine vernünftige Design-Entscheidung angesichts der Art und Weise, wie Hardware-Ressourcen in den 1970er Jahren waren.
ANSI C fügte die Möglichkeit hinzu, Strukturen wertmäßig zurückzugeben, aber zu diesem Zeitpunkt wäre es zu spät gewesen, die Zerfallsregel zu ändern, selbst wenn sie es gewollt hätten; es würde viel vorhandenen Code brechen, der sich auf die Zerfallsregel verlässt.
Technisch können Sie ein Array zurückgeben; Sie können es einfach nicht "direkt" machen, sondern müssen es in eine Struktur einfügen:
%Vor%Warum C es dir nicht erlaubt, es direkt zu tun, obwohl es die Fähigkeit hat, ist immer noch eine gute Frage. Es hängt wahrscheinlich mit der Tatsache zusammen, dass es auch keine Ganz-Array-Zuweisungen unterstützt:
%Vor%Was es noch seltsamer macht, ist natürlich, dass die gesamte Array-Kopie über das Argument-Passing unterstützt wird. Wenn jemand weiß, wie er die Entscheidungen des ANSI-Komitees zu diesem Thema finden kann, wäre das interessant zu lesen.
Allerdings
Schließlich ist das Array nur ein Zeiger, der durch Größeninformationen unterstützt wird (um die Größe der Arbeit zu bestimmen).
Das ist nicht korrekt. Es gibt weder einen expliziten Zeiger noch eine gespeicherte Größe eines Arrays. Das Array wird als Rohwerte zusammen verpackt gespeichert. Die Größe ist nur innerhalb des Compilers bekannt und wird niemals als Laufzeitdaten im Programm explizit gemacht. Das Array zerfällt in einen Zeiger , wenn Sie versuchen, es als einen zu verwenden.
Wenn eine Überarbeitung der Sprache plötzlich dazu führt, dass eine Funktion in der Lage ist, ein vollständiges Array zurückzugeben, sollte diese Revision auch diese Situationen behandeln:
Wenn diese Konstruktionen erlaubt sind, werden existierende Programme, die den Namen eines Arrays als Argument an eine Funktion übergeben und erwarten, dass die Funktion dieses Array ändert, nicht mehr funktionieren.
Auch bestehende Programme, die den Namen des Arrays als Zeiger verwenden, um ihn einer Zeigervariablen zuzuordnen, funktionieren nicht mehr.
Obwohl es technisch machbar ist, Arrays so zu machen, dass sie als komplette Entitäten funktionieren, die zugewiesen, zurückgegeben und so weiter werden können, würde das viele existierende Programme zerstören.
Beachten Sie, dass Strukturen "aktualisiert" werden konnten, da es keine vorherige Semantik in der K & amp; R C gab, die den Namen einer Variablenstruktur als einen Zeiger auf sich selbst bezeichnete. Jede Funktion, die Strukturen als Argumente oder Rückgabewerte verwenden musste, musste Zeiger auf sie verwenden.
Der "Grund" ist, dass Arrays zerfallen auf Zeiger in den meisten Ausdrücken und die Dinge würden "so falsch" sein, als wenn Sie die Zuweisung von Arrays erlauben würden. Wenn Sie ein Array von einer Funktion zurückgeben würden, könnten Sie es nicht von einem normalen Zeiger unterscheiden. Wenn f()
double[5]
zurückgibt, sagen wir die Initialisierung
wäre gültig. A
würde die Adresse eines temporären Objekts annehmen, was in C nur bis zum Ende des vollständigen Ausdrucks reicht, bei dem der Aufruf von f
aufgetreten ist. Also wäre A
ein fliegender Zeiger, ein Zeiger, der auf eine Adresse zeigt, die nicht mehr gültig ist.
Zusammenfassend: Die anfängliche Entscheidung, dass sich Arrays in den meisten Kontexten den Zeigern ähnlich verhalten, erzwingt, dass Arrays nicht von Funktionen zugewiesen oder zurückgegeben werden können.