Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 17
  1. #1

    Heap

    Ciao a tutti!
    Qualcuno mi spiega un po' dettagliatamente come funziona l'area di memoria heap?
    So che è dinamica, essendo associata alla funzioni malloc, calloc, realloc..
    Ma vorrei avere qualche chiariemento in più: ad esempio, se una funzione mi deve ritornare una stringa creata all'interno della funzione, questa non può essere stata allocata normalmente, con

    codice:
    char stringa [10];
    ma occorre averla allocata ad esempio con:

    codice:
    char* stringa;
    stringa = (char*) malloc (sizeof (char) * 10);
    A livello pratico/teorico come si spiega questa cosa?
    Salute a voi, da Laikius!

    --> Faber est suae quisque fortunae <--

  2. #2
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Provo a spiegarlo io aspettando correzioni semmai dagli utentu più esperti.
    Praticamente bisogna distinguere tra allocazione dinamica e allocazione statica.
    In generale nello stack c'è tutto quello che dura per tutta l' esecuzione del programma,quindi le variabili globali e le variabili che dichiari nella main sono nello stack.
    Invece le variabili che possono essere cancellate,come quelle temporanee usate nelle funzioni,o quelle allocate con malloc e compagnia bella sono tenute nell' heap.
    Poi spetta al programmatore liberare "manualmente" l' area di memoria allocata dinamicamente,in generale quelle nello stack sono variabili statiche,come ad esempio una static usata in una funzione,che mantiene sempre lo stesso valore,o quelle usate nella main

    Poi se chiedi come si spiega il fatto che le funzioni si passano le variabili tra di loro,a livello intuitivo ti rispondo che se usi:
    codice:
    printf("%d",power(2,3));
    Secondo me la variabile usata per questa funzione è del tutto temporanea,viene prima di tutto memorizzata nell' heap,poi per passare il valore di ritorno si fa una copia dall' heap allo stack se e solo se il valore di ritorno della funzione è allocato,come ad esempio:
    codice:
    int num=power(2,3);
    Ma non ho studiato queste cose,sto provando a rispondere a intuito,qualcuno mi corregga se sbaglio.

  3. #3
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    1,469
    l' "heap" altro non è che una porzione della memoria virtuale della macchina che viene associata ad un certo programma (/processo, bisognerebbe distinguere ma non complichiamo).

    La "RAM" (uso le " così tolgo tutto il discorso virtuale, un pochino troppo complicato in questo contesto) del computer viene assegnata, dal sistema operativo, ad ogni programma, il quale la richiede.

    In sostanza quando il programma X ha bisogno di un tot di memoria, ove metterci ad esempio un vettore, una stringa, o quello che vuoi, chiede al sistema operativo "mi dai tot memoria?"

    Il sistema operativo risponde "eccoti la tua memoria della dimensione X, inizia all'indirizzo Y" (che viene serbato nel mitico puntatore)

    La funzione di libreria (malloc o quello che vuoi) chiama (in modi più o meno complicati) il sistema operativo, il quale - dinamicamente - assegna il blocco di memoria richiesto
    ---
    Le variabili del programma, al contrario, sono "fisse", nel senso che il compilatore sa già quanto sono grandi.
    In tal caso le alloca o nello stack o direttamente in un'area di memoria "pre-allocata" da un pezzo di codice dentro la parte di inizializzazione del programma.

    Non voglio farla troppo complicata, è tipicamente un retaggio di quando la memoria x86 era segmentata a blocchi di 64K, e quindi tenere "libero" lo stack era importante. Oggi ha segmenti (chiamiamoli così per semplicità) di 4GB per le macchine a 32bit (2GB in realtà per tutta una serie di motivi) e la differenza è spesso sfumata, o persa del tutto
    ---
    Riassumendo: l'heap altro non è che un "pezzo" della "RAM" del computer che puoi richiedere.

    Prendiamo un computer con una memoria piccola, diciamo 64KB, così
    ci si capisce più facilmente [è un esempio didattico, le cose sono un pochino più complicate, ma facciamo finta di no]


    Supponiamo di avere il programma X che occupa 10.000 byte, dall'indirizzo [0] a [10.000]. Poi ci saranno i suoi dati statici (il suo "heap") dove saranno poste le variabili definite, poniamo 5.000 byte da 10.001 a 15.000.
    Poi ci sarà lo stack, che normalmente (in realtà no, ma facciamo finta di sì) cresce al contrario, quindi immaginiamo che sia - per iniziare - di 2.000 byte, starà da 63.535 a 65.535.
    La memoria del programma sarà quindi

    00000-10000 = codice
    10001-15000 = variabili statiche
    15000-63534 = HEAP (zona di memoria libera che si può richiedere)
    65535-65535 = stack

    In questo banale esempio quando fai la malloc supponiamo di 100 byte, ti verrà ritornato un puntatore che vale 15001 (il primo indirizzo libero dell'heap).
    Se poi fai una seconda malloc di 200 byte, il puntatore che ti ritornerà varrà 15.101, perchè da 15.001 a 15.100 la memoria è già stata allocata.

    E' il sistema operativo che tiene al suo interno un elenco dei blocchi di memoria che sono liberi e che vengono man mano "prestati" al programma.
    In altri linguaggi (es. java) il compilatore tiene traccia di queste allocazioni ed è in grado di attivare il "garbage collector", ossia un meccanismo automatico che cerca le aree di memoria allocate, ma non più richieste, per liberarle automaticamente.

    In C (e pure C++) invece una volta allocata la memoria... tale rimane finquando non la liberi "a mano". Se ti "scordi" di avere un puntatore 15.101 (anche se non ti servono più), i 100 byte allocati non saranno mai più disponibili [finquando non viene terminato il programma a causa di un altro meccanismo dei sistemi operativi "moderni" che non introduco]


    ---
    Se ti sembra che ci siano "buchi" logici... è vero, è difficile spiegare il funzionamento di un sistema operativo, di un compilatore C e di un'API in 4 battute.
    Alla grossissima, però, funziona così

  4. #4
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    1,469
    Originariamente inviato da ramy89
    In generale nello stack c'è tutto quello che dura per tutta l' esecuzione del programma,quindi le variabili globali e le variabili che dichiari nella main sono nello stack.
    Senza complicare il problema eccessivamente, questo dipende dal compilatore.
    Può memorizzare tutto nello stack, oppure avere un "vero" stack (per le variabili delle funzioni), "tanti" stack (esempio per i fork), uno heap statico, tanti heap statici etc.

    Diciamo che tra i modelli "scolastici" (=supersemplificati) e quelli "veri" (=compilatori "veri") ci possono essere grandi differenze, ma sono dettagli

  5. #5
    Davvero grazie mille per le risposte più che dettagliate!


    Ma quindi, ricapitolando gli effetti che tutto questo ha a livello pratico:
    le variabili locali di una funzione vengono memorizzate nello stack e terminata la funzione "muoiono"?
    e invece, se io voglio che una variabile creata in una funzione, "resti in vita" dopo che la funzione termina, uso l'allocazione dinamica per far si che vengano memorizzate nell'Heap, rimanendo li presenti fino a quando io personalmente non vado a deallocare?
    Salute a voi, da Laikius!

    --> Faber est suae quisque fortunae <--

  6. #6
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    si oppure utilizzi la parola chiave static
    codice:
    int* func( int b )
    {
    static int s;
    s = b;
    return &s;
    }
    Dichiarando static una variabile (in una funzione) non fai nientaltro che dire al compilatore che sebbene sia una variabile locale, deve trattarla come una variabile gloabale (a livello di "esistenza") ... In poche parole la variabile s viene creata alla prima chiamata della funzione e distrutta (automaticamente) alla fine del programma
    C++ 4ever
    496e2062696e6172696f206e6f6e2063692061767265737469 206e656d6d656e6f2020726f7661746f203a29

  7. #7
    Utente di HTML.it
    Registrato dal
    May 2008
    Messaggi
    475
    Originariamente inviato da Laikius91
    Davvero grazie mille per le risposte più che dettagliate!


    Ma quindi, ricapitolando gli effetti che tutto questo ha a livello pratico:
    le variabili locali di una funzione vengono memorizzate nello stack e terminata la funzione "muoiono"?
    e invece, se io voglio che una variabile creata in una funzione, "resti in vita" dopo che la funzione termina, uso l'allocazione dinamica per far si che vengano memorizzate nell'Heap, rimanendo li presenti fino a quando io personalmente non vado a deallocare?
    Esatto.

    Piccola nota per franzauker:

    In altri linguaggi (es. java) il compilatore tiene traccia di queste allocazioni ed è in grado di attivare il "garbage collector"
    Non è il compilatore ma la virtual machine che esegue il codice.
    "Let him who has understanding reckon the number of the beast, for it is a human number.
    Its number is rw-rw-rw-."

  8. #8
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Originariamente inviato da franzauker
    Senza complicare il problema eccessivamente, questo dipende dal compilatore.
    Può memorizzare tutto nello stack, oppure avere un "vero" stack (per le variabili delle funzioni), "tanti" stack (esempio per i fork), uno heap statico, tanti heap statici etc.

    Diciamo che tra i modelli "scolastici" (=supersemplificati) e quelli "veri" (=compilatori "veri") ci possono essere grandi differenze, ma sono dettagli
    Ma in generale c'è un modo per sapere il compilatore dove mette le variabili?
    Io con mingw32 e il debugger di default di code::blocks l' unico mode era ricevere un segmentation fault.
    Quando avevo il segmentation fault mi diceva spesso che era una variabile nello stack ad avere problemi (spesso era un puntatore nullo,o un puntatore fuori zona di allocazione).
    Comunque a me non ha mai riportato un segmentation fault sull' heap,non ho mai visto la parola heap scritta tra gli errori del debugger.
    Comunque un' altra domanda che avevo: ho fatto un piccolo conto,2^32 è all' incirca lo spazio di indirizzamento che serve a memorizzare puntatori di 32 bit,e sul mio widnows 7 a 64 bit i puntatori hanno sempre 4 byte cioè 32 bit di dimensione,eppure la mia macchina è a 64 bit.
    Ma allora c'è un legame tra la quantità di ram che hai e la dimensione di puntatori?
    Io ho 4 gb di ram,ma se sulla mia macchina i puntatori sono di 32 bit come fa un puntatore a tenere traccia di tutta la ram?
    Ci vorrebbero puntatori lunghi 8 byte se non sbaglio i conti.

  9. #9
    I miei quesiti sono stati pienamente chiariti!
    Grazie mille a tutti davvero
    Salute a voi, da Laikius!

    --> Faber est suae quisque fortunae <--

  10. #10
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    1,469
    Originariamente inviato da Ippo343
    Esatto.

    Piccola nota per franzauker:



    Non è il compilatore ma la virtual machine che esegue il codice.
    bhè mi sembrava di aver precisato che questa era la versione per "superniubbi", sennò, a rigore, è tutto falso quanto ho scritto
    Ho tirato fuori java perchè è quello "più simile" a C con un garbage collector.

    Altrimenti esempi ce ne son tanti, a cominciare dal mitico Basic

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.