2014-08-29 20 views
11

Per il codice seguente: (1) "main" chiama una funzione "f1". (2) la funzione "f1" esegue alcuni scricchiolii numerici; crea un array di "char" con malloc e quindi restituisce il puntatore dell'array al main (senza de-allocare-freeing- l'array).La memoria allocata in una funzione rimane allocata anche dopo il ritorno della funzione?

ho 3 domande relative al caso: (1) assumo, anche se la funzione "f1" è terminato, char allocato ancora rimane assegnato finché il programma principale termina completamente. Cioè, la memoria allocata appartiene ancora al principale e nessun altro processo può accedere (intendo, interferire con) dall'esterno. Ho ragione? (2) Devo liberare l'array (assegnato in "f1") prima che il programma termini (o viene liberato non appena termina il programma principale)? (3) Se la risposta per la seconda domanda è "sì", come si libera una matrice allocata in un'altra funzione?

nota: voglio rimanere entro i limiti del puro c e non passare al C++.

char *f1 (...) { 
    ... 
    ... 
    char *fTmp = malloc (length1 * sizeof (char)); 
    char *fData = malloc (length2 * sizeof (char)); 
    ... 
    ... 
    free (fTmp); 
    return (fData); 
} 

int main() { 
    char *fData = f1 (...); 
    ... 
    return (0); 
} 

risposta

14

Presumo, sebbene la funzione "f1" sia terminata, l'array di caratteri assegnato rimane ancora assegnato fino a quando il programma principale non termina completamente.

Vero. La memoria allocata dinamicamente non ha nulla a che fare con le funzioni, appartiene al processo.

Vale a dire, la memoria allocata appartiene ancora al principale e nessun altro processo può accedervi dall'esterno. Ho ragione?

memoria non appartiene al main() (inteso come funzione), ma al processo stesso (di cui main() è solo il punto di ingresso). In un sistema con protezione della memoria (in cui ogni processo è isolato dagli altri) non è accessibile dall'esterno. Tuttavia, è possibile allocarlo in un modo specifico del sistema per condividere la memoria tra i processi.

Devo liberare l'array (assegnato in "f1") prima che il programma termini (o viene liberato non appena termina il programma principale)?

Sì. Memoria non allocata - nella maggior parte dei sistemi - viene automaticamente rilasciata dal sistema operativo quando il processo termina ma dipende dal sistema. IMO anche quando il sistema operativo lo fa dovresti sempre deallocarlo, usando tale deallocazione automatica come una bandiera rossa (non ricordo che per deallocare, è un bug? Qualcosa mi è sfuggito?). Inoltre, se f1 viene richiamato 1000 volte, la memoria perderà ogni volta rapidamente consumando tutta la memoria disponibile. Pensa a un processo in un server, potrebbe (e dovrebbe) essere attivo e funzionante per anni.

Se la risposta per la seconda domanda è "sì", come si libera un array assegnato in un'altra funzione?

È bello quando l'allocazione di memoria lo libera anche. Se non è possibile, il chiamante diventerà responsabile di tale memoria. Ad esempio, è quello che fa strdup(). In tal caso, la funzione chiamata deve restituire (in qualche modo) un puntatore alla memoria allocata (o un handle/token che può essere utilizzato da un'altra funzione specializzata). Per esempio:

char* pBuffer = f1(); 
// Use it 
free(pBuffer); 

Nota che ci sono molte molte tecniche, se si desidera nascondere tale interno puntatore.È possibile utilizzare un token (ad esempio un numero intero, una chiave in un dizionario), un typedef o un tipo opaco.

+1

Stavo facendo la stessa cosa; cioè, ho liberato la matrice in un processo che è stato creato in un altro processo ** usando il puntatore passato attraverso **. Non ero sicuro che quello che stavo facendo fosse il modo giusto. Quindi, il tuo approccio sembra la risposta più vicina: "È bello che chi assegna la memoria lo liberi anche. Se non è possibile, il chiamante diventerà responsabile di tale memoria". – ssd

+1

@ merkez3110 ma non è possibile condividere i puntatori tra i processi (a meno che non si stia eseguendo in un ambiente senza memoria virtuale protetta). –

+1

Perdonami per aver usato la terminologia sbagliata: "processo". Nel mio commento sopra, intendevo realmente "funzioni" diverse all'interno dello stesso programma, non processi diversi. Grazie a tutti. – ssd

