Wie greife ich mit Zeigern von einer anderen Funktion auf eine lokale Variable zu?

Lesezeit: 7 Minuten

Wie greife ich mit Zeigern von einer anderen Funktion auf
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

Wie greife ich mit Zeigern von einer anderen Funktion auf
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

1647298821 941 Wie greife ich mit Zeigern von einer anderen Funktion auf
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.

#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
 printf("%i\n", array[0]);
 printf("%i\n", array[1]);
 printf("%i\n" , array[2]);
 free(array);
}

int * getArray() {
 int * myArray = malloc(sizeof(int) * 3);
 myArray[0] = 4;
 myArray[1] = 64;
 myArray[2] = 23;
 //{4, 65, 23};
 return myArray;
}

int main() {
 replaceNumberAndPrint(getArray());
}

Mehr : http://www.cplusplus.com/reference/clibrary/cstdlib/malloc/

Bearbeiten: Wie Kommentare richtig darauf hingewiesen haben: Ein besserer Weg wäre, dies zu tun:

#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
    if(!array)
        return;

    printf("%i\n", array[0]);
    printf("%i\n", array[1]);
    printf("%i\n" , array[2]);
}

int * createArray() {
    int * myArray = malloc(sizeof(int) * 3);

    if(!myArray)
        return 0;

    myArray[0] = 4;
    myArray[1] = 64;
    myArray[2] = 23;
    return myArray;
}

int main() {
    int * array = createArray();
    if(array)
    {
        replaceNumberAndPrint(array);
        free(array);
    }
    return 0;
}

  • 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.

1647298822 674 Wie greife ich mit Zeigern von einer anderen Funktion auf
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.

1647298822 144 Wie greife ich mit Zeigern von einer anderen Funktion auf
tp1

Der richtige Weg, dies zu tun, ist wie folgt:

struct Arr {
   int array[3];
};
Arr get_array() {
   Arr a;
   a.array[0] = 4;
   a.array[1] = 65;
   a.array[2] = 23;
   return a;
}
int main(int argc, char **argv) {
   Arr a = get_array();
   for(size_t i=0; i<3; i++)
       printf("%d\n", a.array[i]);
   return 0;
}

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 Foo und FooNein typedef erforderlich.

    – Melpomen

    13. September 2018 um 6:05 Uhr

1003350cookie-checkWie greife ich mit Zeigern von einer anderen Funktion auf eine lokale Variable zu?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy