Stack-Variablen vs. Heap-Variablen

Lesezeit: 7 Minuten

Sehe ich das richtig:

char *buff[500];

… erstellt eine Stapelvariable und:

char *buff = (char *)malloc(500);

… eine Heap-Variable erstellt?

Wenn das richtig ist, wann und warum würden Sie Heap-Variablen über Stack-Variablen verwenden und umgekehrt. Ich verstehe, dass der Stack schneller ist, gibt es noch etwas.

Eine letzte Frage, ist die Hauptfunktion ein Stapelrahmen auf dem Stapel?

  • um die beiden belegungen vergleichbar zu haben, wolltest du wahrscheinlich eine version ohne haben * fürs erste, nein?

    – Jens Gustedt

    10. März 2011 um 12:15 Uhr

  • Eine Kleinigkeit: Es gibt keine “Heap-Variable”. In deinem Beispiel char *buff ist ein Variableaber der Speicher, auf den es zeigt (erhalten von malloc) wird nicht als Variable bezeichnet; es wird ein Objekt genannt. Variablen in C haben einen Namen, einen Gültigkeitsbereich, eine Speicherdauer und möglicherweise eine Verknüpfung. Jede Variable hat ein zugeordnetes Objekt, das (die Darstellung) ihres Wertes enthält, aber das Gegenteil ist nicht wahr.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    10. März 2011 um 14:21 Uhr


Benutzeravatar von Arkaitz Jimenez
Arkaitz Jimenez

Ja, zuerst erstellt man ein Array von Zeichenzeigern im Stapel, ungefähr 500*4 bytes und zweitens weist man 500 Zeichen im Heap zu und zeigt ihnen einen Stack char ptr.

Das Zuordnen im Stack ist einfach und schnell, aber der Stack ist begrenzt, der Heap ist langsamer, aber viel größer. Abgesehen davon werden Stack-zugewiesene Werte “gelöscht”, sobald Sie den Bereich verlassen, also ist es sehr gut für kleine lokale Werte wie primitive Variablen.

Wenn Sie zu viel im Stack zuweisen, könnte Ihnen der Stack ausgehen und Sie sterben, main Da alle Funktionen, die Sie ausführen, einen Stack-Frame im Stack haben und alle lokalen Variablen der Funktion dort gespeichert sind, kann es auch zu einem Stackoverflow kommen, wenn Sie zu tief in den Funktionsaufruf gehen.

Im Allgemeinen ist es eine gute Faustregel, alles zuzuweisen, was Sie häufig verwenden und größer als hundert Bytes im Heap sind, sowie kleine Variablen und Zeiger im Stack.

  • tolle antwort! Danke Arkaitz.

    – JackHarvin

    10. März 2011 um 11:11 Uhr

  • Auch 2 weisen darauf hin, dass man bei der Verwendung von Speicher auf dem Heap besonders vorsichtig sein sollte. Da die Zeiger auf dem Stack gespeichert werden (und daher lokal sind), führt dies zu Speicherverwaltungsproblemen, wie z. B. baumelnden Zeigern. Verwenden Sie also lieber intelligente Zeiger.

    – lasst uns

    10. März 2011 um 15:16 Uhr

Habe gesehen, dass du geschrieben hast

char *buff = (char *)malloc(500);

du meintest wahrscheinlich

char buff[500];    instead of 
char* buff[500];

in Ihrem ersten Beispiel (Sie haben also ein Char-Array, kein Array von Zeigern auf Zeichen)

Ja, die “Zuweisung” auf dem Stack ist schneller, weil Sie einfach einen im ESP-Register gespeicherten Zeiger erhöhen.

Du brauchen Heap-Variablen, wenn Sie wollen:

1) mehr Speicher als in den Stapel passt (im Allgemeinen viel früher)

2) Speicher, der von einer aufgerufenen Funktion zugewiesen wurde, an die aufrufende Funktion übergeben.

  • Ja, entschuldigung, ich habe vergessen, den Zeiger hinzuzufügen. Wieder eine weitere perfekte Antwort. Daymn wünschte, ich könnte 2 beste Antworten auswählen.

    – JackHarvin

    10. März 2011 um 11:12 Uhr


  • @eznme: Entschuldigen Sie die dumme Frage, aber … ich frage mich: 2) Speicher, der von einer aufgerufenen Funktion zugewiesen wurde, an die aufrufende Funktion übergeben. – Angenommen, ich habe einen Vektor zugewiesen, indem ich einfach sage: vector someReturnedVector = myFunctionReturningVectorOfInts(); Ich nahm den von erstellten Vektor an myFunctionReturningVectorOfInts() Die Funktion wird auf dem Stapel erstellt und kehrt dennoch zu der Funktion zurück, von der sie aufgerufen wird, oder bin ich hier schrecklich irregeführt?

    – Irgendjemand anderes

    9. Oktober 2013 um 7:27 Uhr


  • @AnyOneElse Diese Frage und diese Antworten beziehen sich auf C, nicht auf C++. C++ hat viel mehr Regeln darüber, was als Wert oder Zeiger oder Referenz übergeben oder verschoben wird. Ich schlage vor, Sie öffnen eine neue Frage, um es sicher herauszufinden.

    – Bernd Elkemann

    9. Oktober 2013 um 9:22 Uhr

Dein buffs sind nicht äquivalent.

Der erste (char *buff[500]) ist ein Array von 500 Zeigern; der 2. (char *buff = (char *)malloc(500)) ist ein Zeiger.

Der Zeiger (auf dem Stapel) zeigt auf 500 Byte Speicher (wenn der malloc-Aufruf erfolgreich war) auf dem Heap.
Das Array von Zeigern befindet sich auf dem Stack. Seine Zeiger werden nicht initialisiert.

