Autor Wątek: Pytanie na szybko  (Przeczytany 1255 razy)

Offline lastseeds

  • Użytkownik

# Marzec 27, 2009, 14:59:55
mam nastepujacy kod
char* Sprawdz()
{
return "lol";
}
int _tmain(int argc, _TCHAR* argv[])
{
char* b=Sprawdz();
cout<<b;
return 0;
}

efektem dzialania programu jest :
lol
i teraz mam pytanie
w funkcji Sprawdz() tworzony jest tymczasowy wskaznik 3-elementowy i zostaje zwrocony

w main nastepuje przypisanie adresu utworzonego napisu do zmiennej b a potem ten tymczasowy napis zostaje niszczony ( bo wychodzi poza funkcje Sprawdz)
jednak w b nadal zapisany jest adres tego napisu( ktory nota bene nie istnieje)

o co chodzi , czemu prawidlowo sie wyswietla napis?

i teraz mam pytanie :

jesli po zwroceniu tego

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Kos

  • Użytkownik
    • kos.gd

# Marzec 27, 2009, 15:21:52
W Twoim programie (tj w pamięci systemu, tam gdzie Twój program, bodajże za kodem) zostają umieszczone 4 bajty o treści "lol\0" (\0 to symboliczne oznaczenie znaku o kodzie ASCII równym 0, nie mylić ze znaczkiem zera - ten znak oznacza koniec stringa). Dzieje się tak zawsze, gdy piszesz w kodzie "cokolwiek".

Twoja funkcja pobiera wskaźnik o typie const char* pokazujący na ten kawałek pamięci, konwertuje go w locie na char* (bug :)) i zwraca.


Offline lastseeds

  • Użytkownik

# Marzec 27, 2009, 15:54:05
moje pytanie jest czemu zmienna b wciaz zawiera adres tego zwroconego elementu, skoro zostal on zniszczony pod koniec funkcji SPrawdz

Offline nilphilus

  • Użytkownik
    • wordpress

# Marzec 27, 2009, 15:55:33
chyba dlatego że nie został. Zniszczony został wskaźnik, ale nie to na co wskazywał.

Offline Kos

  • Użytkownik
    • kos.gd

# Marzec 27, 2009, 15:56:17
Cytuj
W Twoim programie (tj w pamięci systemu, tam gdzie Twój program, bodajże za kodem) zostają umieszczone 4 bajty o treści "lol\0"
Może wyraziłem się niejasno - one są tam umieszczone na stałe podczas kompilacji. ;)

Offline Mormegil

  • Użytkownik
    • Moj dev blog

# Marzec 27, 2009, 15:59:42
"Takie stringi" nie trafiają na stos, więc nie są niszczone. Na stos trafi wskaźnik, i zostaje on "zdjęty" wraz z końcem funkcji.

"Takie stringi" trafią do przestrzeni pamięci przeznaczonej na stałe.

therealremi

  • Gość
# Marzec 27, 2009, 16:01:09
chyba dlatego że nie został. Zniszczony został wskaźnik, ale nie to na co wskazywał.

Ani wskaźnik, ani to na co wskazuje nie zostało zniszczone.
Jak Kos napisał, const char* "lol" jest w pamięci przez cały okres trwania programu, a adres "lol" jest po prostu kopiowany by value (i nie jest przechowywany w żadnej zmiennej lokalnej w funkcji), więc nie ma jak zostać "zniszczony".
« Ostatnia zmiana: Marzec 27, 2009, 16:05:37 wysłana przez therealremi »

Offline nilphilus

  • Użytkownik
    • wordpress

# Marzec 27, 2009, 16:04:23
aj, fakt, jakoś tak krzywo popatrzyłem XD i zdawało mi się że jest coś w stylu char* zmienna; return zmienna.


Offline .:NOXY:.

  • Użytkownik
    • Profil

# Marzec 27, 2009, 16:21:10
skompiluj to sobie ;p i jak uzywasz totalcmd to sobie kliknij F3 na *.exe rozwiejesz wszystkie watpliwosic ukaze ci sie twoje "lol" wpisane w exe :>

Offline lastseeds

  • Użytkownik

# Marzec 27, 2009, 17:42:09
unsigned char* Sprawdz()
{
unsigned char* abc=new unsigned char[5];
memset(abc,rand()%255,5);
return abc;
}

takie cos tez dziala..

taki cos juz nie :
string* Sprawdz()
{
string str("asd");
return &str;
}
int _tmain(int argc, _TCHAR* argv[])
{
string* b=Sprawdz();
cout<<*b; //straszne bazgroly , komputer piszczy xD
return 0;
}

