OK alcune risposte su malloc erano già state pubblicate.
La parte più interessante è come funziona il libero (e in questa direzione, anche il malloc può essere compreso meglio).
In molte implementazioni malloc / free, free normalmente non restituisce la memoria al sistema operativo (o almeno solo in rari casi). Il motivo è che otterrai spazi vuoti nel tuo heap e quindi può succedere, che finisci i tuoi 2 o 4 GB di memoria virtuale con spazi vuoti. Questo dovrebbe essere evitato, poiché non appena la memoria virtuale sarà terminata, avrai davvero grossi problemi. L'altro motivo è che il sistema operativo può gestire solo blocchi di memoria di dimensioni e allineamento specifici. Per essere precisi: normalmente il sistema operativo può gestire solo blocchi che il gestore della memoria virtuale è in grado di gestire (il più delle volte multipli di 512 byte, ad esempio 4KB).
Quindi la restituzione di 40 byte al sistema operativo non funzionerà. Quindi cosa fa gratis?
Free inserirà il blocco di memoria nel proprio elenco di blocchi gratuiti. Normalmente tenta anche di fondere insieme blocchi adiacenti nello spazio degli indirizzi. L'elenco dei blocchi liberi è solo un elenco circolare di blocchi di memoria che all'inizio hanno alcuni dati amministrativi. Questo è anche il motivo per cui la gestione di elementi di memoria molto piccoli con lo standard malloc / free non è efficiente. Ogni blocco di memoria necessita di dati aggiuntivi e con dimensioni inferiori si verifica una maggiore frammentazione.
L'elenco libero è anche il primo posto che viene visualizzato da Malloc quando è necessaria una nuova porzione di memoria. Viene scansionato prima che richieda nuova memoria dal sistema operativo. Quando viene trovato un pezzo più grande della memoria necessaria, viene diviso in due parti. Uno viene restituito al chiamante, l'altro viene riportato nell'elenco gratuito.
Esistono diverse ottimizzazioni per questo comportamento standard (ad esempio per piccoli blocchi di memoria). Ma poiché malloc e free devono essere così universali, il comportamento standard è sempre il fallback quando le alternative non sono utilizzabili. Esistono anche ottimizzazioni nella gestione dell'elenco libero, ad esempio la memorizzazione dei blocchi in elenchi ordinati per dimensioni. Ma anche tutte le ottimizzazioni hanno i loro limiti.
Perché il tuo codice si arresta in modo anomalo:
Il motivo è che scrivendo 9 caratteri (non dimenticare il byte null finale) in un'area dimensionata per 4 caratteri, probabilmente sovrascriverai i dati amministrativi memorizzati per un altro blocco di memoria che risiede "dietro" il tuo blocco di dati ( poiché questi dati sono spesso memorizzati "davanti" ai blocchi di memoria). Quando libero prova quindi a mettere il tuo pezzo nella lista libera, può toccare questi dati amministrativi e quindi inciampare su un puntatore sovrascritto. Questo causerà l'arresto anomalo del sistema.
Questo è un comportamento piuttosto grazioso. Ho anche visto situazioni in cui un puntatore in fuga da qualche parte ha sovrascritto i dati nell'elenco di memoria libera e il sistema non si è arrestato immediatamente ma alcune subroutine in seguito. Anche in un sistema di media complessità tali problemi possono essere davvero molto difficili da eseguire il debug! Nel primo caso in cui sono stato coinvolto, ci sono voluti diversi giorni (un gruppo più ampio di sviluppatori) per trovare il motivo dell'incidente, poiché si trovava in una posizione completamente diversa da quella indicata dal dump della memoria. È come una bomba a orologeria. Sai, il tuo prossimo "libero" o "malloc" andrà in crash, ma non sai perché!
Questi sono alcuni dei peggiori problemi di C / C ++ e uno dei motivi per cui i puntatori possono essere così problematici.