Ich habe ein Array int arr[5]
, das an eine Funktion übergeben wird fillarr(int arr[])
:
int fillarr(int arr[])
{
for(...);
return arr;
}
- Wie kann ich dieses Array zurückgeben?
- Wie werde ich es verwenden, sagen wir, ich habe einen Zeiger zurückgegeben, wie werde ich darauf zugreifen?
std::vector
.5
Signatur in der Funktion wird vom Compiler verworfen.Antworten:
In diesem Fall kann Ihre Array-Variable
arr
durch eine implizite Konvertierung auch als Zeiger auf den Anfang des Blocks Ihres Arrays im Speicher behandelt werden. Diese Syntax, die Sie verwenden:Ist nur syntaktischer Zucker. Sie könnten es wirklich dadurch ersetzen und es würde immer noch funktionieren:
Im gleichen Sinne ist das, was Sie von Ihrer Funktion zurückgeben möchten, tatsächlich ein Zeiger auf das erste Element im Array:
Und Sie können es trotzdem wie ein normales Array verwenden:
quelle
array
und&array
sind in vielen Fällen austauschbar.a
inint a[10]
istint[10]
. Was Sie sagen können, ist, dass Arrays in Zeiger auf ihr erstes Element "zerfallen". (Dies ist eine implizite Array-zu-Zeiger-Konvertierung.) Dann würde Ihre Antwort in die Richtung gehen, die meine tut. Wenn Sie Ihre Antwort bearbeiten, um zwischen Arrays, Array-zu-Zeiger-Konvertierung und Zeigern zu unterscheiden, lösche ich meine Antwort, da sie dieselben Kerninformationen enthalten würden und Sie der Erste waren.C ++ - Funktionen können keine Arrays im C-Stil nach Wert zurückgeben. Am nächsten ist es, einen Zeiger zurückzugeben. Darüber hinaus wird ein Array-Typ in der Argumentliste einfach in einen Zeiger konvertiert.
Sie können es verbessern, indem Sie Array-Referenzen für das Argument und die Rückgabe verwenden, wodurch der Zerfall verhindert wird:
Bei Boost oder C ++ 11 ist die Referenzübergabe nur optional und die Syntax ist weniger umwerfend:
Die
array
Vorlage generiert einfach einstruct
Array mit einem C-Stil, sodass Sie eine objektorientierte Semantik anwenden und dabei die ursprüngliche Einfachheit des Arrays beibehalten können.quelle
typedef int array[5]; array& foo();
Sie benötigen jedoch nicht einmal das typedef, wenn Sie dies schreiben möchten:int (&foo())[5] { static int a[5] = {}; return a; }
Das Beispiel in der Frage wäre :int (&foo( int (&a)[5] ))[5] { return a; }
. Einfach, nicht wahr?error: function returning array is not allowed
die auftritt, wenn Sie die äußeren Parens in der Nicht-Typedef-Syntax weglassen. Glücklicherweise habe ich heute die Rechts-Links-Regel auf eine andere Frage überprüft und es geschafft, das Richtige zu konstruieren ... nachdem ich gesehen habe, dass es möglich ist ... bevor ich gesehen habe, dass Sie den Code gegeben haben: vP.In C ++ 11 können Sie zurückkehren
std::array
.quelle
(...) you can consider the array returned arr2, totally another array (...)
$ 8.3.5 / 8 Staaten-
"Funktionen dürfen keinen Rückgabetyp vom Typ Array oder Funktion haben, obwohl sie einen Rückgabetyp vom Typ Zeiger oder Verweis auf solche Dinge haben können. Es darf keine Arrays von Funktionen geben, obwohl es Arrays von Zeigern auf Funktionen geben kann."
quelle
int
ein Array zurück.Die Antwort hängt möglicherweise davon ab, wie Sie diese Funktion verwenden möchten. Lassen Sie uns für die einfachste Antwort entscheiden, dass Sie anstelle eines Arrays wirklich einen Vektor wünschen. Vektoren sind schön, weil das Aussehen für die ganze Welt wie langweilige, gewöhnliche Werte ist, die Sie in regulären Zeigern speichern können. Wir werden uns andere Optionen ansehen und warum Sie sie später wollen:
Dies wird genau das tun, was Sie erwarten. Der Vorteil ist,
std::vector
dass alles sauber gehandhabt wird. Der Nachteil ist, dass dadurch eine sehr große Datenmenge kopiert wird, wenn Ihr Array groß ist. Tatsächlich kopiert es jedes Element des Arrays zweimal. Zuerst wird der Vektor kopiert, damit die Funktion ihn als Parameter verwenden kann. dann kopiert es es erneut, um es an den Anrufer zurückzugeben. Wenn Sie den Vektor selbst verwalten können, können Sie die Dinge viel einfacher erledigen. (Es kann ein drittes Mal kopiert werden, wenn der Anrufer es in einer Variablen speichern muss, um mehr Berechnungen durchzuführen.)Es sieht so aus, als ob Sie wirklich nur versuchen, eine Sammlung zu füllen. Wenn Sie keinen bestimmten Grund haben, eine neue Instanz einer Sammlung zurückzugeben, tun Sie dies nicht. wir können es so machen
Auf diese Weise erhalten Sie einen Verweis auf das an die Funktion übergebene Array, keine private Kopie davon. Alle Änderungen, die Sie am Parameter vornehmen, werden vom Aufrufer angezeigt. Sie könnten einen Verweis darauf zurückgeben, wenn Sie möchten, aber das ist keine wirklich gute Idee, da dies impliziert, dass Sie etwas anderes bekommen als das, was Sie bestanden haben.
Wenn Sie wirklich eine neue Instanz der Sammlung benötigen, diese aber nicht auf dem Stapel haben möchten (und das damit verbundene Kopieren), müssen Sie einen Vertrag für die Behandlung dieser Instanz erstellen. Der einfachste Weg, dies zu tun, ist die Verwendung eines intelligenten Zeigers, der die referenzierte Instanz so lange in der Nähe hält, wie jemand daran festhält. Es geht sauber weg, wenn es außerhalb des Anwendungsbereichs liegt. Das würde so aussehen.
Die Verwendung
*myArr
funktioniert größtenteils identisch mit der Verwendung eines einfachen Vanillevektors. In diesem Beispiel wird auch die Parameterliste durch Hinzufügen desconst
Schlüsselworts geändert. Jetzt erhalten Sie eine Referenz, ohne sie zu kopieren, aber Sie können sie nicht ändern, sodass der Anrufer weiß, dass sie dieselbe ist wie vor dem Aufrufen der Funktion.All dies ist gut, aber idiomatisches C ++ funktioniert selten mit Sammlungen als Ganzes. Normalerweise verwenden Sie Iteratoren für diese Sammlungen. das würde eher so aussehen
Die Verwendung sieht etwas seltsam aus, wenn Sie diesen Stil nicht gewohnt sind.
foo zeigt jetzt auf den Anfang des Modifizierten
arr
.Das Schöne daran ist, dass es auf Vektoren genauso gut funktioniert wie auf einfachen C-Arrays und vielen anderen Arten von Sammlungen
Was jetzt sehr nach den einfachen Zeigerbeispielen aussieht, die an anderer Stelle in dieser Frage gegeben wurden.
quelle
&
Symbol muss nach dem Typ erscheinen:void fillarr(std::vector<int> & arr)
Dies:
wird tatsächlich genauso behandelt wie:
Wenn Sie nun wirklich ein Array zurückgeben möchten, können Sie diese Zeile in ändern
Es gibt nicht wirklich ein Array zurück. Sie geben einen Zeiger auf den Anfang der Array-Adresse zurück.
Denken Sie jedoch daran, dass Sie beim Übergeben des Arrays nur einen Zeiger übergeben. Wenn Sie also die Array-Daten ändern, ändern Sie tatsächlich die Daten, auf die der Zeiger zeigt. Bevor Sie das Array übergeben, müssen Sie daher feststellen, dass Sie das geänderte Ergebnis bereits außen haben.
z.B
Ich schlage vor, Sie möchten vielleicht eine Länge in Ihre Fillarr-Funktion wie diese einfügen.
Auf diese Weise können Sie die Länge verwenden, um das Array auf seine Länge zu füllen, egal was es ist.
Um es tatsächlich richtig zu benutzen. Mach so etwas:
Wenn Sie das Array nur auf einige Standardwerte setzen möchten, sollten Sie die integrierte Memset-Funktion verwenden.
so etwas wie: memset ((int *) & arr, 5, sizeof (int));
Während ich beim Thema bin. Sie sagen, Sie verwenden C ++. Schauen Sie sich die Verwendung von STL-Vektoren an. Ihr Code ist wahrscheinlich robuster.
Es gibt viele Tutorials. Hier ist eine, die Ihnen eine Vorstellung davon gibt, wie Sie sie verwenden können. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
quelle
std::copy
vorbeimemset
, es ist sicherer und einfacher. (Und genauso schnell, wenn nicht schneller.)Um ein Array von einer Funktion zurückzugeben, definieren wir dieses Array in einer Struktur. Es sieht also ungefähr so aus
Lassen Sie uns nun Variablen der Typstruktur erstellen.
Wir können ein Array auf folgende Weise an eine Funktion übergeben und ihr einen Wert zuweisen:
Wir können das Array auch zurückgeben. Um das Array zurückzugeben, sollte der Rückgabetyp der Funktion vom Strukturtyp sein, dh Markierungen. Dies liegt daran, dass wir in Wirklichkeit die Struktur übergeben, die das Array enthält. Der endgültige Code könnte also so aussehen.
quelle
Dies ist eine ziemlich alte Frage, aber ich werde meine 2 Cent eingeben, da es viele Antworten gibt, aber keine, die alle möglichen Methoden klar und präzise zeigt (nicht sicher über das prägnante Bit, da dies eine bekam etwas außer Kontrolle geraten. TL; DR 😉).
Ich gehe davon aus, dass das OP das übergebene Array ohne Kopieren zurückgeben wollte, um es direkt an den Aufrufer zu übergeben und an eine andere Funktion zu übergeben, damit der Code schöner aussieht.
Wenn Sie ein Array wie dieses verwenden, wird es jedoch in einen Zeiger zerfallen und vom Compiler wie ein Array behandelt. Dies kann zu subtilen Fehlern führen, wenn Sie ein Array wie übergeben, wobei die Funktion erwartet, dass es 5 Elemente enthält, Ihr Anrufer jedoch tatsächlich eine andere Nummer übergibt.
Es gibt einige Möglichkeiten, wie Sie besser damit umgehen können. Übergeben Sie ein
std::vector
oderstd::array
(nicht sicher, obstd::array
es 2010 war, als die Frage gestellt wurde). Sie können das Objekt dann als Referenz übergeben, ohne das Objekt kopieren / verschieben zu müssen.Wenn Sie jedoch darauf bestehen, mit C-Arrays zu spielen, verwenden Sie eine Vorlage, in der die Informationen über die Anzahl der Elemente im Array gespeichert sind.
Außer, das sieht ziemlich hässlich aus und ist super schwer zu lesen. Ich benutze jetzt etwas, um mit dem zu helfen, was es 2010 nicht gab, was ich auch für Funktionszeiger verwende:
Dies bewegt den Typ dahin, wo man ihn erwarten würde, und macht ihn weitaus lesbarer. Die Verwendung einer Vorlage ist natürlich überflüssig, wenn Sie nur 5 Elemente verwenden möchten. Sie können sie also natürlich hart codieren:
Wie gesagt, mein
type_t<>
Trick hätte zu dem Zeitpunkt, als diese Frage gestellt wurde, nicht funktioniert. Das Beste, was Sie sich damals erhofft hatten, war die Verwendung eines Typs in einer Struktur:Was wieder ziemlich hässlich aussieht, aber zumindest noch besser lesbar ist, obwohl das
typename
damals je nach Compiler optional gewesen sein könnte, was zu Folgendem führte:Und dann hätten Sie natürlich einen bestimmten Typ angeben können, anstatt meinen Helfer zu verwenden.
Damals die freien Funktionen
std::begin()
undstd::end()
nicht existierte, obwohl sein könnten leicht umgesetzt werden . Dies hätte eine sicherere Iteration über das Array ermöglicht, da sie auf einem C-Array sinnvoll sind, jedoch nicht auf einem Zeiger.Für den Zugriff auf das Array können Sie es entweder an eine andere Funktion übergeben, die denselben Parametertyp verwendet, oder einen Alias erstellen (was nicht viel Sinn macht, da Sie bereits das Original in diesem Bereich haben). Der Zugriff auf eine Array-Referenz entspricht dem Zugriff auf das ursprüngliche Array.
oder
Zusammenfassend ist es am besten, einen Array-Zerfall in einen Zeiger nicht zuzulassen, wenn Sie beabsichtigen, darüber zu iterieren. Es ist nur eine schlechte Idee, da es den Compiler davon abhält, Sie davor zu schützen, sich in den Fuß zu schießen, und Ihren Code schwerer lesbar macht. Versuchen Sie immer, dem Compiler zu helfen, indem Sie die Typen so lange wie möglich beibehalten, es sei denn, Sie haben einen sehr guten Grund, dies nicht zu tun.
Bearbeiten
Oh, und der Vollständigkeit halber können Sie zulassen, dass es sich zu einem Zeiger verschlechtert, aber dies entkoppelt das Array von der Anzahl der darin enthaltenen Elemente. Dies geschieht häufig in C / C ++ und wird normalerweise durch Übergeben der Anzahl der Elemente im Array verringert. Der Compiler kann Ihnen jedoch nicht helfen, wenn Sie einen Fehler machen und den falschen Wert an die Anzahl der Elemente übergeben.
Anstatt die Größe zu übergeben, können Sie den Endzeiger übergeben, der auf einen nach dem Ende Ihres Arrays zeigt. Dies ist nützlich, da es sich um etwas handelt, das näher an den Standardalgorithmen liegt, die einen Anfangs- und einen Endzeiger verwenden. Was Sie jedoch zurückgeben, ist jetzt nur etwas, an das Sie sich erinnern müssen.
Alternativ können Sie dokumentieren, dass diese Funktion nur 5 Elemente benötigt, und hoffen, dass der Benutzer Ihrer Funktion nichts Dummes tut.
Beachten Sie, dass der Rückgabewert seinen ursprünglichen Typ verloren hat und zu einem Zeiger herabgesetzt wird. Aus diesem Grund sind Sie jetzt allein, um sicherzustellen, dass Sie das Array nicht überlaufen.
Sie könnten ein übergeben
std::pair<int*, int*>
, das Sie für Anfang und Ende verwenden und das weitergeben können, aber dann sieht es wirklich nicht mehr wie ein Array aus.oder
Komischerweise ist dies der
std::initializer_list
Arbeitsweise (c ++ 11) sehr ähnlich , aber sie funktionieren in diesem Kontext nicht.quelle
Der einfachste Weg, dies zu tun, besteht darin, es als Referenz zurückzugeben. Selbst wenn Sie das Symbol '&' nicht schreiben, wird es automatisch als Referenz zurückgegeben
quelle
Sie können das Ergebnis weiterhin wie verwenden
quelle
Wie oben erwähnt sind die Pfade korrekt. Aber ich denke, wenn wir nur eine lokale Array-Variable einer Funktion zurückgeben, gibt sie manchmal Müllwerte als ihre Elemente zurück.
Um zu vermeiden, dass ich das Array dynamisch erstellen und fortfahren musste. Welches ist so etwas.
quelle
quelle
Quelle: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
In C ++ kann nicht ein gesamtes Array als Argument für eine Funktion zurückgegeben werden. Sie können jedoch einen Zeiger auf ein Array zurückgeben, indem Sie den Namen des Arrays ohne Index angeben.
Wenn wir diese Regeln auf die aktuelle Frage anwenden, können wir das Programm wie folgt schreiben:
Die Ausgabe wird sein:
quelle
und was ist mit:
quelle
Wenn Sie ein Array innerhalb einer Funktion übergeben, wird der Zeiger auf das ursprüngliche Array im Funktionsparameter übergeben, und somit werden die am Array innerhalb dieser Funktion vorgenommenen Änderungen tatsächlich am ursprünglichen Array vorgenommen.
Führen Sie es aus und Sie werden die Änderungen sehen
quelle
y
selbst wird als Kopie von sich selbst übergeben. Da es sich jedoch um einen Zeiger handelt, werden Sie direkt mit dem Array arbeiten. Bitte bearbeiten Sie Ihre Antwort.Hier ist ein vollständiges Beispiel für diese Art von Problem, das gelöst werden muss
quelle
Definieren Sie einfach einen Typ [] als Rückgabewert, wie:
. . . Funktionsaufruf:
quelle