Sofern Sie nicht C99 verwenden, muss die Größe Ihres Arrays zur Kompilierungszeit bekannt sein, wenn Sie den Stack verwenden. Das bedeutet, dass Sie Folgendes nicht tun können:

int size = 3; // somewhere, possibly from user input
char *buff[size];

Aber mit “The Heap” (dynamische Zuordnung) können Sie beliebige Dimensionen angeben. Das liegt daran, dass die Speicherzuweisung zur Laufzeit erfolgt und nicht fest in die ausführbare Datei codiert ist.

Der C-Standard enthält weder die Wörter Haufen Noch Stapel. Was wir hier stattdessen haben, sind zwei Speicherdauern (von insgesamt 4): automatisch und zugeteilt:

  • char buff[500]; // note the missing * to match the malloc example
    

    innerhalb einer Funktion deklariert das Objekt buff als Array von char und haben automatische Speicherdauer. Das Objekt hört auf zu existieren, wenn der Block, in dem das Objekt deklariert wurde, verlassen wird.

  • char *buff = malloc(500);  // no cast necessary; this is C
    

    wird erklären buff als Hinweis auf char. malloc reserviert 500 fortlaufende Bytes und gibt einen Zeiger darauf zurück. Das zurückgegebene 500-Byte-Objekt bleibt bestehen, bis es explizit vorhanden ist freed mit einem Anruf an free. Das Objekt soll haben zugeteilte Speicherdauer.


Das ist alles, was die C-Norm sagt. Es gibt nicht an, dass die char buff[500] von einem “Stack” zugewiesen werden muss oder dass es einen Stack geben muss. Es gibt nicht an, dass die malloc muss einen “Haufen” verwenden. Im Gegenteil, ein Compiler könnte die intern implementieren char buff[500] wie

{
    char *buff = malloc(500);
    free(buff);
}

Oder es kann ableiten, dass der zugewiesene Speicher nicht verwendet wird oder dass er nur einmal verwendet wird, und eine stapelbasierte Zuweisung verwenden, anstatt tatsächlich aufzurufen malloc.

In der Praxis die meisten aktuellen Compiler und Umgebungen Wille Verwenden Sie ein Speicherlayout namens Stapel für automatische Variablen, und die Objekte mit zugewiesener Speicherdauer sollen von “Haufen” stammen, was eine Metapher für das unorganisierte Durcheinander ist, das mit dem geordneten Stapel verglichen wird, aber das muss nicht so sein.

Benutzeravatar von krtek
krtek

Heap-Variablen können dynamisch erstellt werden, dh Sie können Ihren Benutzer nach einer Größe fragen und eine neue Variable mit dieser Größe mallocieren.

Die Größe einer Stack-Variablen muss zur Kompilierzeit bekannt sein.

Wie Sie sagten, werden Stack-Variablen schneller zugewiesen und abgerufen. Daher empfehle ich, sie jedes Mal zu verwenden, wenn Sie die Größe zur Kompilierzeit kennen. Sonst hast du keine Wahl, musst du nutzen malloc()

Jons Benutzeravatar
Jon

Dies ist in der Tat eine auf dem Stack zugewiesene Variable:

char buff[500]; // You had a typo here?

und das ist auf dem haufen:

char *buff = (char *)malloc(500);

Warum würden Sie das eine gegen das andere verwenden?

  • Im char *buff[500]das 500 muss eine Kompilierzeitkonstante sein. Sie können es nicht verwenden, wenn 500 wird zur Laufzeit berechnet.
  • Andererseits erfolgen Stack-Zuweisungen sofort, während Heap-Zuweisungen Zeit in Anspruch nehmen (daher verursachen sie Laufzeitleistungseinbußen).
  • Der Speicherplatz auf dem Stapel ist durch die Stapelgröße des Threads begrenzt (normalerweise 1 MB, bevor Sie einen Stapelüberlauf erhalten), während auf dem Heap viel mehr verfügbar ist.
  • Wenn Sie ein Array auf dem Stack zuweisen, das groß genug ist, um mehr als 2 Seiten virtuellen Speicher zu belegen, wie vom Betriebssystem verwaltet, und auf das Ende des Arrays zugreifen, bevor Sie etwas anderes tun, besteht die Möglichkeit, dass eine Schutzverletzung auftritt (dies hängt von ab das Betriebssystem)

Schließlich: Jede aufgerufene Funktion hat einen Rahmen auf dem Stack. Das main Funktion ist nicht anders. Sie ist nicht einmal spezieller als die anderen Funktionen in Ihrem Programm, denn wenn Ihr Programm mit der Ausführung beginnt, ist der erste Code, der ausgeführt wird, darin enthalten the C runtime environment. Nachdem die Laufzeit bereit ist, mit der Ausführung Ihres eigenen Codes zu beginnen, ruft sie auf main so wie Sie jede andere Funktion aufrufen würden.

  • Sie können es verwenden, wenn der 500 zur Laufzeit berechnet wird, aber es ist gefährlich, und es gibt keine Möglichkeit zu wissen, welche Werte sicher sind …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    10. März 2011 um 14:23 Uhr

  • Die Verwendung dynamischer Array-Größen hängt vom Compiler ab. Ich erinnere mich, wie verwirrt ich war, als ich den folgenden Code sah: char buff[myDynamicLength]. Visual Studio hat mich nicht kompilieren lassen, aber Dev++ hat es kompiliert (mit GCC, denke ich). Aber wie auch immer, es scheint eine schlechte Praxis zu sein und sollte vermieden werden.

    – JustAMartin

    30. September 2013 um 18:32 Uhr

1407300cookie-checkStack-Variablen vs. Heap-Variablen

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

Privacy policy