[ itf @ 01.12.2008. 00:10 ] @
Ako znamo da se deklaracijom

char niz[] = "123";

rezervira ukupno 4 byte-a za niz, što se onda dogodi kada napravimo tu deklaraciju i inicijalizaciju preko pokazivača (što je također legalno)?

Code:
char* x = "123";  // gdje je ovo spremljeno? x je automatski alociran?
x = "ABC123";  // realokacija?
cout << x[100];


Zanimljivo je da mi program ne puca niti na drugoj niti na trećoj liniji ovog koda, pa mi zato nije jasno kako je to moguće. Što se onda dogodi na drugoj liniji koda? To bi trebala biti logička greška jer memorija nije nigdje alocirana, niti se koristila funkcija strcpy.. zar ne?

[Ovu poruku je menjao itf dana 01.12.2008. u 01:23 GMT+1]
[ karas @ 01.12.2008. 14:39 ] @
Prvi slucaj alocira memoriju za niz karaktera a drugi ne.
x oba puta pokazuje na staticki alociran niz znakova, prvo na 123 a potom na ABC123, tj. dodeljena mu je adresa datih string literala. Kada se zavrsi tekuci blok i 123 i ABC123 budu unisteni, x ce (ako i sam ne bude unisten) pokazivati na to parce memorije koje tada vec sadrzi random podatke. Zato ovo ne treba raditi.
[ itf @ 01.12.2008. 15:31 ] @
hoćeš reći da se on 2 puta statički alocirao tj. prvo na 123 a potom na ABC123? Meni je jasno što se događa u prvoj liniji koda, ali ova druga mi je problematična i svakako bi trebala biti pogrešna jer veličina niza je već određena prvom inicijalizacijom (pri deklaraciji).
[ djoka_l @ 01.12.2008. 16:09 ] @
Ako ovaj deo koda generišeš, kompajler će predvideti 4 bajta za prvi string ('1', '2', '3', '\0'), 4 bajta za pokazivač x (ako je mašina 32 bitna) i 7 bajtova za drugi string. Ti su stringovi statički definisani u DATA segmentu (može i na steku ali to nije bitno), tj. 11 bajtova je već odvojeno za smeštaj pointera i 2 niza znakova. Dodela statičkog string literara pokazatelju će samo promeniti adresu na koju pokazivač pokazuje, a neće se raditi nikakva alokacija memorije (ona je već odrađena u procesu kompajliranja).
[ karas @ 01.12.2008. 16:10 ] @
Ne, "123" i "ABC123" su staticki alocirani, a x u oba slucaja samo pokazuje na njih, nema alokacije za njega. Dakle,
Code:

char* x = "123";

ne alocira niz za x, samo se alocira pokazivac koji pokazuje na staticki string.
[ itf @ 01.12.2008. 16:59 ] @
Zar onda zapravo nije napravljen memory leak ako prvo alociraš pokazivač x tako da pokazuje na jedan niz, a zatim ga preusmjeriš na drugi niz. Ovaj prvi niz se sam dealocirao?
[ X Files @ 01.12.2008. 20:09 ] @
^
Citat:

Zar onda zapravo nije napravljen memory leak ako prvo alociraš pokazivač x tako da pokazuje na jedan niz, a zatim ga preusmjeriš na drugi niz. Ovaj prvi niz se sam dealocirao?

Zapravo, nije X preusmereno. Ako se ispise "adresa od X" (umesto sadrzaja), ona je uvek ona koja je jednom vec dodeljena prilikom: char* x = "123";. Nije se promenila. Promenio se samo sadrzaj string literala, a kako je i da li je prethodni sadrzaj string literala u data segmentu unisten, pojma nemam.

Drugim recima, nije mi poznato kako se unistava 123:
Code:

char *ptr1 = "123";
cout << ptr1[0] << ptr1[1] << ptr1[2];

ptr1 = "X";
cout << ptr1[0] << ptr1[1] << ptr1[2]; // <--- ne ispise se 3

... jer se izgleda ne radi o overwrite-u, barem sudeci prema ovom primeru koga sam na brzinu isprobao.


Standard ISO/IEC 14882 kao i The C++ Programming Language, Third Edition by Bjarne Stroustrup donekle opisuju taj slucaj u sekcijama posvecenim String literal-ima.

Poenta je da string literal treba da je const:
Citat:

