Imansible liberare i puntatori const in C

Come posso liberare un const char* ? Ho assegnato nuova memoria usando malloc , e quando sto provando a liberarlo ricevo sempre l’errore “tipo di puntatore incompatibile”

Il codice che causa questo è qualcosa del tipo:

 char* name="Arnold"; const char* str=(const char*)malloc(strlen(name)+1); free(str); // error here 

Diverse persone hanno pubblicato la risposta giusta, ma continuano a cancellarla per qualche motivo. Devi lanciarlo su un puntatore non const; free prende un void* , non un const void* :

 free((char*)str); 

Il tuo codice è invertito.

Questo:

 char* name="Arnold"; const char* str=(const char*)malloc(strlen(name)+1); 

Dovrebbe assomigliare a questo:

 const char* name="Arnold"; char* str=(char*)malloc(strlen(name)+1); 

Il tipo di archiviazione const dice al compilatore che non si intende modificare un blocco di memoria una volta allocato (in modo dinamico o statico). Liberare memoria lo sta modificando. Nota, non è necessario eseguire il cast del valore di ritorno di malloc () , ma questo è solo un accenno.

È poco utile allocare dynamicmente la memoria (cosa che si sta facendo, in base alla lunghezza del name ) e dire al compilatore che non si ha intenzione di usarla. Nota, usando il significato scrivendo qualcosa ad esso e poi (opzionalmente) liberandolo in seguito.

La trasmissione a un tipo di archiviazione diverso non risolve il fatto che hai invertito i tipi di archiviazione per iniziare 🙂 Fa semplicemente andare via un avviso, che stava cercando di dirti qualcosa.

Se il codice è invertito (come dovrebbe essere), free() funzionerà come previsto poiché è ansible modificare effettivamente la memoria allocata.

Non ha senso per malloc un puntatore a const, dato che non sarai in grado di modificarne il contenuto (senza brutti hack).

FWIW però, gcc fornisce solo un avvertimento per quanto segue:

 // // const.c // #include  #include  int main(void) { const char *p = malloc(100); free(p); return 0; } $ gcc -Wall const.c -o const const.c: In function 'main': const.c:8: warning: passing argument 1 of 'free' discards qualifiers from pointer target type $ 

Che compilatore stai usando ?

Non c’è alcun scopo nel lanciare un puntatore malloc’d su const. Qualsiasi funzione che accetta un puntatore const non dovrebbe essere responsabile della liberazione della memoria che gli è stata passata.

Ci sono casi in cui vuoi liberare un const* . Tuttavia non vuoi farlo a meno che non lo assegni / assegni nella stessa funzione. Altrimenti potresti rompere le cose. Vedi il codice qui sotto per un esempio del mondo reale. Uso const nelle dichiarazioni delle funzioni per mostrare che non sto cambiando il contenuto degli argomenti. Tuttavia è riassegnato con un duplicato in minuscolo (strdup) che deve essere liberato.

 char* tolowerstring(const char *to_lower) { char* workstring = strdup(to_lower); for(;workstring != '\0'; workstring++) *workstring = tolower(workstring); return workstring; } int extension_checker(const char* extension, const char* to_check) { char* tail = tolowerstring(to_check); extension = tolowerstring(extension); while ( (tail = strstr( tail+1, extension)) ) { /* The +1 prevents infinite loop on multiple matches */ if ( (*extension != '.' ) && ( tail[-1] != '.')) continue; if ( tail[strlen(extension)] == '\0') { free(tail); free( (char*) extension); return 1; } } free(tail); free( (char *) extension); return 0; } 

Potrei sbagliarmi ma penso che il problema si trovi in const . Trasmetti il ​​puntatore a non-const come:

 free((char *) p); 

Perché con const dici: non modificare i dati a cui punta questo puntatore .

Diverse risposte hanno suggerito semplicemente il casting in char* . Ma come el.pescado ha scritto sopra,

lanciare const a non const è un sintomo di odore di codice.

Ci sono avvertimenti del compilatore che si -Wcast-qual da questo, come -Wcast-qual in gcc, che trovo molto utile. Se hai davvero un caso valido per liberare un puntatore const (contrariamente a quanto molti hanno scritto qui, ci sono casi validi, come sottolineato da nlstd), potresti definire una macro per questo scopo in questo modo:

 #define free_const(x) free((void*)(long)(x)) 

Questo funziona almeno per gcc. Il doppio cast rende la logica -Wcast-qual non rilevarlo come “lanciare via const”. Inutile dire che questa macro dovrebbe essere usata con cura. In realtà dovrebbe essere usato solo per i puntatori assegnati nella stessa funzione.

Non è ansible liberare const char * perché è const . Store puntatori ricevuti da malloc in variabili di puntatore non const, in modo che tu possa passarli free . È ansible passare gli argomenti char * alle funzioni utilizzando gli argomenti const char * , ma l’opposto non è sempre vero.

 void foo (const char *x); char *ptr = malloc (...); foo (ptr); free (ptr); 

Se stai parlando di C pura e hai il controllo completo dell’allocazione di memoria puoi usare il seguente trucco per trasmettere (const char *) a (char *) che non ti darà alcun avvertimento nel compilatore:

 const char *const_str = (const char *)malloc(...); char *str = NULL; union { char *mutable_field_p; const char *const_field_p; } u; u.const_field_p = const_str; str = u.mutable_field_p; 

Ora puoi usare free (str); per liberare la memoria.

Ma ATTENZIONE che questo è il male oltre le parole e dovrebbe essere usato solo in un ambiente strettamente controllato (ad es. La libreria che alloca e libera le stringhe, ma non vuole consentire all’utente di modificarle) Altrimenti finirai con il crash del tuo programma quando qualcuno ti fornisce compila il tempo “STRING” alla tua funzione gratuita.

Se dai un’occhiata alla firma della funzione libera, free prende sempre void * ptr come argomento quindi devi lanciarlo sul tipo appropriato ie free ((void *) str); free non consente di dirottare direttamente i puntatori const, quindi devi lanciarli su un tipo non const

Penso che la vera risposta sia che free dovrebbe prendere un argomento pointer const e NULL dovrebbe essere definito come un puntatore const . Questo sembra essere un bug negli standard. Liberare un puntatore const dovrebbe essere implementato come segue:

 free(p); p = NULL; 

Non vedo come un compilatore possa generare codice errato in questo caso, il puntatore const p non è più accessibile, quindi non importa se l’object a cui punta è const , valid, any other. È così non ci possono essere copie sporche nei registri o in qualsiasi altro luogo. È valido impostare un puntatore const su un altro valore e il fatto che tale valore sia NULL non ha importanza perché il valore precedente non è più accessibile.

Penso che anche se lanci il puntatore su un non-const, il risultato del libero arbitrio dipende dall’implementazione. Normalmente const è stato progettato per variabili che non si desidera modificare !!