Incapable de libérer des pointeurs de const en C
Comment puis-je libérer un const char*
? J'ai alloué une nouvelle mémoire en utilisant malloc
, et quand j'essaie de la libérer, je reçois toujours l'erreur "incompatible pointer type"
le code qui provoque ceci est quelque chose comme:
char* name="Arnold";
const char* str=(const char*)malloc(strlen(name)+1);
free(str); // error here
12 réponses
plusieurs personnes ont posté la bonne réponse, mais ils continuent à la supprimer pour une raison quelconque. Vous devez le lancer à un pointeur non-const; free
prend un void*
, pas un const void*
:
free((char*)str);
votre code est inversé.
:
char* name="Arnold";
const char* str=(const char*)malloc(strlen(name)+1);
devrait ressembler à ceci:
const char* name="Arnold";
char* str=(char*)malloc(strlen(name)+1);
le type de stockage const
indique au compilateur que vous n'avez pas l'intention de modifier un bloc de mémoire une fois alloué (dynamiquement, ou statiquement). Libérer la mémoire, c'est la modifier. Notez que vous n'avez pas besoin de lancer la valeur de retour de malloc() , mais c'est juste une mise de côté.
Il y a peu d'utilité à allouer dynamiquement la mémoire (ce que vous faites, basé sur la longueur de name
) et dire au compilateur que vous n'avez pas l'intention de l'utiliser. Remarque, à l'aide sens de l'écriture quelque chose et puis (éventuellement) de libérer plus tard.
moulage à un type de stockage différent ne fixe pas le fait que vous avez inversé les types de stockage pour commencer :) il fait juste un avertissement disparaître, qui essayait de vous dire quelque chose.
Si le code est inversé (comme il faut), free()
fonctionne comme prévu puisque vous pouvez modifier la mémoire allouée.
cela n'a aucun sens de malloc un pointeur à const, puisque vous ne pourrez pas modifier son contenu (sans de vilains hacks).
FWIW si, gcc donne juste un avertissement pour la suite:
//
// const.c
//
#include <stdio.h>
#include <stdlib.h>
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
$
quel compilateur utilisez-vous ?
il n'y a pas de raison de lancer un pointeur malloc'd à const. Toute fonction qui prend un pointeur const ne devrait pas être responsable de libérer la mémoire qui lui a été transmise.
il y a des cas où vous voulez libérer un const*
. Cependant, vous ne voulez pas le faire à moins que vous allouer/assigner dans la même fonction. Sinon vous risquez de casser des choses. Voir le code ci-dessous pour un exemple réel. J'utilise const
dans les déclarations de fonction pour montrer que je ne change pas le contenu des arguments. Toutefois, il est réassigné avec un double minuscule (strdup) qui doit être libéré.
char* tolowerstring(const char *to_lower)
{
char* workstring = strdup(to_lower);
for(;workstring != '"151900920"'; 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)] == '"151900920"') {
free(tail);
free( (char*) extension);
return 1;
}
}
free(tail);
free( (char *) extension);
return 0;
}
je pourrais me tromper mais je pense que le problème réside dans const
. Lancer le pointeur à non-const comme:
free((char *) p);
parce qu'avec const
vous dites: ne changez pas les données que ce pointeur pointe en .
plusieurs réponses ont suggéré simplement casting à char*
. Mais comme el.pescado a écrit ci-dessus,
casting
const
nonconst
est un symptôme de l'odeur de code.
il y a des avertissements de compilateur qui s'en prémunissent, comme -Wcast-qual
dans gcc, que je trouve très utile. Si vous vraiment avez un cas valable pour libérer un pointeur const
(contrairement à ce que beaucoup ont écrit ici, il sont cas valides, comme l'a souligné la nlstd), vous pourriez définir une macro à cette fin comme ceci:
#define free_const(x) free((void*)(long)(x))
Cela fonctionne au moins pour gcc. Le double moulage fait que la logique -Wcast-qual
ne le détecte pas comme"casting const away". Inutile de dire que cette macro doit être utilisé avec précaution. En fait, il ne doit être utilisé que pour les pointeurs affectés à la même fonction.
vous ne pouvez pas Vous libérer const char *
parce que c'est const
. Stockez les pointeurs reçus de malloc
dans des variables de pointeur non-const, de sorte que vous pouvez les passer à free
. Vous pouvez passer char *
arguments aux fonctions prenant const char *
arguments, mais le contraire n'est pas toujours vrai.
void foo (const char *x);
char *ptr = malloc (...);
foo (ptr);
free (ptr);
si vous parlez de C pur et que vous êtes en contrôle complet de l'allocation de mémoire, vous pouvez utiliser l'astuce suivante pour lancer (const char *) à (char *) qui ne vous donnera aucun avertissement dans le compilateur:
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;
Maintenant vous pouvez utiliser free(str); pour libérer la mémoire.
mais méfiez-vous que c'est un mal au-delà des mots et ne doit être utilisé que dans un environnement strictement contrôlé (par exemple une bibliothèque qui alloue et libère des chaînes, mais ne souhaitez autoriser l'utilisateur à modifier) Sinon vous allez vous retrouver avec votre programme plante lorsque quelqu'un fournit la compilation "CHAÎNE" à votre fonction.
si vous regardez la signature de la fonction libre , free prend toujours void* ptr comme argument et vous devez donc le lancer au type approprié, c'est-à-dire free((void *)str); free ne permet pas de désallouer directement les pointeurs de const, vous devez donc le mouler à un type non const
je pense que la vraie réponse est que free devrait prendre un argument de pointeur const
et NULL
devrait être défini comme un pointeur const
. Cela semble être un bug dans les normes. Libérer un pointeur const
devrait être mis en œuvre comme suit:
free(p);
p = NULL;
Je ne vois pas comment un compilateur pourrait générer un code incorrect dans ce cas, le const
pointeur p
n'est plus accessible, de sorte qu'il n'a pas d'importance si l'objet pointé vers est const
, valide, quoi que ce soit d'autre. C'est const
donc il ne peut pas y avoir de copies sales dans les registres ou ailleurs. Il est valide de définir un pointeur const
à une autre valeur, et le fait que cette valeur soit NULL
n'a pas d'importance parce que la valeur précédente n'est plus accessible.
je pense que même si vous lancez le pointeur vers un non-const, le résultat du libre arbitre dépend de la mise en œuvre. Normalement const a été conçu pour variable que vous ne voulez pas modifier !!