Kann eine lokale variable den Speicher zugegriffen werden, die außerhalb Ihrer Reichweite?
Ich habe den folgenden code.
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
Und der code ist nur im Betrieb mit keine runtime-Ausnahmen!!!
Wurde die Ausgabe 58
Wie kann es sein? Ist nicht die Erinnerung an eine lokale variable unzugänglich außerhalb seiner Funktion?
das wird nicht mal kompilieren, wie Sie ist; wenn Sie fix die nonforming business, gcc noch warnen
Zurück in meiner Jugend arbeitete ich einmal auf einige ein bisschen tricky null-ring-code ausgeführt, der auf dem Netware-Betriebssystem, dass die beteiligten geschickt bewegen Sie den stack-pointer in einer Weise, die nicht genau sanktioniert durch das Betriebssystem. Ich würde wissen, wenn ich einen Fehler gemacht, weil oft der Stapel würde bis Ende, wobei am Bildschirm Gedächtnis und ich konnte zusehen, wie die bytes geschrieben wird rechts auf dem display. Sie können nicht Weg mit dieser Art der Sache in diesen Tagen.
lol. Ich musste Lesen die Frage und einige Antworten, bevor ich überhaupt verstanden wo das problem ist. Ist das eigentlich eine Frage, über die variable access-Bereich? Sie verwenden nicht einmal 'ein' außerhalb Ihrer Funktion. Und das ist alles dort ist zu ihm. Werfen um einige Speicher-Referenzen ist ein ganz anderes Thema aus dem Geltungsbereich von Variablen.
Dupe Antwort bedeutet nicht, dass dupe in Frage. Viele der dummen Fragen, die Menschen, die hier vorgeschlagen sind ganz andere Fragen, die zufällig beziehen sich auf die gleiche zugrunde liegende symptom... aber der Fragesteller hat, wissen, wissen, so dass Sie offen bleiben sollen. Ich Schloss eine ältere dupe und fusionierte Sie in dieser Frage, die offen bleiben sollte, weil es eine sehr gute Antwort.
Wenn die Antwort hier ist gut, es sollte zusammengeführt älteren Fragen, von denen dies ist ein dupe, nicht die andere Weise herum. Und dies Frage von ist in der Tat ein dupe von den anderen Fragen, die hier vorgeschlagen wird und dann einige (auch wenn einige der vorgeschlagenen sind eine bessere Passform als andere). Beachten Sie, dass ich denke, Eric ' s Antwort ist gut. (In der Tat, ich markiert dieser Frage für Sie die Zusammenführung der Antworten in eine der älteren Fragen, um zu retten den älteren Fragen).
address of local variable ‘a’ returned
; valgrind zeigt Invalid write of size 4 [...] Address 0xbefd7114 is just below the stack ptr
Zurück in meiner Jugend arbeitete ich einmal auf einige ein bisschen tricky null-ring-code ausgeführt, der auf dem Netware-Betriebssystem, dass die beteiligten geschickt bewegen Sie den stack-pointer in einer Weise, die nicht genau sanktioniert durch das Betriebssystem. Ich würde wissen, wenn ich einen Fehler gemacht, weil oft der Stapel würde bis Ende, wobei am Bildschirm Gedächtnis und ich konnte zusehen, wie die bytes geschrieben wird rechts auf dem display. Sie können nicht Weg mit dieser Art der Sache in diesen Tagen.
lol. Ich musste Lesen die Frage und einige Antworten, bevor ich überhaupt verstanden wo das problem ist. Ist das eigentlich eine Frage, über die variable access-Bereich? Sie verwenden nicht einmal 'ein' außerhalb Ihrer Funktion. Und das ist alles dort ist zu ihm. Werfen um einige Speicher-Referenzen ist ein ganz anderes Thema aus dem Geltungsbereich von Variablen.
Dupe Antwort bedeutet nicht, dass dupe in Frage. Viele der dummen Fragen, die Menschen, die hier vorgeschlagen sind ganz andere Fragen, die zufällig beziehen sich auf die gleiche zugrunde liegende symptom... aber der Fragesteller hat, wissen, wissen, so dass Sie offen bleiben sollen. Ich Schloss eine ältere dupe und fusionierte Sie in dieser Frage, die offen bleiben sollte, weil es eine sehr gute Antwort.
Wenn die Antwort hier ist gut, es sollte zusammengeführt älteren Fragen, von denen dies ist ein dupe, nicht die andere Weise herum. Und dies Frage von ist in der Tat ein dupe von den anderen Fragen, die hier vorgeschlagen wird und dann einige (auch wenn einige der vorgeschlagenen sind eine bessere Passform als andere). Beachten Sie, dass ich denke, Eric ' s Antwort ist gut. (In der Tat, ich markiert dieser Frage für Sie die Zusammenführung der Antworten in eine der älteren Fragen, um zu retten den älteren Fragen).
InformationsquelleAutor |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ihnen ein Hotelzimmer mieten. Sie legte ein Buch in der obersten Schublade des Nachttisch und schlafen gehen. Beim check out am nächsten morgen, aber "vergessen" zurück zu geben, Ihre Schlüssel. Sie stehlen den Schlüssel!
Eine Woche später, kehren Sie zurück zum hotel, check das nicht, schleichen sich in Ihre alten Zimmer, die mit Ihren gestohlenen Schlüssel, und suchen Sie in der Schublade. Ihr Buch ist immer noch da. Erstaunlich!
Wie kann das sein? Nicht der Inhalt eines Hotelzimmers Schublade unzugänglich, wenn Sie nicht vermietet Zimmer?
Gut, dass offensichtlich Szenario kann passieren in der realen Welt kein problem. Es gibt keine geheimnisvolle Kraft, die bewirkt, dass Ihr Buch zu verschwinden, wenn Sie nicht mehr berechtigt, in das Zimmer. Es gibt eine geheimnisvolle Kraft, die Sie daran hindert, Sie betreten einen Raum mit einem gestohlenen Schlüssel.
Das hotel-management ist nicht erforderlich zu entfernen Ihrem Buch. Sie nicht machen einen Vertrag mit Ihnen, sagte, dass, wenn Sie verlassen Sachen hinter sich, die Sie zerreißen es für Sie. Wenn Sie illegal re-geben Sie Ihr Zimmer mit einem gestohlenen Schlüssel, um es zu bekommen zurück, die hotel-security-Personal ist nicht erforderlich zu fangen, Sie schleichen in. Sie nicht machen einen Vertrag mit Ihnen, der sagte: "wenn ich versuche zu schleichen zurück in mein Zimmer später, Sie sind verpflichtet, mich zu stoppen." Vielmehr haben Sie einen Vertrag mit Ihnen, der sagte: "ich verspreche nicht, zu schleichen zurück in mein Zimmer später", ein Vertrag, der Sie brach.
In dieser situation alles passieren kann. Das Buch ist da-haben Sie Glück gehabt. Jemand anderes Buch kann da sein, und Ihnen könnte in der hotel-Ofen. Jemand könnte es Recht, wenn Sie kommen, reißen Sie Ihr Buch in Stücke. Das hotel haben könnte, entfernt die Tabelle aus und buchen Sie ganz und ersetzt es mit einem Kleiderschrank. Das gesamte hotel könnte genau das sein, werden abgerissen und ersetzt durch ein Fußball-Stadion, und du stirbst in einer explosion, während Sie schleicht herum.
Wissen Sie nicht, was geschehen wird; wenn Sie aus dem hotel ausgecheckt und Stahlen einen Schlüssel, um die gesetzwidrige Verwendung später, Sie gab das Recht auf Leben in einem vorhersagbaren, sicheren Welt, weil Sie wählte zu brechen, die Regeln des Systems.
C++ ist keine sichere Sprache. Es wird fröhlich erlauben, Sie zu brechen, die Regeln des Systems. Wenn Sie versuchen, etwas illegales zu tun und dumm wie eine Reise in ein Zimmer, Sie sind nicht autorisiert, in und durchstöbern ein Schreibtisch, der vielleicht gar nicht mehr da sein, C++ ist nicht, Sie zu stoppen. Sicherer Sprachen als C++ lösen dieses problem durch die Beschränkung Ihrer macht-indem er viel strengere Kontrolle über Ihre Schlüssel, zum Beispiel.
UPDATE
Heilige Güte, diese Antwort ist immer eine Menge Aufmerksamkeit. (Ich bin mir nicht sicher, warum-ich hielt es nur ein "Spaß" - kleine Analogie, aber egal.)
Ich dachte, es wäre angemessen zu aktualisieren, dies ein bisschen mit ein paar mehr technischen Gedanken.
Compiler sind in das Geschäft der Generierung von code verwaltet die Speicherung der Daten manipuliert durch das Programm. Es gibt viele verschiedene Möglichkeiten der Generierung von code, um Speicher zu verwalten, aber im Laufe der Zeit zwei grundlegende Techniken haben sich verschanzt.
Die erste ist, um irgendeine Art von "lange gelebt" - storage-Bereich, wo die "Lebensdauer" jedes byte in den Speicher-das ist die Zeit, wenn es ist gültig in Zusammenhang mit manchen Programm-variable -- nicht leicht vorhergesagt vor der Zeit. Die compiler-Aufrufe zu einer "heap-manager", der weiß, wie dynamisch reservieren Speicher, wenn es nötig ist, und Sie es zurückfordern, wenn es nicht mehr benötigt wird.
Die zweite Methode ist, um eine "kurzlebige" storage-Bereich, wo die Lebensdauer jedes byte ist bekannt. Hier die Lebensdauern Folgen einer "nesting" - Muster. Die längste Dauer dieser kurzlebigen Variablen zugewiesen werden, bevor andere kurzlebige Variablen, und wird freigegeben, letzten. Kürzer Variablen zugewiesen werden, nach der am längsten lebte, und freigegeben bevor Sie. Die Lebensdauer dieser kürzer Variablen ist "verschachtelt" innerhalb der Laufzeit von länger Leben lieben.
Lokale Variablen Folgen Sie dieser, Muster; wenn eine Methode eingegeben wird, dessen lokale Variablen lebendig. Wenn diese Methode ruft eine andere Methode, die neue Methode lokale Variablen lebendig. Sie werden tot sein, bevor die erste Methode lokale Variablen tot sind. Die relative Reihenfolge der Anfänge und enden der Lebensdauer der Speicher im Zusammenhang mit lokalen Variablen gearbeitet werden kann vor der Zeit.
Aus diesem Grund werden die lokalen Variablen sind in der Regel generiert, als die Speicherung auf einem "Stapel" von Daten-Struktur, weil ein stack hat die Eigenschaft, dass das erste, was bewegt auf es ist das Letzte Ding tauchte ab.
Es ist wie das hotel entscheidet, zu vermieten nur die Zimmer nummeriert, und man kann nicht check-out bis jeder mit einem Zimmer-Anzahl höher, als Sie ausgecheckt hat.
Denken wir also über den stack. In vielen Betriebssystemen erhalten Sie einen Stapel pro thread und stack zugeordnet ist, um eine bestimmte Feste Größe. Wenn Sie eine Methode aufrufen, Sachen auf dem Stapel abgelegt. Wenn Sie dann übergeben Sie einen Zeiger auf den stack wieder aus der Methode, wie der ursprüngliche poster nicht hier, das ist nur ein Zeiger auf die Mitte ein paar ganz gültig Mio-byte-Speicher-block. In unserer Analogie, checken Sie aus dem hotel; wenn Sie das tun, werden Sie nur Check-out der höchsten Nummerierung besetzten Raum. Wenn sonst niemand prüft nach, und gehen Sie zurück zu Ihrem Zimmer, illegal, alle Ihre Sachen, ist garantiert noch da sein in diesem hotel.
Verwenden wir stapeln für temporary stores, denn Sie sind wirklich Billig und einfach. Eine Umsetzung von C++ ist nicht erforderlich, um einen Stapel für Lagerung die einheimischen; es könnte heap. Tut es nicht, weil das würde das Programm langsamer.
Eine Implementierung von C++ ist nicht erforderlich, zu verlassen, den Müll, den Sie Links auf dem Stapel unberührt, so dass Sie kommen zurück für ihn später illegal; es ist völlig legal für den compiler, um code zu generieren, stellt sich zurück auf null, alles, was in den "Raum", den Sie gerade geräumt. Es nicht, weil wieder, das wäre teuer.
Eine Implementierung von C++ ist nicht erforderlich, um sicherzustellen, dass, wenn der stack logischerweise schrumpft, die Adressen, die verwendet werden, um gültig zu sein, sind immer noch in den Speicher gemappt. Die Umsetzung ist erlaubt zu sagen, das Betriebssystem "sind wir fertig mit dieser Seite der Stapel ist jetzt. Bis ich etwas anderes sagen, Frage eine Ausnahme, zerstört den Prozess, wenn jemand berührt, die zuvor gültigen stack-Seite". Wieder, Implementierungen, die eigentlich nicht tun, weil es ist langsam und unnötig.
Statt, Implementierungen lassen Sie Sie Fehler machen und Weg mit ihm. Die meisten der Zeit. Bis eines Tages etwas wirklich schrecklich schief geht und der Prozess platzt.
Dies ist problematisch. Es gibt eine Menge von Regeln und es ist sehr leicht zu brechen Sie versehentlich. Ich habe natürlich viele Male. Und schlimmer noch, oft das problem, dass nur die Flächen, wenn der Speicher erkannt wird beschädigt Milliarden von Nanosekunden nach der Korruption ist passiert, Wann ist es sehr schwer, herauszufinden, wer es versaut.
Mehr Speicher-sichere Sprachen lösen dieses problem durch die Beschränkung Ihrer macht. In "normalen" C# gibt es einfach keine Möglichkeit zu nehmen, die Adresse einer lokalen und senden Sie es oder speichern Sie es für später. Sie können die Adresse einer lokalen, aber die Sprache ist geschickt so konzipiert, dass es unmöglich ist, es zu benutzen, nachdem die Lebensdauer der lokalen endet. Um die Adresse einer lokalen und übergeben Sie es zurück, Sie haben, um den compiler in einem speziellen "unsafe" - Modus, und setzen Sie das Wort "unsicher" in Ihrem Programm, um Aufmerksamkeit auf die Tatsache, dass Sie wahrscheinlich etwas tun, die gefährlich werden könnte, brechen die Regeln.
Zur weiteren Lektüre:
Was ist, wenn C# habe ermöglichen die RÜCKFÜHRUNG Referenzen? Zufällig, das ist das Thema des heutigen blog-post:
http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx
Warum verwenden wir stapeln, um Speicher zu verwalten? Sind Werttypen in C# immer auf dem stack gespeichert werden? Wie funktioniert der virtuelle Speicher? Und viele weitere Themen, wie die C# - memory-manager arbeitet. Viele dieser Artikel sind auch relevant für C++ - Programmierer:
https://blogs.msdn.microsoft.com/ericlippert/tag/memory-management/
Nur sicher, hotels haben. Die unsichere hotels messbaren Gewinn Gewinne aus, nicht zu verschwenden Zeit auf die Programmierung der Tasten.
C++ ist die Erinnerung nicht sicher ist einfach eine Tatsache. Es ist kein "bashing" nichts. Hatte ich gesagt, zum Beispiel "C++ ist eine schreckliche Mischmasch von unter-angegeben, übermäßig komplexen features obendrauf krokant-gefährliche Speicher-Modell, und ich bin dankbar, dass ich jeden Tag nicht mehr in meinen eigenen Verstand", das wäre bashing, C++. Wies darauf hin, dass es die Erinnerung nicht sicher ist erklärt, warum der original-poster ist zu sehen, dass dieses Problem; es ist die Beantwortung der Frage, nicht hin editorializing.
Streng genommen ist die Analogie sollte erwähnen, dass die empfangsdame im hotel war sehr glücklich für Sie, um den Schlüssel mit. "Oh, tun Sie etwas dagegen, wenn ich diesen Schlüssel mit mir?" "Go ahead. Warum sollte mich das interessieren? Ich arbeite nur hier". Ist es nicht illegal, bis Sie versuchen, es zu benutzen.
Bitte, bitte wenigstens daran denken, ein Buch zu schreiben, eines Tages. Ich würde es kaufen, auch wenn es nur eine Sammlung von überarbeiteten und erweiterten blog-posts, und ich bin sicher, so würde eine Menge von Menschen. Aber ein Buch mit dem ursprünglichen Gedanken auf verschiedene Programmier-Angelegenheiten würde eine große Lesen. Ich weiß, dass es unglaublich schwer, Zeit zu finden für Sie, aber bitte berücksichtigen Sie schreiben.
InformationsquelleAutor Eric Lippert
Was du hier tust ist einfach nur Lesen und in den Speicher geschrieben wird, dass benutzt die Adresse des
a
. Du bist jetzt außerhalb derfoo
, es ist nur ein Zeiger auf einen zufälligen Speicherbereich. Es ist einfach so passiert, dass in Ihrem Beispiel, dass der Speicherbereich nicht existiert und nichts anderes im moment. Sie nicht etwas zu brechen, indem Sie fortfahren, es zu benutzen, und nichts anderes hat, überschrieben es noch nicht. Daher die5
ist immer noch da. In einem echten Programm, dass der Speicher wäre wieder fast sofort, und Sie würde brechen etwas durch, dies zu tun (obwohl die Symptome treten möglicherweise erst viel später!)Zurückkehren, wenn Sie von
foo
Sie sagen, die OS, die Sie nicht mehr verwenden, Speicher und es kann neu zugewiesen werden, um etwas anderes. Wenn Sie Glück haben und es nie bekommen hat neu zugewiesen, und das OS nicht fangen Sie erneut zu verwenden, dann erhalten Sie Weg mit der Lüge. Chancen sind, wenn Sie am Ende schreiben, über was auch sonst, endet mit dieser Adresse.Nun, wenn Sie sich Fragen, warum der compiler nicht meckern, es ist wahrscheinlich, weil
foo
habe beseitigt-Optimierung. Es wird in der Regel warnen Sie über diese Art der Sache. C setzt Voraus, Sie wissen, was Sie tun, obwohl, und technisch Sie noch nicht verletzt Rahmen hier (es gibt keine Referenz zua
sich außerhalb derfoo
), nur die memory-access-Regeln, die nur löst eine Warnung statt einem Fehler.Kurz: diese in der Regel nicht arbeiten, aber manchmal durch Zufall.
InformationsquelleAutor Rena
Weil der Speicherplatz nicht stampfte auf nur noch. Zählen Sie nicht auf dieses Verhalten.
Mann, das war die längste Wartezeit für einen Kommentar da, "Was ist Wahrheit? sagte scherzend Pilatus." Vielleicht war es auch eine Gideon - Bibel in diesem hotel Schublade. Und was passiert mit Ihnen sowieso? Beachten Sie sind Sie nicht mehr vorhanden, in London zumindest. Ich denke, dass unter der Gleichheit der Gesetzgebung, bräuchte man eine Bibliothek mit religiösen Schriften.
Ich hätte schwören können, dass ich schrieb, dass vor langer Zeit, aber es tauchte bis vor kurzem und fand meine Antwort nicht da war. Jetzt habe ich zu gehen, herauszufinden, Ihre Anspielungen vor, wie ich erwarte, werde ich amüsiert, als ich tun >.<
Haha. Francis Bacon, einer von Großbritanniens größten Essayisten, den manche Menschen vermuten schrieb Shakespeares Stücke, weil Sie nicht akzeptieren können, dass ein Gymnasium Kind vom Land, Sohn eines glover, könnte ein Genie sein. So ist die Englisch-Klasse-system. Jesus sagte, "ich bin die Wahrheit'. oregonstate.edu/instruct/phl302/texts/bacon/bacon_essays.html
InformationsquelleAutor msw
Eine kleine Ergänzung für alle die Antworten:
wenn Sie so etwas tun:
die Ausgabe wird wahrscheinlich sein: 7
Ist, weil nach der Rückkehr von foo() der Stapel ist befreit und dann wiederverwendet von boo().
Wenn Sie deassemble die ausführbare Datei werden Sie es deutlich sehen.
-1 "für wahrscheinlich werden 7". Der compiler könnte enregister a boo. Könnte es entfernen, weil es unnötig ist. Es gibt eine gute chance, dass *p 5, aber das bedeutet nicht, daß es einen besonders guten Grund, warum es wird wahrscheinlich werden 7.
Es heißt Undefiniertes Verhalten!
warum und wie
boo
wiederverwendetfoo
stack ? nicht-Funktion-stacks voneinander getrennt, auch bekomme ich Müll läuft dieser code auf Visual Studio 2015es ist fast ein Jahr alt, aber Nein, die Funktion "stacks", sind nicht getrennt von einander. Ein KONTEXT hat einen Stapel. Das Kontext nutzt seinen stack eingeben, Haupt -, dann steigt in
foo()
vorhanden ist, dann steigt inboo()
.Foo()
undBoo()
beide geben Sie mit der stack-pointer an der gleichen Stelle. Dies ist jedoch nicht, Verhalten, sollte verlassen werden. Andere 'Sachen' (wie interrupts, oder das Betriebssystem) kann die stack zwischen dem Aufruf vonboo()
undfoo()
, ändern Sie den Inhalt...InformationsquelleAutor
In C++, Sie kann Zugriff auf eine Adresse, aber es bedeutet nicht, dass Sie sollte. Die Adresse, auf die Sie zugreifen, ist nicht mehr gültig. Es funktioniert weil nichts anderes verschlüsselt den Speicher nach foo zurückgegeben, aber es könnte Abstürzen unter vielen Umständen ab. Versuchen Sie, analysieren Sie Ihr Programm mit Valgrind, oder auch nur kompiliert, optimiert und sehen...
InformationsquelleAutor Charles Brunet
Sie werfen eine C++ - Ausnahme durch den Zugriff auf ungültigen Speicher zu. Sie geben ein Beispiel für die Allgemeine Idee der Verweis auf eine beliebige memory location. Ich könnte das gleiche zu tun wie diese:
Hier bin ich einfach der Behandlung von 123456, wie die Adresse, ein Doppel-und schreiben. Eine beliebige Anzahl von Dingen könnte passieren:
q
könnte in der Tat wirklich eine gültige Adresse von einem double, z.B.double p; q = &p;
.q
könnte Punkt irgendwo im inneren Speicher zugewiesen, und ich einfach überschreiben 8 bytes drin.q
Punkte außerhalb der reservierten Arbeitsspeicher und das Betriebssystem Speicher-manager sendet ein segmentation-fault-signal zu meinem Programm, wodurch die Laufzeit zu kündigen.Die Weise, die Sie es einrichten, ist es ein wenig mehr angemessen, dass die Adresse zurückgegeben Punkte in einem gültigen Bereich von Speicher, wie es wahrscheinlich nur ein wenig weiter unten auf dem Stapel, aber es ist immer noch eine ungültige Position, dass Sie nicht in einer deterministischen Weise.
Niemand wird automatisch überprüfen Sie die semantische Gültigkeit der Speicher-Adressen so für Sie während der normalen Ausführung des Programms. Aber ein Speicher-debugger wie
valgrind
gerne tun Sie dies, so führen Sie Ihr Programm durch und werden Sie Zeuge der Fehler.4) I win the lottery
InformationsquelleAutor Kerrek SB
Hast, kompilieren Sie Ihr Programm mit dem Optimierungstool aktiviert? Die
foo()
Funktion ist ganz einfach und hätte inlined oder ersetzt, der resultierende code.Aber ich Stimme mit Mark B, dass das resultierende Verhalten nicht definiert ist.
Das ist nicht notwendig. Da keine neue Funktion wird aufgerufen, nachdem foo(), die Funktionen der lokalen stack-Rahmen wird einfach noch nicht überschrieben. Fügen Sie eine weitere Funktion Aufruf nach der foo(), und die
5
geändert werden...Ich lief das Programm mit GCC 4.8, ersetzen cout mit printf (einschließlich stdio). Zu Recht warnt, "Warnung: address of local variable 'a' zurückgegebene [-Wreturn-local-addr]". Ausgänge 58 ohne Optimierung und 08 mit -O3. Seltsamerweise P hat eine Adresse, auch wenn sein Wert 0 ist. Ich erwartete NULL (0) als Adresse ein.
InformationsquelleAutor gastush
Dein problem hat nichts zu tun mit Umfang. In dem code, den Sie zeigen, ist die Funktion
main
nicht sehen, die Namen in der Funktionfoo
, so dass Sie nicht zugreifen könnena
foo direkt mit diese Namen außerhalbfoo
.Das problem, das Sie haben ist, warum das Programm nicht das signal zu einem Fehler beim verweisen auf illegalen Speicher. Dies ist, weil C++ - standards nicht angeben, in eine sehr klare Grenze zwischen illegalen Speicher und rechtliche Speicher. Verweisen auf etwas in herausgesprungen stack verursacht manchmal Fehler, und manchmal nicht. Es hängt davon ab. Zählen Sie nicht auf dieses Verhalten. Nehme an, es wird immer Fehler beim Programm, sondern davon ausgehen, es wird niemals das signal error beim Debuggen.
Kjörling: Sicher! Menschen wie zu tun, einige schmutzige Arbeit einmal in eine Weile 😉
InformationsquelleAutor Chang Peng
Sind Sie einfach wieder eine Speicheradresse, es ist erlaubt, wird aber wahrscheinlich ein Fehler.
Ja, wenn Sie versuchen, Sie zu dereferenzieren, die Speicher-Adresse, die Sie haben Undefiniertes Verhalten.
cout
.*a
Punkte, um nicht zugeordneten (befreit) Speicher. Auch wenn Sie nicht derefence, es ist immer noch gefährlich (und wahrscheinlich falsch).Ich geklärt, mehr meinte ich mit problem, aber Nein, es ist nicht gefährlich im Sinne der gültigen c++ - code. Aber es ist gefährlich, im Sinne von wahrscheinlicher, dass ein Benutzer einen Fehler gemacht und etwas böses tun. Vielleicht zum Beispiel Sie versuchen, um zu sehen, wie der Stapel wächst, und Sie kümmert sich nur um die Adresse, Wert und wird nie dereferenzieren.
InformationsquelleAutor Brian R. Bondy
Es funktioniert, weil der stack nicht verändert wurde (noch) nicht, da eine war dort.
Rufen ein paar andere Funktionen (die auch den Aufruf von anderen Funktionen) vor dem Zugriff auf
a
wieder und Sie werden wahrscheinlich nicht so glücklich mehr... 😉InformationsquelleAutor Adrian Grigore
Dass die klassischen Undefiniertes Verhalten das ist diskutiert worden, hier nicht vor zwei Tagen -- Suche rund um die Website für ein bisschen. Kurz gesagt, Sie waren glücklich, aber alles, was hätte geschehen können, und der code macht Ungültiger Zugriff auf den Speicher.
InformationsquelleAutor Kerrek SB
Dieses Verhalten ist nicht definiert, wie Alex darauf hingewiesen-in der Tat, die meisten Compiler warnen vor dies zu tun, weil es eine einfache Möglichkeit, um Abstürze.
Ein Beispiel für die Art von Spuk Verhalten Sie wahrscheinlich zu bekommen, versuchen Sie dieses Beispiel:
Dieser druckt "y=123", aber Ihre Ergebnisse können variieren (wirklich!). Ihr Zeiger ist Stress für andere, die unabhängig von lokalen Variablen.
InformationsquelleAutor AHelps
Achten Sie auf alle Warnungen . Nicht nur lösen, Fehler.
GCC zeigt diese Warnung
Dies ist die Stärke von C++. Sie sollten darauf achten, über Speicher. Mit der
-Werror
Flagge, diese Warnung immer ein Fehler und jetzt haben Sie, um zu Debuggen.InformationsquelleAutor
Sie tatsächlich aufgerufen wird, Undefiniertes Verhalten.
Rückgabe der Adresse einer temporären funktioniert, aber als Provisorien sind zerstört am Ende einer Funktion die Ergebnisse der Zugriff auf Sie nicht definiert wird.
Also bist du auch nicht ändern
a
sondern den Speicherort, woa
einmal war. Dieser Unterschied ist sehr ähnlich zu dem Unterschied zwischen Absturz und nicht Absturz.InformationsquelleAutor Alexander Gessler
In typische compiler-Implementierungen, kann man sich den code als "drucken Sie den Wert des Speicherblocks mit der Adresse, die verwendet werden besetzt". Auch, wenn Sie fügen Sie eine neue Funktion Aufruf einer Funktion, die constains eine lokale
int
es ist eine gute chance, dass der Wert vona
(oder die Speicher-Adresse, diea
verwendet, um Punkt-zu -) änderungen. Dies geschieht, weil der stack wird überschrieben mit einem neuen Rahmen mit verschiedenen Daten.Dies ist jedoch undefined Verhalten, und Sie sollten sich nicht darauf verlassen, dass es funktioniert!
Während der Lagerung war besetzt von
a
, die Zeiger hielten die Adresse vona
. Obwohl der Standard verlangt nicht, dass Implementierungen definieren Sie das Verhalten von Adressen, nachdem die Lebensdauer Ihrer Ziel beendet hat, Sie erkennt auch, dass auf einigen Plattformen UB werden in eine dokumentierte Art und Weise charakteristisch für die Umgebung. Während die Adresse einer lokalen variable wird meist nicht viel nützen, nachdem Sie gegangen ist, out of scope, einige andere Arten von Adressen kann es noch sinnvoll sein, nach der Lebensdauer der jeweiligen Ziele.Zum Beispiel, während der Standard kann nicht verlangen, dass Implementierungen erlauben ein Zeiger übergeben
realloc
verglichen werden und den Rückgabewert zu, noch erlauben Sie die Pointer auf Adressen im alten block angepasst werden, um auf die neue Version, einige Implementierungen tun, und der code, die nutzt eine solche Funktion kann effizienter sein, als code, hat jede Handlung zu vermeiden, - auch vergleichen--mit Zeigern, um die Zuordnung, umrealloc
.InformationsquelleAutor larsmoa
Kann es, weil
a
ist eine variable zugeordnet, die vorübergehend für die Lebensdauer Ihres Anwendungsbereichs (foo
- Funktion). Nach Ihrer Rückkehr ausfoo
den Speicher frei und kann überschrieben werden.Was du machst, ist wie beschrieben Undefiniertes Verhalten. Das Ergebnis kann nicht vorhergesagt werden.
InformationsquelleAutor littleadv
Die Dinge, mit richtigen (?) die Ausgabe in der Konsole kann sich dramatisch ändern, wenn Sie ::printf aber nicht cout.
Sie können spielen, um mit debugger in folgenden code (getestet auf x86, 32-bit, MSVisual Studio):
InformationsquelleAutor
Nach der Rückkehr aus der Funktion werden alle Bezeichner werden zerstört, stattdessen gehalten, der Werte in einem Speicher-Ort und die wir nicht lokalisieren können, die Werte ohne Bezeichner.Aber, dass die Lage weiterhin enthält der gespeicherte Wert von der vorherigen Funktion.
So, hier die Funktion
foo()
ist die Rücksendung die Adresse vona
unda
ist zerstört, nach der Rückkehr seine Adresse. Und Sie können auf die geänderten Wertes durch, der Adresse zurückgegeben.Lassen Sie mich ein praktisches Beispiel:
Angenommen, ein Mann versteckt sich Geld an einem Ort und erzählt Ihnen die Lage. Nach einiger Zeit, der Mann, der gesagt hatte, daß Sie das Geld Ort stirbt. Aber noch immer haben Sie den Zugriff, die Geld verborgen.
InformationsquelleAutor
Es "Schmutziger" Art und Weise der Verwendung von Speicher-Adressen. Wenn Sie wieder eine Adresse (Zeiger) Sie nicht wissen, ob es gehört zu den lokalen Gültigkeitsbereich einer Funktion. Es ist nur eine Adresse. Nun, da Sie aufgerufen wird, die " foo "Funktion), die Adresse (Speicherstelle) des" a " war bereits zugewiesen die es in die (sicher, zumindest für den Moment) adressierbaren Speicher der Anwendung (Prozess). Nach der 'foo' - Funktion zurückgegeben, die Adresse von 'a' werden als 'dirty', aber das ist es nicht aufgeräumt, noch gestört/verändert durch die Ausdrücke in den anderen Teil des Programms (in diesem speziellen Fall zumindest). Ein C/C++ - compiler bedeutet nicht aufhören Sie von solchen "dirty" - Zugang (vielleicht warnen Sie aber, wenn Sie Pflege). Sie können sicher verwenden (update) jeden Speicherbereich, in dem Daten-segment des Programms Instanz (Prozess), es sei denn, Sie schützen Sie die Adresse durch einige Mittel.
InformationsquelleAutor
Dein code ist sehr riskant. Erstellen Sie eine lokale variable (die als vernichtet gelten, nachdem die Funktion beendet ist) und Sie geben die Adresse des Speichers an, dass die variable nach der destoyed.
Das bedeutet, dass die Speicher-Adresse gilt oder nicht, und Ihr code wird anfällig sein für mögliche Speicher-Probleme (z.B. segmentation fault).
Dies bedeutet, dass Sie tun, eine sehr schlechte Sache, weil Sie auf der Durchreise sind, eine Speicheradresse auf einen Zeiger, welches nicht vertrauenswürdig überhaupt.
Beachten Sie in diesem Beispiel, statt, und testen Sie es:
Im Gegensatz zu deinem Beispiel mit diesem Beispiel:
new
.Der Fragesteller verwendet raw-Pointer. Ich habe ein Beispiel, welches reflektiert genau das Beispiel, das er in Auftrag, um ihm zu erlauben, den Unterschied zu sehen zwischen untrusty Zeiger und treuen. Tatsächlich gibt es eine andere Antwort, wie bei mir, aber es nutzt strcpy wich, IMHO, könnte weniger sein, klar, ein Anfänger coder als mein Beispiel mit neuen.
Sie nicht benutzen
new
. Sie lehren Sie zu benutzennew
. Aber sollten Sie nicht verwendennew
.Also deiner Meinung nach ist es besser, um eine Adresse auf eine lokale variable, welche zerstört wird, in einer Funktion, als tatsächlich Speicher zugewiesen? Das macht keinen Sinn. Verständnis das Konzept der Zuweisung von e freigeben von Speicher ist wichtig, imho, vor allem wenn Sie sich Fragen, über Zeiger (Fragesteller nicht neu, sondern verwendet Zeiger).
Wann habe ich das gesagt? Nein, es ist besser, auf intelligente Zeiger richtig zu deuten Eigentum der referenzierten Ressource. Verwenden Sie nicht
new
im Jahr 2019 (es sei denn, Sie schreiben code für die Bibliothek) und Lehre nicht Neulinge, dies zu tun! Cheers.InformationsquelleAutor