Czy pamięć zmiennej lokalnej może być dostępna poza jej zakresem?

Mam następujący kod.

#include <iostream>

int * foo()
{
    int a = 5;
    return &a;
}

int main()
{
    int* p = foo();
    std::cout << *p;
    *p = 8;
    std::cout << *p;
}

I Kod jest po prostu uruchomiony bez wyjątków runtime!

Wyjście było 58

Jak to możliwe? Czy pamięć zmiennej lokalnej nie jest niedostępna poza jej funkcją?

20 answers

Jak to możliwe? Czy pamięć zmiennej lokalnej nie jest niedostępna poza jej funkcją?
Wynajmujesz pokój w hotelu. Wkładasz książkę do górnej szuflady nocnego stolika i idziesz spać. Wymeldujesz się następnego ranka, ale "zapomnij" o oddaniu klucza. Ukradłeś klucz! Tydzień później wracasz do hotelu, nie meldujesz się, zakradasz się do starego pokoju ze skradzionym kluczem i zajrzysz do szuflady. Twoja książka wciąż tam jest. Zadziwiające!

Jak czy to możliwe? Czy zawartość szuflady pokoju hotelowego nie jest niedostępna, jeśli nie wynająłeś pokoju?

Oczywiście ten scenariusz może się zdarzyć w prawdziwym świecie bez problemu. Nie ma tajemniczej siły, która powoduje, że Twoja książka zniknie, gdy nie masz już pozwolenia na przebywanie w pokoju. Nie ma też tajemniczej siły, która uniemożliwia wejście do pokoju ze skradzionym kluczem.

Kierownictwo hotelu nie jest wymagane , aby usunąć książkę. Nie zrobiłeś umowa z nimi, które mówią, że jeśli zostawisz coś za sobą, zniszczą to dla Ciebie. Jeśli nielegalnie wejdziesz do pokoju ze skradzionym kluczem, aby go odzyskać, personel ochrony hotelowej nie jest zobowiązany do złapania Cię zakradającego się. Nie zawarłeś z nimi umowy, która mówi: "jeśli spróbuję później zakraść się do mojego pokoju, musisz mnie powstrzymać."Raczej podpisałeś z nimi umowę, która mówi:" obiecuję, że nie zakradnę się później do mojego pokoju". złamane .

W tej sytuacji wszystko może się zdarzyć . Książka może tam być ... miałeś szczęście. Książka kogoś innego może tam być, a twoja może być w hotelowym piecu. Ktoś może tam być, Kiedy wejdziesz i rozwalisz książkę na kawałki. Hotel mógł całkowicie usunąć stół i książkę i zastąpić go szafą. Cały hotel może zostać zburzony i zastąpiony stadionem piłkarskim, a ty umrzesz w eksplozji, podczas gdy ty skradają się.

Nie wiesz, co się stanie; kiedy wymeldowałeś się z hotelu i ukradłeś klucz do nielegalnego użycia później, zrezygnowałeś z prawa do życia w przewidywalnym, bezpiecznym świecie, ponieważ zdecydowałeś się złamać zasady systemu.

C++ nie jest bezpiecznym językiem . Radośnie pozwoli Ci złamać zasady systemu. Jeśli próbujesz zrobić coś nielegalnego i głupiego, jak powrót do pokoju, do którego nie masz pozwolenia i grzebanie w biurku, którego może już nie być, C++ cię nie powstrzyma. Bezpieczniejsze języki niż C++ rozwiązują ten problem, ograniczając swoją władzę - na przykład poprzez znacznie ściślejszą kontrolę nad kluczami.

UPDATE

[1]} święta dobroć, ta odpowiedź jest coraz dużo uwagi. (Nie jestem pewien dlaczego-uznałem to za "zabawną" małą analogię, ale co tam.)

Pomyślałem, że może to być germane, aby zaktualizować to trochę z kilku bardziej technicznych myśli.

Kompilatory zajmują się generowaniem kodu, który zarządza przechowywaniem danych manipulowanych przez ten program. Istnieje wiele różnych sposobów generowania kodu do zarządzania pamięcią, ale z czasem dwie podstawowe techniki zostały zakorzenione.

Pierwszym jest posiadanie pewnego rodzaju "długowiecznego" obszaru przechowywania, w którym "żywotność" każdego bajtu w magazynie - to znaczy okres, w którym jest on prawomocnie powiązany z jakąś zmienną programu-nie może być łatwo / align = "left" / Kompilator generuje wywołania do "menedżera sterty", który wie, jak dynamicznie przydzielać magazyn, gdy jest potrzebny i odzyskiwać go, gdy nie jest już potrzebny.

Druga metoda polega na "krótkotrwałym" obszarze przechowywania, gdzie czas życia każdego bajtu jest dobrze znany. Tutaj życia podążają za wzorcem "gniazdowania". Najdłużej żyjąca z tych krótkotrwałych zmiennych zostanie przydzielona przed innymi krótkotrwałymi zmiennymi i zostanie zwolniona jako ostatnia. Krótsze życie zmienne będą przydzielane po tych najdłużej żyjących i zostaną uwolnione przed nimi. Czas życia tych krótszych zmiennych jest "zagnieżdżony"w ciągu życia dłuższych.

Zmienne lokalne są zgodne z tym drugim wzorcem; gdy metoda jest wprowadzana, jej zmienne lokalne ożywają. Gdy ta metoda wywoła inną metodę, zmienne lokalne nowej metody ożywają. Będą martwe, zanim zmienne lokalne pierwszej metody będą martwe. Względny porządek początków i zakończenia żywotności magazynów powiązanych ze zmiennymi lokalnymi mogą być wypracowane z wyprzedzeniem.

Z tego powodu zmienne lokalne są zwykle generowane jako magazyn na" stosie " struktury danych, ponieważ stos ma właściwość, że pierwsza rzecz na niego naciśnięta będzie ostatnią rzeczą wyrzuconą.

To tak, jakby hotel zdecydował się wynajmować pokoje tylko sekwencyjnie, a nie możesz wymeldować się, dopóki wszyscy z numerem pokoju wyższym niż ty nie wymeldują się.

Więc pomyślmy o stosie. W wielu systemach operacyjnych dostajesz jeden stos na wątek i stos jest przypisany do pewnego stałego rozmiaru. Kiedy wywołujesz metodę, rzeczy są popychane na stos. Jeśli następnie przekażesz wskaźnik do stosu z powrotem ze swojej metody, tak jak robi to oryginalny plakat, będzie to tylko wskaźnik do środka jakiegoś całkowicie poprawnego milionobajtowego bloku pamięci. W naszej analogii wymeldujesz się z hotelu; kiedy to zrobisz, wymeldujesz się z najwyżej numerowanego zajmowanego pokoju. Jeśli nikt inny nie zamelduje się za tobą, a Ty wrócisz do pokoju nielegalnie, wszystkie twoje rzeczy na pewno nadal będą tam w tym konkretnym hotelu .

Stosy używamy do tymczasowych sklepów, ponieważ są naprawdę tanie i łatwe. Implementacja C++ nie jest wymagana, aby używać stosu do przechowywania lokalnych; może używać sterty. Nie, bo to by spowolniło program.

Implementacja C++ nie jest wymagana do pozostawienia śmieci pozostawionych na stos nietknięty, abyś mógł po niego wrócić później nielegalnie; jest całkowicie legalne, aby kompilator generował kod, który odwraca się do zera wszystko w "pokoju", który właśnie opuściłeś. Nie, bo to byłoby drogie.

Implementacja C++ nie jest wymagana, aby zapewnić, że gdy stos logicznie się kurczy, adresy, które kiedyś były poprawne, nadal są mapowane do pamięci. Implementacja może powiedzieć systemowi operacyjnemu "skończyliśmy korzystać z tej strony stack teraz. Dopóki nie powiem inaczej, wystaw wyjątek, który niszczy proces, jeśli ktoś dotknie wcześniej poprawnej strony stosu". Ponownie, implementacje tak naprawdę tego nie robią, ponieważ jest to powolne i niepotrzebne.

Zamiast tego implementacje pozwalają popełniać błędy i ujść im na sucho. Przez większość czasu. Aż pewnego dnia coś naprawdę okropnego pójdzie nie tak i proces wybuchnie.

To jest problematyczne. Istnieje wiele zasad i bardzo łatwo je przypadkowo złamać. I z pewnością wiele razy. Co gorsza, problem często pojawia się tylko wtedy, gdy pamięć zostanie wykryta jako uszkodzona miliardy nanosekund po tym, jak doszło do uszkodzenia, kiedy bardzo trudno jest dowiedzieć się, kto to zepsuł.

Więcej języków bezpiecznych dla pamięci rozwiązuje ten problem ograniczając twoją moc. W "normalnym" C# po prostu nie ma sposobu, aby wziąć adres lokalnego i zwrócić go lub zapisać na później. Możesz wziąć adres lokalnego, ale język jest sprytnie zaprojektowany tak, aby był niemożliwe do użycia po zakończeniu życia lokalnych końców. Aby pobrać adres lokalnego i przekazać go z powrotem, musisz umieścić kompilator w specjalnym trybie "unsafe", i umieścić słowo" unsafe " w swoim programie, aby zwrócić uwagę na fakt, że prawdopodobnie robisz coś niebezpiecznego, które może być łamanie zasad.

Do dalszego czytania:

 4853
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-21 18:15:48

To, co tutaj robisz, to po prostu czytanie i zapisywanie do pamięci, która kiedyś była adresem a. Teraz, gdy jesteś poza foo, to tylko wskaźnik do jakiegoś przypadkowego obszaru pamięci. Tak się składa, że w twoim przykładzie ten obszar pamięci istnieje i nic innego go w tej chwili nie używa. Nie łamiesz niczego, kontynuując korzystanie z niego, i nic innego nie nadpisało go jeszcze. Dlatego 5 nadal tam jest. W prawdziwym programie Pamięć ta byłaby ponownie wykorzystywana niemal natychmiast i można złamać coś robiąc to (choć objawy mogą pojawić się dopiero znacznie później!)

Kiedy wrócisz z foo, powiesz systemowi, że nie używasz już tej pamięci i możesz ją przypisać do czegoś innego. Jeśli masz szczęście i nigdy nie zostanie przeniesiony, a system operacyjny nie przyłapie Cię na używaniu go ponownie, to ujdzie ci to na sucho. Są szanse, że skończysz pisząc o tym, co jeszcze kończy się z tym adresem.

Teraz, jeśli jesteś zastanawiam się, dlaczego kompilator nie narzeka, prawdopodobnie dlatego, że foo został wyeliminowany przez optymalizację. Zazwyczaj ostrzega Cię przed takimi rzeczami. C zakłada, że wiesz, co robisz, i technicznie nie naruszyłeś tu zakresu (nie ma odniesienia do samej a poza foo), tylko reguły dostępu do pamięci, które tylko wyzwalają Ostrzeżenie, a nie błąd.

W skrócie: to zwykle nie zadziała, ale czasami będzie przez przypadek.

 278
Author: Rena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-07 19:23:41

Ponieważ przestrzeń magazynowa nie została jeszcze nadepnięta. Nie licz na takie zachowanie.

 153
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-19 02:33:30

Mały dodatek do wszystkich odpowiedzi:

Jeśli zrobisz coś takiego:

#include<stdio.h>
#include <stdlib.h>
int * foo(){
    int a = 5;
    return &a;
}
void boo(){
    int a = 7;

}
int main(){
    int * p = foo();
    boo();
    printf("%d\n",*p);
}

Wyjście prawdopodobnie będzie: 7

Dzieje się tak dlatego, że po powrocie z foo() stos jest zwalniany, a następnie ponownie używany przez boo(). Jeśli zdemontujesz plik wykonywalny, zobaczysz go wyraźnie.

 85
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-25 14:35:20

W C++, Możesz uzyskać dostęp do dowolnego adresu, ale to nie znaczy, że powinieneś. Adres, na który uzyskujesz dostęp, nie jest już ważny. To działa ponieważ nic innego nie zakłóciło pamięci po powrocie foo, ale może się rozbić w wielu okolicznościach. Spróbuj przeanalizować swój program za pomocą Valgrind , lub nawet po prostu skompilować go zoptymalizowanym i zobacz...

 72
Author: Charles Brunet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 21:33:42

Nigdy nie wyrzucasz wyjątku C++ poprzez dostęp do nieprawidłowej pamięci. Podajesz tylko przykład ogólnej idei odwoływania się do arbitralnej lokalizacji pamięci. Mógłbym zrobić to samo tak:

unsigned int q = 123456;

*(double*)(q) = 1.2;

Tutaj po prostu traktuję 123456 jako adres sobowtóra i piszę do niego. Każda liczba rzeczy może się zdarzyć:

  1. q może w rzeczywistości być poprawnym adresem podwójnego, np. double p; q = &p;.
  2. q może wskazywać gdzieś wewnątrz pamięci i po prostu zastąp tam 8 bajtów.
  3. q wskazuje poza przydzieloną pamięcią, a Menedżer pamięci systemu operacyjnego wysyła sygnał błędu segmentacji do mojego programu, powodując jego zakończenie.
  4. wygrywasz na loterii.

Sposób, w jaki go skonfigurujesz, jest nieco bardziej rozsądny, że zwracany adres wskazuje na prawidłowy obszar pamięci, ponieważ prawdopodobnie będzie nieco dalej w dół stosu, ale nadal jest to Nieprawidłowa lokalizacja, do której nie można uzyskać dostępu w deterministyczna Moda.

Nikt nie będzie automatycznie sprawdzał poprawności semantycznej adresów pamięci w ten sposób podczas normalnego wykonywania programu. Jednak debuger pamięci, taki jak valgrind, z przyjemnością to zrobi, więc powinieneś uruchomić swój program i być świadkiem błędów.

 67
Author: Kerrek SB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-20 15:29:18

Czy skompilowałeś swój program z włączonym optymalizatorem? Funkcja foo() jest dość prosta i mogła zostać wstawiona lub zastąpiona w kodzie wynikowym.

Ale Zgadzam się z Markiem B, że wynikowe zachowanie jest niezdefiniowane.

 29
Author: gastush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-21 08:24:54

Twój problem nie ma nic wspólnego z zakresem . W wyświetlonym kodzie funkcja main nie widzi nazw w funkcji foo, więc nie możesz uzyskać dostępu a w foo bezpośrednio z TA Nazwa poza foo.

Problem, który masz, polega na tym, że program nie sygnalizuje błędu podczas odwoływania się do nielegalnej pamięci. Dzieje się tak dlatego, że standardy C++ nie określają bardzo wyraźnej granicy między pamięcią nielegalną a pamięcią legalną. Nawiązywanie do czegoś w stos czasami powoduje błąd, a czasami nie. To zależy. Nie licz na takie zachowanie. Załóżmy, że zawsze spowoduje to błąd podczas programowania, ale załóżmy, że nigdy nie będzie sygnalizować błędu podczas debugowania.

 23
Author: Chang Peng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-23 04:45:29

Po prostu zwracasz adres pamięci, jest to dozwolone, ale prawdopodobnie błąd.

Tak jeśli spróbujesz dereferować adres pamięci, będziesz miał nieokreślone zachowanie.

int * ref () {

 int tmp = 100;
 return &tmp;
}

int main () {

 int * a = ref();
 //Up until this point there is defined results
 //You can even print the address returned
 // but yes probably a bug

 cout << *a << endl;//Undefined results
}
 18
Author: Brian R. Bondy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-19 12:56:09

To klasyczne nieokreślone zachowanie , o którym mówiono tu nie dwa dni temu.przeszukaj trochę stronę. W skrócie, miałeś szczęście, ale wszystko mogło się zdarzyć, a Twój kod powoduje nieprawidłowy dostęp do pamięci.

 18
Author: Kerrek SB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 21:57:55

To zachowanie jest niezdefiniowane, jak zauważył Alex-w rzeczywistości większość kompilatorów ostrzega przed tym, ponieważ jest to łatwy sposób na awarie.

Dla przykładu rodzaju upiornego zachowania, które prawdopodobnie uzyskasz , wypróbuj tę próbkę:

int *a()
{
   int x = 5;
   return &x;
}

void b( int *c )
{
   int y = 29;
   *c = 123;
   cout << "y=" << y << endl;
}

int main()
{
   b( a() );
   return 0;
}

To wypisuje "y=123" , ale Twoje wyniki mogą się różnić (naprawdę!). Twój wskaźnik zatyka inne, niepowiązane zmienne lokalne.

 18
Author: AHelps,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 22:04:21

Zwróć uwagę na wszystkie ostrzeżenia . Nie tylko rozwiązuj błędy.
GCC pokazuje to Ostrzeżenie

Warning: zwracany adres zmiennej lokalnej 'a'

To jest potęga C++. Powinieneś dbać o pamięć. Z flagą -Werror to Ostrzeżenie staje się błędem i teraz musisz go debugować.

 18
Author: sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-28 02:42:17

To działa, ponieważ stos nie został zmieniony (jeszcze) od kiedy a został tam umieszczony. Wywołaj kilka innych funkcji (które również wywołują inne funkcje) przed ponownym dostępem do a, a prawdopodobnie nie będziesz już taki szczęśliwy... ;-)

 17
Author: Adrian Grigore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-23 15:31:51

Powołałeś się na nieokreślone zachowanie.

Zwracanie adresu tymczasowego działa, ale gdy tymczasowe obiekty są niszczone na końcu funkcji, wyniki dostępu do nich będą niezdefiniowane.

Więc nie zmodyfikowałeś a, ale raczej Miejsce Pamięci, w którym kiedyś było a. Różnica ta jest bardzo podobna do różnicy między upaść i nie upaść.

 16
Author: Alexander Gessler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 21:57:13

W typowych implementacjach kompilatora można myśleć o kodzie jako "wydrukuj wartość bloku pamięci z adresem, który był kiedyś zajęty przez a". Ponadto, jeśli dodasz nowe wywołanie funkcji do funkcji, która konstruuje lokalny int, jest duża szansa, że wartość a (lub adres pamięci, na który wskazuje a) ulegnie zmianie. Dzieje się tak, ponieważ stos zostanie nadpisany nową ramką zawierającą inne dane.

Jednak jest to undefined zachowanie i nie powinieneś na nim polegać!

 14
Author: larsmoa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-23 08:02:35

Może, ponieważ {[0] } jest zmienną przydzieloną tymczasowo na czas trwania jej zakresu (foo funkcja). Po powrocie z foo pamięć jest wolna i można ją nadpisać.

To, co robisz, jest opisane jako nieokreślone zachowanie . Wyniku nie da się przewidzieć.

 14
Author: littleadv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 21:57:54

Rzeczy z poprawnym (?) wyjście konsoli może się radykalnie zmienić, jeśli używasz metody:: printf, ale nie cout. Możesz pobawić się debuggerem w poniższym kodzie (testowanym na x86, 32-bit, MSVisual Studio):

char* foo() 
{
  char buf[10];
  ::strcpy(buf, "TEST”);
  return buf;
}

int main() 
{
  char* s = foo();    //place breakpoint & check 's' varialbe here
  ::printf("%s\n", s); 
}
 12
Author: Mykola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 15:07:13

Po powrocie z funkcji, wszystkie identyfikatory są niszczone zamiast wartości przechowywanych w pamięci i nie możemy zlokalizować wartości bez posiadania identyfikatora.Ale ta lokalizacja nadal zawiera wartość zapisaną przez poprzednią funkcję.

Więc tutaj funkcja foo() zwraca adres a i {[1] } jest niszczona po zwróceniu jej adresu. I możesz uzyskać dostęp do zmodyfikowanej wartości poprzez ten zwrócony adres.

Let me take a real world przykład:

Przypuśćmy, że człowiek ukrywa pieniądze w miejscu i mówi ci o miejscu. Po pewnym czasie umiera człowiek, który powiedział ci, gdzie są pieniądze. Ale nadal masz dostęp do tych ukrytych pieniędzy.
 5
Author: Ghulam Moinul Quadir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-19 07:07:55

To "brudny" sposób używania adresów pamięci. Zwracając adres (wskaźnik) nie wiesz, czy należy on do lokalnego zakresu funkcji. To tylko adres. Teraz, gdy wywołałeś funkcję 'foo', ten adres (lokalizacja pamięci) 'a' został już przydzielony tam w (bezpiecznie, przynajmniej na razie) adresowalnej pamięci twojej aplikacji (procesu). Po zwróceniu funkcji " foo " adres "a" może być uznany za "brudny", ale jest tam, nie jest wyczyszczony, ani disturbed/modified by expressions in other part of program (in this specific case conajmniej). Kompilator C / C++ nie powstrzymuje cię przed takim "brudnym" dostępem(może cię jednak ostrzec, jeśli Ci zależy). Możesz bezpiecznie używać (aktualizować) dowolnej lokalizacji pamięci znajdującej się w segmencie danych instancji programu (procesu), chyba że w jakiś sposób zabezpieczysz adres.

 4
Author: Ayub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-08 15:25:53

Twój kod jest bardzo ryzykowny. Tworzysz zmienną lokalną (która jest uważana za zniszczoną po zakończeniu funkcji) i zwracasz adres pamięci tej zmiennej po jej destoyed.

Oznacza to, że adres pamięci może być poprawny lub nie, a Twój kod będzie podatny na ewentualne problemy z adresem pamięci (na przykład błąd segmentacji).

Oznacza to, że robisz bardzo złą rzecz, ponieważ przekazujesz adres pamięci do wskaźnika, który nie jest godny zaufania w wszystkie.

Rozważ ten przykład i przetestuj go:

int * foo()
{
   int *x = new int;
   *x = 5;
   return x;
}

int main()
{
    int* p = foo();
    std::cout << *p << "\n"; //better to put a new-line in the output, IMO
    *p = 8;
    std::cout << *p;
    delete p;
    return 0;
}

W przeciwieństwie do twojego przykładu, z tym przykładem jesteś:

  • przydzielanie pamięci dla int do funkcji lokalnej
  • ten adres pamięci jest nadal ważny również wtedy, gdy funkcja wygaśnie, (nie jest usuwana przez nikogo)
  • adres pamięci jest zaufany (ten blok pamięci nie jest uważany za wolny, więc nie zostanie nadpisany, dopóki nie zostanie usunięty)
  • adres pamięci powinien zostać usunięty, gdy nie używany. (zobacz Usuń na końcu programu)
 1
Author: Nobun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-02 10:17:27