Domanda

int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

Sembra funzionare bene, ma sono ancora leggermente confuso su stack vs heap. È permesso? Se è consentito, myString deve essere liberato manualmente o verrà rilasciato quando esce dal campo di applicazione?


Modifica: grazie per le risposte, quindi presumo che sia ugualmente illegale

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
È stato utile?

Soluzione

No, questo è completamente sbagliato. realloc dovrebbe essere usato solo per riallocare la memoria allocata da malloc, quello che stai facendo funziona solo per caso, e alla fine andrà in crash orribilmente

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

Stai meglio usando new ed delete, e ancora meglio usando std :: string, comunque.

Altri suggerimenti

Alcuni problemi con il codice che hai pubblicato:

  • Sì, è necessario liberare tutto ciò che viene allocato con malloc e realloc e le altre funzioni di allocazione della memoria in stile C correlate.
  • Penso che intendevi avere char * myString, non char. Passare l'indirizzo di qualcosa nello stack (il tuo carattere) è completamente sbagliato.
  • È necessario inizializzare il puntatore char myString su NULL prima di utilizzarlo in realloc.
  • Dovresti passare 4 in strncpy e non 5, se avessi una stringa più grande dovresti sovrascrivere la memoria.
  • Dovresti liberare il buffer che hai creato nel tuo esempio
  • Dovresti controllare il valore restituito della tua chiamata realloc. realloc ()
  

[Per quanto riguarda il valore di ritorno di realloc:] Al completamento con esito positivo con una dimensione   non uguale a 0, realloc () restituisce a   puntatore al (eventualmente spostato)   spazio assegnato. Se la dimensione è 0, neanche   un puntatore nullo o un puntatore univoco   che può essere passato con successo   viene restituito free (). Se non c'è   memoria disponibile sufficiente, realloc ()   restituisce un puntatore null e imposta errno   a [ENOMEM].

  • la riassegnazione funzionerà come malloc quando passi NULL:
  

Se ptr è un puntatore null, realloc ()   si comporta come malloc () per il   dimensione specificata.

Un modo più C ++ per farlo:

Hai taggato questo come C ++, ed è più sicuro usare il nuovo operatore di C ++. Sebbene il nuovo operatore non consenta le riassegnazioni, funzionerà per le allocazioni e per riutilizzare i buffer esistenti (posizionamento nuovo).

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

o anche:

#include <string>

//...

std::string str = "test";

Fonte delle prime 2 citazioni

Questo non dovrebbe funzionare. Stai realloppando qualcosa che non è stato deriso in primo luogo. E no, non verrà liberato quando andrà al di fuori dell'ambito - quando usi malloc o realloc, dipende tutto da te.

Aggiornamento: la modifica non cambia nulla: stai ancora cercando di riallocare qualcosa che non è stato eseguito il malfunzionamento in primo luogo. Inoltre, non puoi ignorare il valore restituito da realloc - se realloc deve spostare la memoria da qualche altra parte, lo troverai nel ritorno. In altre parole:

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

Dopo realloc, ptr potrebbe puntare a un posto completamente diverso nella memoria, e continuare a usare il valore originale di ptr potrebbe lasciarti usando la memoria che è stata liberata e che non è grande come pensi che sia.

QUESTO È PERICOLOSO! Questo danneggerà il tuo stack. Se dovessi riallocare qualcosa nello stack di una funzione che poi tornasse a main (), finiresti per sovrascrivere il frame dello stack e tornare in un posto diverso da main (). QUESTO È UN FORO DI SICUREZZA POTENZIALE.

Prova a eseguire quanto segue. Se si blocca su Realloc, sei fortunato. Puoi fare gravi danni con qualcosa come memcpy (& amp; myString).

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}

Questo è ciò che non dovresti mai fare. Cercare di liberare () o realloc () una variabile di stack può portare a comportamenti indefiniti tra cui (ma non limitato a) stack corrotto (che porta a un flusso di controllo imprevedibile), strutture di servizio heap danneggiate, memoria utente danneggiata. Sei fortunato se il programma si blocca con un AV. In alcuni casi potrebbe funzionare, ma non dovresti mai provare a farlo.

Regola empirica: restituisce la memoria solo al gestore della memoria su cui è stata allocata. In questo caso, non tentare di restituire la variabile stack all'heap di runtime.

