Wie greife ich mit Zeigern von einer anderen Funktion auf eine lokale Variable zu?
Lesezeit: 7 Minuten
Radek Simko
Darf ich Zugriff auf eine lokale Variable in einer anderen Funktion haben? Wenn das so ist, wie?
void replaceNumberAndPrint(int array[3]) {
printf("%i\n", array[1]);
printf("%i\n", array[1]);
}
int * getArray() {
int myArray[3] = {4, 65, 23};
return myArray;
}
int main() {
replaceNumberAndPrint(getArray());
}
Die Ausgabe des obigen Codestücks:
65
4202656
Was mache ich falsch? Was bedeutet “4202656”?
Muss ich das ganze Array in die kopieren replaceNumberAndPrint() Funktion mehr als beim ersten Mal darauf zugreifen zu können?
Es ist schwer, hier den besten Vorschlag für Ihre Absicht zu finden. Aber vielleicht möchten Sie sich über gemeinsam genutzte Zeiger (shared_ptr und Freunde) informieren. Sie stellen einige der netten Eigenschaften von Garbage Collection-Sprachen bereit, indem sie Verweise zählen. Aber anders, also Vorsicht.
– HostileFork sagt, vertraue SE nicht
31. Dezember 2010 um 13:59 Uhr
Ich stimme dafür, dies erneut zu öffnen und es als kanonisches Duplikat für Fragen der Art “Ich bekomme einen Absturz, wenn ich einen Zeiger auf eine lokale Variable zurückgebe, warum?”, anstatt dieses andere klassische kanonische Duplikat, das eher für ” Ich bekomme keinen Absturz, warum nicht?”
– Ludin
14. Januar 2016 um 11:09 Uhr
@Lundin irgendwie problematisch, dass dies sowohl C als auch C ++ hat.
– Antti Haapala – Слава Україні
6. November 2018 um 16:02 Uhr
@AnttiHaapala Die Frage enthält nichts Einzigartiges für C++, aber leider gibt es C++-Antworten, sodass das Tag bleiben muss.
– Ludin
6. November 2018 um 16:34 Uhr
Bei Verwendung auf einem eingebetteten System ist die dynamische Speicherzuweisung gefährlich, daher gibt es 3 Möglichkeiten, die Variable global zu machen, sie statisch zu machen oder einen Zeiger auf die Variable von der aufrufenden Routine zu übergeben.
– Benutzer1582568
16. März 2021 um 7:45 Uhr
CodesInChaos
myArray ist eine lokale Variable und daher ist der Zeiger nur bis zum Ende seines Gültigkeitsbereichs gültig (was in diesem Fall die enthaltende Funktion ist getArray) bleibt übrig. Wenn Sie später darauf zugreifen, erhalten Sie undefiniertes Verhalten.
In der Praxis passiert, dass der Anruf an printf überschreibt den Teil des Stapels, der von verwendet wird myArray und es enthält dann einige andere Daten.
Um Ihren Code zu reparieren, müssen Sie entweder das Array in einem Bereich deklarieren, der lange genug lebt (die main Funktion in Ihrem Beispiel) oder auf dem Heap zuweisen. Wenn Sie es auf dem Heap zuweisen, müssen Sie es entweder manuell oder in C++ mit RAII freigeben.
Eine Alternative, die ich übersehen habe (wahrscheinlich sogar die beste hier, vorausgesetzt, das Array ist nicht zu groß), besteht darin, Ihr Array in eine Struktur zu verpacken und es so zu einem Werttyp zu machen. Wenn Sie es dann zurückgeben, wird eine Kopie erstellt, die die Rückgabe der Funktion überlebt. Einzelheiten dazu finden Sie in der Antwort von tp1.
Oder Sie könnten es als statisch deklarieren.
– Oystein
31. Dezember 2010 um 13:47 Uhr
Es statisch zu machen, hat eine ganz andere Semantik, insbesondere in Multi-Thread-Anwendungen, es sei denn, der Inhalt des Arrays ist konstant.
– CodesInChaos
31. Dezember 2010 um 13:51 Uhr
Sicher, aber es ist eine Möglichkeit, das Problem zu lösen, und sollte darauf hingewiesen werden, oder?
– Oystein
31. Dezember 2010 um 13:57 Uhr
Es ist natürlich nützlich, darauf hinzuweisen, aber Sie müssen auch auf die Nachteile hinweisen, daher war Ihr erster Kommentar etwas unvollständig.
– CodesInChaos
31. Dezember 2010 um 14:29 Uhr
Empfehlenswert würde ich sagen static als Lösung für dieses Problem ist schädlich und niemals hilfreich. Für Neulinge wird es zu einem formelhaften Pflaster, anstatt das Problem wirklich zu verstehen und korrekten Code zu schreiben, und später, wenn jemand anderes den Code des Neulings erbt, werden sie entsetzt sein über all die unsinnigen statischen Variablen überall.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
31. Dezember 2010 um 19:44 Uhr
James Gaunt
Sie können nicht auf eine lokale Variable zugreifen, sobald sie den Gültigkeitsbereich verlässt. Das bedeutet es, eine lokale Variable zu sein.
Wenn Sie auf das Array in der zugreifen replaceNumberAndPrint Funktion ist das Ergebnis undefiniert. Dass es beim ersten Mal zu funktionieren scheint, ist nur ein glücklicher Zufall. Wahrscheinlich ist der Speicherort, auf den Sie zeigen, auf dem Stapel nicht zugeordnet und für den ersten Aufruf immer noch korrekt festgelegt, aber der Aufruf an printf überschreibt dies dann, indem es während des Betriebs Werte auf den Stapel drückt, weshalb der zweite Aufruf von to printf zeigt etwas anderes an.
Sie müssen die Array-Daten auf dem Heap speichern und einen Zeiger oder in einer Variablen übergeben, die im Bereich bleibt (z. B. eine globale oder etwas innerhalb der Hauptfunktion).
Versuchen Sie so etwas. Die Art, wie du es machst, “tötet” myArray verursachen, wenn es lokal definiert ist.
Achten Sie darauf, dieses “Feature” WIRKLICH gut zu kommentieren, wenn Sie es in Ihrem Code verwenden. Das Zuweisen von Speicher durch eine Funktion und das Freigeben durch eine andere ist SEHR gefährlich, wenn es nicht ordnungsgemäß dokumentiert ist, und selbst dann ist es anfällig für Speicherlecks! Es wäre besser, das Array in zuzuweisen main und geben Sie es frei, wenn es nicht mehr benötigt wird.
– Schahi
31. Dezember 2010 um 13:40 Uhr
@Shaihi, das ist wahr, auch dieses Stück Code ist sehr naiv, weil es nicht prüft, ob malloc() erfolgreich zugeordnet. Aber ich denke, OP wird den ganzen Punkt verstehen.
– Benutzer418748
31. Dezember 2010 um 13:42 Uhr
Während dies funktioniert, ist es hässlich. Sie sollten die Funktionsnamen ändern (getArray => createArray), um ihr Verhalten besser zu beschreiben. Und haben replaceNumberAndPrint Das Löschen des Quellarrays scheint mir keine gute Idee zu sein. Ich würde lieber das Löschen und Drucken in zwei verschiedene Funktionen aufteilen.
– CodesInChaos
31. Dezember 2010 um 13:42 Uhr
Eine “korrektere” Version hinzugefügt.
– Benutzer418748
31. Dezember 2010 um 13:48 Uhr
@Muggen: bevorzugst du nicht array[i] anstatt *(array+i)?
– jweyrich
31. Dezember 2010 um 13:50 Uhr
myArray verlässt den Gültigkeitsbereich, sobald Sie getArray verlassen. Sie müssen ihm stattdessen Platz auf dem Heap zuweisen.
Ihr Code ruft undefiniertes Verhalten auf, weil myArray geht aus dem Geltungsbereich sobald getArray() Rückkehr und jeder Versuch, verwenden (Dereferenzierung) der baumelnde Zeiger ist UB.
Gemeinschaft
Lokale Variablen verlassen bei der Rückgabe den Gültigkeitsbereich, sodass Sie keinen Zeiger auf eine lokale Variable zurückgeben können.
Sie müssen es dynamisch (auf dem Heap) zuweisen, indem Sie verwenden malloc oder new. Beispiel:
int *create_array(void) {
int *array = malloc(3 * sizeof(int));
assert(array != NULL);
array[0] = 4;
array[1] = 65;
array[2] = 23;
return array;
}
void destroy_array(int *array) {
free(array);
}
int main(int argc, char **argv) {
int *array = create_array();
for (size_t i = 0; i < 3; ++i)
printf("%d\n", array[i]);
destroy_array(array);
return 0;
}
Alternativ können Sie das Array als statisch deklarieren, wobei die Semantik unterschiedlich ist. Beispiel:
int *get_array(void) {
static int array[] = { 4, 65, 23 };
return array;
}
int main(int argc, char **argv) {
int *array = get_array();
for (size_t i = 0; i < 3; ++i)
printf("%d\n", array[i]);
return 0;
}
Wenn Sie nicht wissen, was static bedeutet, lesen Sie diese Frage & Antwort.
Um zu verstehen, warum Sie dies tun müssen, müssen Sie wissen, wie sizeof(array) funktioniert. C (und damit C++) bemüht sich sehr, das Kopieren des Arrays zu vermeiden, und Sie benötigen die Struktur, um darüber hinauszugehen. Warum das Kopieren erforderlich ist, liegt an den Gültigkeitsbereichen – der Gültigkeitsbereich der get_array()-Funktion verschwindet und jeder Wert, der noch aus diesem Gültigkeitsbereich benötigt wird, muss in den aufrufenden Gültigkeitsbereich kopiert werden.
Ich weiß, das ist schon eine ganze Weile her, aber müsstest du das auch nicht typedef oder weisen Sie die Struktur like zu struct Arr a?
– sherrelbc
2. Oktober 2013 um 16:07 Uhr
@sherrellbc In C, ja. In C++ struct Foo { ... }; definiert automatisch die Typen struct FooundFooNein typedef erforderlich.
– Melpomen
13. September 2018 um 6:05 Uhr
10033500cookie-checkWie greife ich mit Zeigern von einer anderen Funktion auf eine lokale Variable zu?yes
Es ist schwer, hier den besten Vorschlag für Ihre Absicht zu finden. Aber vielleicht möchten Sie sich über gemeinsam genutzte Zeiger (shared_ptr und Freunde) informieren. Sie stellen einige der netten Eigenschaften von Garbage Collection-Sprachen bereit, indem sie Verweise zählen. Aber anders, also Vorsicht.
– HostileFork sagt, vertraue SE nicht
31. Dezember 2010 um 13:59 Uhr
Ich stimme dafür, dies erneut zu öffnen und es als kanonisches Duplikat für Fragen der Art “Ich bekomme einen Absturz, wenn ich einen Zeiger auf eine lokale Variable zurückgebe, warum?”, anstatt dieses andere klassische kanonische Duplikat, das eher für ” Ich bekomme keinen Absturz, warum nicht?”
– Ludin
14. Januar 2016 um 11:09 Uhr
@Lundin irgendwie problematisch, dass dies sowohl C als auch C ++ hat.
– Antti Haapala – Слава Україні
6. November 2018 um 16:02 Uhr
@AnttiHaapala Die Frage enthält nichts Einzigartiges für C++, aber leider gibt es C++-Antworten, sodass das Tag bleiben muss.
– Ludin
6. November 2018 um 16:34 Uhr
Bei Verwendung auf einem eingebetteten System ist die dynamische Speicherzuweisung gefährlich, daher gibt es 3 Möglichkeiten, die Variable global zu machen, sie statisch zu machen oder einen Zeiger auf die Variable von der aufrufenden Routine zu übergeben.
– Benutzer1582568
16. März 2021 um 7:45 Uhr