a taki cos tak :
string* Sprawdz()
{
string* str=new string("asd");
return str;
}
int _tmain(int argc, _TCHAR* argv[])
{
string* b=Sprawdz();
cout<<*b;
return 0;
}

to dowodzi ze WSKAZNIKI nie sa niszczone wraz z zawartoscia. mam metlik w glowie juz troche ;d
« Ostatnia zmiana: Marzec 27, 2009, 17:45:57 wysłana przez lastseeds »

therealremi

  • Gość
# Marzec 27, 2009, 18:02:49
Mieszasz dwa pojęcia.

Np tutaj:
Cytuj
string* Sprawdz()
{
   string str("asd");
        return &str;
}
adres obiektu str (wskaźnik) nie jest przechowywany w żadnej zmiennej która mogłaby zostać zniszczona po opuszczeniu funkcji. Natomiast sam obiekt str jak najbardziej jest niszczony.

Z kolei tutaj:
Cytuj
string* Sprawdz()
{
   string* str=new string("asd");
        return str;
}
zmienna przechowująca wskaźnik - str jest niszczona po opuszczeniu funkcji, ale nie ma to znaczenia bo wskaźnik jest kopiowany przez wartość. Natomiast obiekt pod adresem str nie jest niszczony po opusczeniu funkcji bo jest alokowany dynamicznie.
Mógłbyś napisać też:
Cytuj
string* Sprawdz()
{
   return new string("asd");
}

« Ostatnia zmiana: Marzec 27, 2009, 18:12:27 wysłana przez therealremi »

Offline Avaj

  • Użytkownik

# Marzec 27, 2009, 18:12:54
Wszystko działa tak jak powinno. Zmienne deklarowane statycznie "czyszczą się" po wyjściu z funkcji, zaś wskaźniki pozostają, i jest to zachowanie normalne.

skomentuję krótko te trzy fragmenty kodu co dałeś teraz:

kod 1 - wskaźnik do tablicy charów, zapełniasz go losowymi znaczkami i zwracasz ten wskaźnik w funkcji, wskaźnik pozostaje nawet po wyjściu z funkcji więc jest ok

kod 2 - masz statycznie zdefiniowany string. funkcja zwraca wskaźnik do tego stringa. Wszystko byłoby ok, ale po wyjściu z funkcji zmienna statyczna str czyści się i zostają tam śmieci, stąd też wskaźnik b jest wskaźnikiem do śmieci :D

kod 3 - string jest zadeklarowany dynamicznie poprzez wskaźnik. funkcja zwraca wskaźnik, ale jako że str jest dynamiczną zmienną to nie czyści się w momencie wyjścia z funkcji.

Musisz pamiętać, że string a const char* to zupełnie inne rzeczy. Ten drugi jest praktycznie wskaźnikiem na tablicę charów, zaś ten pierwszy jest skomplikowaną strukturą, która nawet przechowuje długość stringa (char* musisz kończyć znakiem \0)

Offline Mormegil

  • Użytkownik
    • Moj dev blog

# Marzec 27, 2009, 18:47:38
Może warto zacząć od podstaw, czyli wyjaśnienia jakie są pule pamięci dostępne w programie:
Sterta - alokacja i dealokacja za pomocą new i delete (ew. malloc itp.).
Stos - tu alokacja i dealokacja jest automatyczna.
Stała - nie pamiętam jak to się nazywa, ten obszar jest zerowany przed uruchomieniem programu :). Alokacja i dealkoacja jest automatyczna, wraz z uruchomieniem i zakończeniem programu.

string* Sprawdz()
{
   string str("asd");
        return &str;
}
Zmienna str jest alokowana na stosie w momencie uruchomienia funkcji.
W momencie zakończenia funkcji zmienna str jest dealokowana. Czyli zwracasz wskaźnik na nie istniejący obiekt.
Tablica charów "asd" trafi do pamięci stałej. Jest alokowana wraz z uruchomieniem programu, zwolniona zostanie w momencie jego zakończenia.
Wskaźnik na string (wartość zwracana) jest również obiektem istniejącym na stosie i powinien zostać zaalokaowany i dealokowany przez funkcję wywołującą.

Taka jest mniej więcej teoria. Co tak naprawdę zrobi kompilator ? Może być różnie.

Offline lastseeds

  • Użytkownik

# Marzec 27, 2009, 19:50:43
dobra juz wielkie dzieki teraz wszystko rozumiem  ;D