PDA

Visualizza la versione completa : [C] Allocazione memoria in funzione


Fingard
03-04-2011, 10:45
Sempre sulle malloc, mi sta venendo un dubbio parecchio atroce:

char* alloca (int n){
char* stringa = malloc (n * sizeof(char));
return stringa;
}

int main(int argc, char* argv[]){
char* miaStringa = alloca (1);
miaStringa[0] = 'a';
}

Ha senso? Oppure la memoria allocata da malloc viene liberata all'uscita della funzione? Non riesco a trovare una risposta chiara a riguardo...
Grazie mille.

YuYevon
03-04-2011, 10:52
Oppure la memoria allocata da malloc viene liberata all'uscita della funzione?


La memoria allocata dinamicamente *deve* essere deallocata esplicitamente dal programmatore con la funzione free(), non viene deallocata in automatico all'uscita dallo scope di una funzione; questo dipende dalle diverse aree di memoria in cui viene allocato lo spazio richiesto nel caso dell'allocazione statica (stack) e dinamica (heap): il primo si ridimensiona automaticamente alla chiamata di una funzione e alla sua terminazione, il secondo deve essere ridimensionato manualmente dal programmatore con apposite chiamate di sistema (invocate tramite funzioni di libreria), questo almeno in C/C++.

PS: scegli titoli più significativi per i thread.

Fingard
03-04-2011, 13:33
Avrei editato il titolo ma son passati 60 minuti e non me lo fa fare (O_O)
Cmq grazie della risposta... Anche se la mia domanda era un po' diversa credo che indirettamente tu mi abbia risposto lo stesso...
Quindi io quando assegno 'a' a miaStringa[0] non sto accedendo ad un punto "a caso" della memoria no? diciamo... gli "effetti" della malloc permangono anche al di fuori della funzione dove la malloc viene chiamata giusto?

Perchè io da qualche parte avevo trovato che una funzione come

char* alloca(int n){
char stringa[n];
return stringa;
}

Non aveva senso, e mi chiedevo se viceversa utilizzando una malloc era possibile creare una funzione simile...

YuYevon
03-04-2011, 15:25
Originariamente inviato da Fingard
Quindi io quando assegno 'a' a miaStringa[0] non sto accedendo ad un punto "a caso" della memoria no? diciamo... gli "effetti" della malloc permangono anche al di fuori della funzione dove la malloc viene chiamata giusto?


No, non è un punto a caso, è una locazione di memoria appositamente allocata nell'heap con la chiamata alla malloc(), ammesso ovviamente che questa sia andata a buon fine (e per questo è sempre preferibile verificare che il puntatore restituito dalla funzione non sia NULL, stesso discorso per calloc()). Rimarrà allocata fino a quando non la deallochi esplicitamente con free() (o in teoria anche con realloc() passando 0 come nuovo size) o comunque fino a quando non terminerà il processo, caso in cui il sistema operativo provvederà automaticamente a reclamare l'intero spazio in memoria allocato per il processo appena terminato.


Originariamente inviato da Fingard
Perchè io da qualche parte avevo trovato che una funzione come
[...]


In quel modo la memoria per la stringa viene deallocata al momento dell'uscita dalla funzione, quindi se accedi da main() all'indirizzo restituito non hai alcuna garanzia che quell'area di memoria non sia già stata sovrascritta. Tra l'altro fai attenzione al fatto che l'allocazione di un array/stringa con size variabile non è consentita dal C "tradizionale" (ISO C90) ma è un'estensione del C99, tra l'altro non supportata da tutti i compilatori.

Fingard
03-04-2011, 19:41
Perfetto, grazie mille... Ora inizia a essere più chiaro... Anche se il C per me rimane ancora parecchio misterioso...

Risalendo all'indietro con delle stampe mi sono accorto che il mio problema, o almeno uno dei problemi, è che quando ho

...
char** bigBuffer = NULL;
bigBuffer = malloc(sizeof(char*));
bigBuffer[0] = malloc (50 * sizeof(char));
printf("%i\n", (int) strlen(bigBuffer[0]));
...

Questo stampa 6 -_-'
IMMEDIATAMENTE dopo la malloc... Se io poi vado a scrivere su bigBuffer[0] una stringa >= 6 non c'è problema (i chars "nati dal nulla" vengono sovrascritti) ma se ci scrivo ad esempio "sai" mi ritrovo dentro bigBuffer "saiXXX" dove gli XXX sono i vecchi chars (che il mio terminale stampa con dei caratteri indecifrabili)...
Qualcuno ha idea di come questo sia possibile? Da qualche altra parte nel codice sono andato a scrivere dove non si dovrebbe?

Celebron
03-04-2011, 19:45
strlen lavora sulle stringhe
un array di char però non è per forza una stringa
un array di char diventa una stringa se e solo se è presente un terminatore di stringa in una qualsiasi delle sue posizioni ('\0')


se chiami una strlen su un array di char non inizializzato e senza che tu abbiap osto in un punto preciso il terminatore di stringa, il risultato che ottieni è totalmente imprevedibile e dipende da quanto vi fosse precedentemente scritto in quella determinata locazione di memoria


per la cronaca, la malloc si limita semplicemente a renderti disponibile una determinata porzione di memoria, ma non te la inizializza a nessun valore, bensi vi lascia al suo interno quanto precedentemente vi fosse

Fingard
03-04-2011, 20:10
Ecco perfetto... Ora tutto inizia ad avere senso... Lo stesso discorso varrà anche per strcat, che io uso alla fine per rimettere insieme tutte le (non) stringhe di bigBuffer in un testo unico... e da qui tutti i casini a cascata... Bene, ora ho capito perchè il mio codice aveva comportamenti "un tantino" imprevedibili... Grazie delle spiegazioni...
Il fatto è che avendo programmato (sol)tanto in java continuo a prendere per buone equivalenze non vere (tipo
"per allocare una stringa hai bisogno di un char* s = malloc (k * sizeof(char))"
uguale a
"se char* s = malloc(k * sizeof(char)), s è una stringa")...

MacApp
04-04-2011, 00:12
Originariamente inviato da Fingard
Sempre sulle malloc, mi sta venendo un dubbio parecchio atroce:

char* alloca (int n){
char* stringa = malloc (n * sizeof(char));
return stringa;
}

cambia il nome della funzione in NewString, cosi' al chiamante è chiaro che deve rilasciarla; alloca può essere fuorviante, infatti in alcuni SO ci sono delle API che si chiamano alloc e che liberano automaticamente all'uscita dei blocchi.

Dato che ci sei, siccome hai una NewString, crea anche una FreeStringIf del tipo:


char * FreeStringIf (char * theString){
if (NULL != theString){
free (theString);
}
return NULL;
}


che puoi ad esempio utilizzare così:


int main (void){
char * aString = NewString (1024);
if (NULL != aString){
// your program is handling the good string..

}
aString = FreeStringIf (aString);
return 0;
}

alka
04-04-2011, 14:51
Originariamente inviato da Fingard
[C]Domanda nuda e cruda

Per favore, usa titoli più significativi per le discussioni in futuro, come da Regolamento (http://forum.html.it/forum/showthread.php?s=&threadid=973887).

Loading