...
"An ordinary string literal has type “array of n const char” and static storage duration [...]"
...
"The type of a string literal is ''array of the appropriate number of const characters'' [...]"
...

... sto je najbolje da se eksplicitno i navede (valjda ovako: char * const ptr1 = "123").

Dalje, kaze se:
Citat:

...
"The effect of attempting to modify a string literal is undefined."
...

Dakle, efekat pokusaja menjanja string literala je nedefinisan, sto je potkrepljeno primerom da dva string literala istog sadrzaja (teksta) mogu da dele istu adresu, bez obzira sto su uvedeni sa razlicitim pokazivacima!!!

Razlog sto je pokusaj menjanja dozvoljen, moze se opravdati sa cinjenicom:
Citat:

A string literal can be assigned to a char *. This is allowed because in previous definations of C and C++, the type of a string literal was char *. Allowing the assignment of a string literal to a char * ensures that millions of lines of C and C++ remain valid.


Konacno:
Citat:

"Implicit conversion of a string literal to a (non-const) char* is deprecated. You should use array of char or avoid assignment of string literals."


Ako neko ima nesto potpunije neka napise.
[ karas @ 01.12.2008. 20:40 ] @
I na FAQ za C tvrde slično za (ne)promenljivost literala:
http://c-faq.com/decl/strlitinit.html
http://c-faq.com/ansi/strlitnotconst.html
[ Eurora3D Team @ 01.12.2008. 23:43 ] @
Moje vidjenje , stringovi se pri kompajlovanju upisuju i PE fajl (u odredjeni segment) ... kad se proces pokene i fajl se ucita, stringovi su se nasli na odredjenim adresama u virtuelnoj memoriji (tacno se zna na kojim).
Ovde u kodu pointeru su jednostavno dodeljene dve adrese jedna za drugom i to je to ... jedino sto se menja u celom programu je vrednost pointera a memorija stingova ostaje ista celo vreme.
To odgovara ovom citatu koji je okacio X Files
"
"An ordinary string literal has type “array of n const char” and static storage duration [...]"
...
"The type of a string literal is ''array of the appropriate number of const characters'' [...]"
"
ili sto rece @karas " "123" i "ABC123" su staticki alocirani"

Mali test ... adrese sam procitao u debugeru pa prekompajlovao
Code:

#include<iostream>
using namespace std;

int main ()
{
   char* x = "123"; 
   // ^ Ovde je x 0x0043202c , znaci  "123" pocinje na 0x0043202c
   x = "ABC123"; 
   // ^ Ovde je x 0x00431024 , znaci "ABC123" pocinje na 0x00431024

   //ima i ovoga ... ispisuje nesto iz tog segmenta
   char* mem = (char*)0x00431024; //  "ABC123"
   cout << mem << endl; // ispisuje  "ABC123"
   //ali ovo ne prolazi ... segment ne moze da se menja
   *mem = 'A'; // <- ovde se prekida
    cout << mem << endl;
   //ni ovo
   *x ='A';

   system("pause");
   return 0;
}
[ tkaranovic @ 06.09.2009. 04:47 ] @
Dodajem malo konkretnog koda pisanog sa VS2008:

Code:

  char *x = "123";  // u pointer x upisuje pokazivac na: (const char[3]) "123"
  int mem123 = (int)(void*)x;  //mem123 cuva adresu od "123"
  x = "ABC";  // u x upisuje pokazivac na "ABC"
  int memABC = (int)(void*)x;  //memABC cuva adresu od "ABC"
  cout << x << endl;  //pise "ABC" a moze da se vrati i na prvu lokaciju:
  x = (char*)mem123; // u x vraca pokazivac na "123"
  cout << x << endl;  //pise "123"

  //adrese:
  cout << &x << endl;  // x je pointer sa svojom adresom u kojem se mogu zamenjivati pokazivaci adresa:
  cout << (void*)mem123 << endl;  // "123"
  cout << (void*)memABC << endl;  // "ABC"

  //moze i sam pokazivac (adresa memoriske lokacije) da postoji:
  int ConstLiteral = (int)(void*)"ConstLiteral";
  cout << ((char*)ConstLiteral)[0] << endl;  //pise "C"
  cout << (char*)ConstLiteral << endl;  //pise "ConstLiteral"
  
  //ili ovako:
  int CL4 = (int)(const char[4]) "[4]";
  cout << (char*)CL4 << endl;  //pise "[4]"