VolkD je napisal/-a:... Pri PC-ju se mi nikoli ni zdelo pomembno vedeti kdaj in kako se spomin sprosti. To sem vedno prepustil sistemu. ...
Huuh, če si programiral v C-ju potem je to ... hmm, kako bi se izrazil ... nevem ... mogoče velika šlamparija.
Primera funkcij ki jemljejo double-null ( sem moral pogooglat, ker že nekaj let nisem rabil ):
SHFileOperation
ChangeServiceConfig
Omenjeno je bilo spoščanje pomnilnika.
Tole je malo bolj obširna tema.
Najprej je treba vedeti kako je bil pomnilnik rezerviran, potem pa lahko govorimo še o tem kako se sprosti.
Rezervacija pomnilnika:
----------------------------------------
a) alokacija na stacku
b) alokacija na heapu
c) alokacija globalne spremenljivke
a) alokacija na stacku
----------------------------------------
lokalna spremenljivka v funkciji
int Nekafunkcija()
{
char[10] buffer;
strcpy(buffer, "123456");
return 0;
}
tule je treba vedeti da:
- velikost stacka je omejena ( odvisno ali gre za windows, linux, 32bitni proces, 64bitni proces, embedded platformo, ...)
char[65536] buffer; // to je recimo na PC računalniku lahko čisto ok, na mikrokontrolerju pa verjetno ni
- če imamo rekurzivni klic funkcije je treba dovro premisliti kako bo delovalo da ne bo zmanjkalo naslovnega prostora
- vnaprej moramo predvideti kakšna bo največja dolžina teksta ki ga bomo "tlačili" v ta buffer
- upoštevati je treba še prostor za '\0'
- ko se bo funkcija končala se bo sprostil tudi spomin rezerviran za tako spremenljivko
- paziti je treba da ne zapišemo več znakov kot je velikost bufferja, sicer se prepiše vsebina naslednje spremenljivke
int BufferOverwriteDemo()
{
char[10] buffer;
char[10] buffer2;
strcpy(buffer, "0123456798012345");
// tule bo (odvisno od tega kako so stvari zložene v pomnilniku)
// del našega teksta pristal v buffer2!
// program se zelo verjetno ne bo sesul, ker nismo prepisali ničesar drugega
return 0;
}
b) alokacija na heapu
----------------------------------------
int HeapAllocDemo(int bufSize)
{
char *buffer = new char[bufSize];
strcpy(buffer, "0123456798012345");
// buge:
// - nismo preverili če je bufSize večji od dolžine teksta ki ga želimo zapisati
// - tukaj bi morali naslov alociranega pomnilnika sprostiti ali pa spraviti v nek seznam za kasneje
return 0;
}
- alokacija na heapu je bolj "fleksibilna"
- pomnilnik lahko ostane rezerviran tudi po izhodu iz funkcije
- ni treba med pisanjem programa vedeti kakšna bo dolžina podatkov
- če konstantno alociramo in sproščamo pomnilnik se (lahko) pojavi efekt fragmentacije naslovnega prostora
- temu se delno lahko izognemo če recimo vedno alociramo velikosti 2^n bytov ( 2, 4, 8, 16, 32, 64, ... )
recimo za "abcd" alociramo 8 bytov: strlen("abcd")+1 = 4+1 = 5 => nextpowerof2(5) = 8
int HeapAllocDemoFixed(int bufSize)
{
char *buffer = new char[bufSize];
if(!buffer) retrn -1;
if (bufSize <= strlen("0123456798012345")) return -2;
strcpy(buffer, "0123456798012345");
// do something useful with string
delete buffer;
return 0;
}
c) alokacija globalne spremenljivke
----------------------------------------
char[10] globalBuffer;
int GlobalVarDemo()
{
strcpy(globalBuffer, "0123456798012345");
// buge:
// - nismo preverili če je gobalBuffer večji od dolžine teksta ki ga želimo zapisati
return 0;
}
- tukaj je spremenljivka deklarirana kot statiče array in za sprostitev pomnilnika bo poskrbel prevajalnik
Posebno zabavne so funkcije za pretvorbo v tekst (sprintf):
sprintf(buffer, "%s %i", "0123456798012345", 1);
- pri teh funkcijah je probel to ker ni enostavno izračunati koliko podatkov (teksta) bodo zapisale.
- zato modernejše različice ( recimo snprintf ) vsebujejo dolžino bufferja kot parameter
- tako lahko funkcija sama preneha pistai če pride do konca bufferja in ne prepiše vsebine v pomnilniku ki se nahaja za bufferjem
Torej osnovni napotek:
- če alociramo tako: int[] xyz; ... char[128] username; ... potem bo prevajalnik sam poskrbel da se bo spomin sprostil
- če alociramo tako: int *xyz = new int[3]; ... char *username = new char[128]; byte *buff = malloc(1024); ... potem mormao spomin sprostiti sami (delete, free, ...)
Lp,
Gregor