2010-07-17 16 views
5

Qual è la differenza tra questo:C++: definizione del campo locale rispetto a una chiamata malloc

somefunction() { 
    ... 
    char *output; 
    output = (char *) malloc((len * 2) + 1); 
    ... 
} 

e questo:

somefunction() { 
    ... 
    char output[(len * 2) + 1]; 
    ... 
} 

Quando è uno più appropriato rispetto agli altri?

grazie a tutti per le vostre risposte. ecco un riassunto:

  1. ex. 1 è l'allocazione heap
  2. ex. 2 è allocazione pila
  3. c'è un limite di dimensione in pila, utilizzarlo per allocazioni piccole
  4. bisogna assegnazione mucchio libera, o esso colerà
  5. l'allocazione dello stack non è accessibile dopo la funzione esce
  6. l'allocazione heap è accessibile fino a liberarlo (o l'applicazione finisce)
  7. VLA di non fanno parte dello standard C++

correzioni benvenuto.

ecco qualche spiegazione della differenza tra mucchio vs pila:
What and where are the stack and heap?

+0

Si consiglia di consultare il libro C++. Se non si dispone di un libro C++, si consiglia di ottenere uno dei testi per principianti elencati in [La guida e elenco libri C++ completi] (http://stackoverflow.com/questions/388242/the-definitive-c-book -guida-e-list). –

+4

Inoltre, la domanda dipende interamente da come viene definito 'len'; se non è una costante, il secondo esempio di codice è C++ mal formato. –

+0

len è un valore int e viene assegnato al risultato di strlen all'interno della funzione. – Gush

risposta

5

Utilizzare la gente del posto quando si dispone solo di una piccola quantità di dati e non si useranno i dati al di fuori dell'ambito della funzione in cui è stato dichiarato. Se si desidera passare i dati in giro, utilizzare malloc.

Le variabili locali vengono mantenute nello stack, che è molto più limitato rispetto all'heap, dove gli array allocati con malloc go. Di solito vado a cercare qualcosa> 16 byte vengono messi nello heap, ma tu hai un po 'più di flessibilità. Basta non allocare i locali nell'intervallo di dimensioni kb/mb - appartengono all'heap.

+2

+1 per menzionare le limitazioni di dimensione dello stack, ma penso che 16 byte siano un po 'bassi. Non è la dimensione dello stack predefinita sulla maggior parte delle piattaforme nei megabyte (quindi le variabili multi-KB dovrebbero andare bene nella maggior parte dei casi)? –

+0

Sì, ma quando si assegnano allo stack, è necessario considerare anche la durata dei dati e le dimensioni. Intendevo 16 byte per valori le cui vite potrebbero non essere conosciute. Potresti allocare diversi kb nello stack, quindi diramarti in un'altra funzione, che alloca anche molti kb, e così via - può rapidamente riempire. (Discusso di più sulla risposta StackedCrooked.) –

+3

Poiché la domanda riguarda C++, mi oppongo fermamente alla raccomandazione di utilizzare malloc. In C, usa malloc. In C++, usa nuovo. –

6

La prima memoria alloca sul mucchio. Devi ricordare di liberare la memoria, altrimenti si diffonderà. Questo è appropriato se la memoria deve essere utilizzata al di fuori della funzione o se è necessario allocare un'enorme quantità di memoria.

Il secondo alloca la memoria nello stack. Sarà recuperato automaticamente quando la funzione ritorna. Questo è il più conveniente se non è necessario restituire la memoria al chiamante.

+1

D'altra parte, non si vuole mettere troppo in pila, perché non è grande quanto l'heap. Quindi, "int data [10]" va bene, ma non conterei su "int data [10000]" che funzioni affatto. – zvone

5

Il primo esempio alloca un blocco di memoria dall'heap. Il secondo assegna l'archiviazione dallo stack. La differenza diventa visibile quando si restituisce l'output da somefunction(). La memoria allocata dinamicamente è ancora disponibile per l'uso, ma lo storage basato su stack nel secondo esempio è, um, da nessuna parte. È ancora possibile scrivere in questo archivio e leggerlo per un po ', fino alla prossima volta che si chiama una funzione, in quel momento la memoria verrà sovrascritta in modo casuale con gli indirizzi di ritorno, gli argomenti e così via.

C'è anche un sacco di altre cose strane in corso con il codice in questa domanda. Prima di tutto, questo è un programma C++, che ci si vuole utilizzare nuovi invece di malloc() in modo che ci si dice

output = new char[len+1]; 

E che cosa è con la len * 2 + 1 in ogni caso?Forse questo è qualcosa di speciale nel tuo codice, ma suppongo che tu voglia allocare caratteri unicode o caratteri multibyte. Se è unicode, la terminazione nulla prende due byte e ogni carattere lo fa, e char è il tipo sbagliato, essendo 8 bit byte nella maggior parte dei compilatori. Se è multibyte, allora hey, tutte le scommesse sono disattivate.

+1

+1 per nuovo vs malloc – bstpierre

+0

Non so se ciò che sto facendo è corretto - ma deriva dai documenti per PQescapeStringConn - "'to' punterà a un buffer che è in grado di contenere almeno un altro byte del doppio del valore della lunghezza " da qui: http://www.postgresql.org/docs/7.3/static/libpq-exec.html – Gush

3

Prima alcuni termini:

  • Il primo campione è chiamato mucchio allocazione.
  • Il secondo campione è denominato allocazione stack.

La regola generale è: allocare in pila, a meno che:

  1. La dimensione richiesta della matrice è noto al momento della compilazione.
  2. La dimensione richiesta supera il 10% della dimensione totale dello stack. La dimensione dello stack predefinita su Windows e Linux è solitamente 1 o 2 MB. Quindi la tua matrice locale non dovrebbe superare i 100.000 byte.
+1

Penso che quelle regole generali siano un po 'deboli. Per esempio, potrei allocare il 10% del mio stack in main(), e quindi chiamare qualche altra funzione (che a sua volta chiamerà sempre di più, ognuno riempendo lo stack). Non riuscirò a liberare lo spazio finché tutte le mie funzioni più profonde non saranno completate (essenzialmente la fine del programma in questo caso). Il mio programma ha automaticamente il 10% in meno di spazio nello stack. Penso che la regola del 10% debba essere limitata alle sole ** pure ** funzioni. –

+1

@ Mark H: Hai ragione che la regola del 10% non dovrebbe essere allocata in main, e certamente non nel codice di rientro. Tuttavia, non vedo come le funzioni pure siano più sicure contro l'overflow dello stack rispetto alle funzioni non pure. – StackedCrooked

+1

Una funzione pura non chiamerà altre funzioni (a meno che non siano esse stesse pure), ma generalmente eseguiranno alcuni algoritmi e ritorneranno immediatamente. Qualsiasi variabile locale allocata in esse sarà di breve durata, che è come dovrebbe essere lo stack. Le variabili che hanno una durata più lunga (come nell'esempio precedente) dovrebbero andare in heap. –

1

Hai taggato la tua domanda sia con C++ sia con C, ma la seconda soluzione non è consentita in C++. Gli array di lunghezza variabile sono consentiti solo in C (99).

Se si suppone che "len" sia una costante, funzioneranno entrambi.

malloc() (e 'nuovo' di C++) allocano la memoria sull'heap, il che significa che è necessario liberare() (o se si è assegnato con 'nuovo', 'cancella') il buffer, o la memoria mai essere reclamato (perdita).

Quest'ultimo alloca l'array nello stack e scomparirà quando non sarà più disponibile. Ciò significa che non è possibile restituire i puntatori al buffer al di fuori dell'ambito in cui è allocato.

Il primo è utile quando si desidera passare il blocco della memoria (ma in C++, è meglio gestirlo con una classe RAII, non manualmente), mentre il secondo è il migliore per i piccoli array a dimensione fissa che devono essere presenti in un unico ambito.

Infine, è possibile contrassegnare la matrice altrimenti impilare-allocato con 'statica' toglierla pila e in una sezione di dati globale:

static char output[(len * 2) + 1]; 

Ciò consente di restituire i puntatori al buffer di fuori di Nel suo ambito, tuttavia, tutte le chiamate a tale funzione faranno riferimento allo stesso pezzo di dati globali, quindi non usarlo se hai bisogno di un blocco di memoria univoco ogni volta.

Infine, non utilizzare malloc in C++ a meno che non si abbia una buona ragione (vale a dire, realloc). Usa invece 'new' e l''eliminazione' che accompagna.

+0

da http: //gcc.gnu.org/onlinedocs/gcc/Variable-Length.html Gli array automatici a lunghezza variabile sono consentiti in ISO C99 e come estensione GCC li accetta in modalità C90 e in C++. Immagino sia per questo che compila e lavora per me usando gcc. Potrei credere che non sia C++ secondo lo standard o la definizione appropriata della lingua a cui potresti riferirti. Devo rimuovere il tag C++? – Gush

+0

Mi stavo solo chiedendo quale stavi usando, ma per me assumere il C++, ho pensato di avvertirti che i VLA non fanno parte del C++ standard. –

+0

ok. non lo sapevo ed è pertinente – Gush

Problemi correlati