1

Utilizzando malloc sarà allocare memoria sul mucchio fino a quando non si free esso.

Ciò significa che è necessario assicurarsi che ogni malloc abbia una corrispondenza gratuita, inoltre non è implicito che nessun altro processo non possa accedere ai dati. È solo un valore a un indirizzo.

Nel vostro principale è necessario free(fData) evitare una perdita di memoria.

Riassumendo quindi:

1) La tua prima ipotesi è corretta, il secondo e il terzo non lo è. Rimarrà allocato, ma non è locale al principale e non è associato al processo mentre termina .

2) Sì, è necessario liberarlo

3) Utilizzare il puntatore si ottiene dalla funzione. Se non si restituisce un puntatore ai dati allocati da una funzione, assicurarsi che la funzione sia free s.

1
  1. Sì, è ancora in pila. Tuttavia, stai confondendo sul concetto di processo. A meno che non si crei un altro processo (utilizzando fork su * nix), è sempre la stessa procedura.

  2. È una buona abitudine liberare la memoria quando non viene utilizzata. Ma se il programma termina normalmente, la memoria allocata viene liberata dal sistema.

  3. Ti piace questa:

    int main() { 
        char *fData = f1 (...); 
        //... 
        free(fData); 
        //... 
    } 
    
4
  1. Sì, la memoria allocata con malloc() soggiorni fino a quando non viene liberato. In quale altro modo una funzione può mai restituire dati variabili al suo chiamante?

  2. Quando un programma viene chiuso, tutta la memoria allocata con malloc() viene liberata. Tuttavia, non è generalmente una buona idea conservare una quantità di memoria non necessaria fino alla fine del programma, poiché può influire sulle prestazioni, oppure il sistema può esaurire la memoria virtuale. Questo può rappresentare una preoccupazione particolare per i programmi di lunga durata, a volte il loro uso della memoria continua a crescere fino a quando non utilizzano tutta la memoria virtuale disponibile.

  3. Si chiama free() sul puntatore restituito dalla funzione. Quindi nel tuo caso, main() può fare free(fData) dopo aver finito di usare l'array.

Questo dovrebbe essere coperto in qualsiasi classe di programmazione C o libro di testo.

2

malloc alloca memoria su heap e pertanto questa memoria rimane allocata finché non viene liberata dalla funzione free o il programma termina correttamente.
Nel tuo caso hai liberato ftemp in f1 in modo che non esista più al termine della funzione. fdata è ancora in memoria ed è accessibile a main mentre si restituisce il puntatore a tale posizione allocata.

Una volta che main termina correttamente, la memoria indicata da fdata viene liberata.

Quindi, è considerato buono per liberare memoria non appena non ne hai più bisogno. Non ha senso liberare i blocchi alla fine di un programma, perché tutto lo spazio del programma viene restituito al sistema quando il processo termina (considerando i moderni sistemi operativi).

1

Ci sono due tipi base di memoria con cui si può lavorare in C. I due tipi sono lo stack e l'heap. In generale, le variabili che crei all'interno di una funzione verranno allocate nello stack e verranno liberate al termine della funzione. La memoria allocata nell'heap persisterà e tu sarai obbligato a gestire quella allocazione all'interno del tuo programma. La memoria nell'heap rimarrà allocata finché non si libera usando il puntatore (indirizzo di memoria) che si riferisce al blocco di dati.

Una piccola lettura su entrambi ti aiuterà a capire. Ti segnalo che hai due istanze di fData, ciascuna con il proprio ambito. Entrambi i puntatori indicano la memoria si alloca con:

char *fData = malloc (length2 * sizeof (char)); 

.. anche se passano dentro e fuori del campo di applicazione il codice viene eseguito.

1

Se non si libera memoria che non si sta utilizzando, alla fine ciò si accumulerebbe, se lo si faceva con molti altri indicatori, e il programma potrebbe esaurire la memoria. Dopo aver liberato un blocco di memoria usando la funzione free, suggerirei anche di assegnare NULL al puntatore in quanto questo protegge da puntatori penzolanti come anche se hai liberato un puntatore, se provi ad accedervi, potresti ottenere un comportamento indefinito, mentre l'accesso e le operazioni sui puntatori NULL provocano un arresto anomalo, quindi sarebbe facilmente in grado di tracciare il problema

Problemi correlati