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
48
demandé sur Brian 2010-05-12 18:08:13

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);
64
répondu Michael Mrozek 2010-05-12 14:14:48

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.

19
répondu Tim Post 2017-05-23 12:09:53

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 ?

7
répondu Paul R 2010-05-12 14:31:36

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.

4
répondu Puppy 2010-05-12 15:02:15

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;
}
4
répondu nlstd 2011-04-24 13:01:04

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 .

1
répondu Felix Kling 2010-05-12 14:12:50

plusieurs réponses ont suggéré simplement casting à char* . Mais comme el.pescado a écrit ci-dessus,

casting const non const 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.

1
répondu uncleremus 2018-02-16 14:38:35

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);
0
répondu el.pescado 2010-05-12 14:12:44

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.

0
répondu MMasterSK 2013-08-23 14:48:06

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

0
répondu rstalekar 2018-03-07 05:51:24

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.

0
répondu free 2018-08-24 05:20:09

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 !!

-2
répondu Taoufik 2010-05-12 14:42:02