Il tuo programma è sinteticamente valido in C ++, ma produrrà un comportamento indefinito perché passi l'indirizzo di un oggetto stack all'allocatore di heap. In genere questo significa che il programma si arresterà in modo anomalo quando eseguito.

Lo stack e l'heap sono due aree distinte di memoria allocate al processo che esegue il programma. Lo stack cresce quando si inserisce una funzione per contenere i suoi argomenti e le variabili locali e si restringe automaticamente quando si ritorna dalla funzione. L'heap, d'altra parte, è un'area di indirizzi separata in cui la memoria può essere ottenuta su richiesta e deve essere rilasciata esplicitamente quando non è più necessaria.

Se l'indirizzo di una variabile locale viene passato a realloc (), potrebbe tentare di liberare la sua memoria e allocarla altrove. Poiché l'indirizzo non proviene dall'heap e realloc () opera sull'heap, ciò non riuscirà. Molto probabilmente realloc () rileverà l'indirizzo non dall'heap e interromperà il programma.


A parte questo, il programma di esempio contiene alcuni errori logici.


char myString = NULL;

Dichiara una variabile per contenere un carattere, non una stringa. Una stringa in stile C ha il tipo char * , ovvero un puntatore a char.

Inoltre, al carattere viene assegnato NULL , l'indirizzo zero assegnato in modo convenzionale a puntatori non validi. Questo viene compilato perché il preprocessore sostituisce NULL con il 0 letterale. In realtà, si memorizza un byte zero nel carattere, che è, anche per convenzione, il terminatore di una stringa in stile C.


realloc(&myString, 5);

Come accennato in precedenza, questo è illegale perché si passa l'indirizzo di un oggetto stack all'allocatore di heap. Questo problema rimane nel secondo esempio di codice.

Inoltre, si elimina il valore restituito. realloc () restituisce l'indirizzo in cui è stata allocata la nuova memoria. Potrebbe non essere lo stesso indirizzo di prima. Potrebbe anche essere NULL, che è il modo di realloc () per dirti che è andato fuori memoria.


strncpy((char *)&myString, "test", 5);

Questo è corretto, ma il cast è ridondante.


Ecco una versione più corretta del tuo programma:


#include <stdlib.h>
#include <string.h>

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

In C ++, è meglio evitare del tutto realloc (). Ad esempio, potresti usare qualcosa di simile al seguente:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

Non è necessario liberare myString poiché è nello stack (che viene "liberato" quando si lascia l'ambito).

realloc è illegale qui, l'indirizzo deve essere NULL o un indirizzo restituito da una precedente chiamata a realloc , malloc o calloc .

Ogni variabile dichiarata è nello stack, anche un puntatore:

int * x;

La variabile x è nello stack! È di tipo pointer e contiene un indirizzo.

x = (int *) malloc (sizeof (int));

assegna l'indirizzo restituito da malloc alla variabile x! Il contenuto di x è un indirizzo di memoria!

Il problema con quello che stai facendo è che stai confondendo qualcosa che non è una variabile. Hai definito myString come carattere e stai quindi cercando di cambiarne l'indirizzo. Questo è male.

La funzione realloc () non dovrebbe cambiare nulla che vi sia passato. Prende un puntatore a un po 'di memoria sull'heap (o il puntatore null, se non è già stato allocato nulla) e restituisce un puntatore a un po' di memoria sull'heap.

Pertanto, si fornisce un puntatore nullo o un puntatore a qualcosa allocato da malloc () o realloc () o calloc () e si memorizza il puntatore restituito.

Qualcosa di simile

char * myString = NULL;
myString = realloc(myString, 5);

funzionerà, ma vorrai liberare () myString.

In C ++, tuttavia, utilizzare std :: string.

In risposta al tuo secondo esempio di codice:

Sì, anche questo è illegale. myString non è allocato con malloc (o calloc), quindi non può essere riallocato con realloc o liberato con free.

Inoltre quel realloc non prende un puntatore a un puntatore come primo argomento. Prende un puntatore alla memoria allocata e restituisce un altro puntatore (possibilmente diverso). Scrivi invece la chiamata in questo modo:

myString = realloc(myString, strlen(myString)+2);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top