No se pueden liberar punteros const en C


¿Cómo puedo liberar un const char*? Asigné nueva memoria usando malloc, y cuando intento liberarla siempre recibo el error"tipo de puntero incompatible"

El código que causa esto es algo así como:

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

free(str); // error here
 48
Author: Brian, 2010-05-12

12 answers

Varias personas han publicado la respuesta correcta, pero siguen borrándola por alguna razón. Necesita lanzarlo a un puntero no constante; free toma un void*, no un const void*:

free((char*)str);
 64
Author: Michael Mrozek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 14:14:48

Su código está invertido.

Esto:

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

Debería verse así:

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

El tipo de almacenamiento const le dice al compilador que no tiene la intención de modificar un bloque de memoria una vez asignado (dinámica o estática). Liberar memoria es modificarla. Tenga en cuenta que no necesita lanzar el valor devuelto de malloc(), pero eso es solo un aparte.

Hay poco uso en la asignación dinámica de memoria (que está haciendo, basado en la longitud de name) y decirle al compilador que no tiene intención de usarlo. Note, usando significando escribirle algo y luego (opcionalmente) liberarlo más tarde.

La conversión a un tipo de almacenamiento diferente no soluciona el hecho de que hayas invertido los tipos de almacenamiento para empezar :) Solo hace que una advertencia desaparezca, que estaba tratando de decirte algo.

Si el código se invierte (como debería ser), free() funcionará como se espera, ya que en realidad puede modificar la memoria que asignar.

 19
Author: Tim Post,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:53

No tiene sentido malloc un puntero a const, ya que no podrá modificar su contenido (sin hacks feos).

FWIW sin embargo, gcc solo da una advertencia para lo siguiente:

//
// 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
$ 

¿Qué compilador estás usando ?

 7
Author: Paul R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 14:31:36

No hay ningún propósito en lanzar un puntero malloc'd a const. Cualquier función que toma un puntero const no debe ser responsable de liberar la memoria que se le pasó.

 4
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 15:02:15

Hay casos en los que quieres liberar un const*. Sin embargo, no desea hacerlo a menos que lo asigne/asigne en la misma función. De lo contrario, es probable que rompa cosas. Vea el siguiente código para ver un ejemplo del mundo real. Utilizo const en las declaraciones de función para mostrar que no estoy cambiando el contenido de los argumentos. Sin embargo, es reasignado con un duplicado en minúsculas (strdup) que necesita ser liberado.

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;
}
 4
Author: nlstd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-24 13:01:04

Podría estar equivocado, pero creo que el problema radica en const. Lanza el puntero a non-const como:

free((char *) p);

Porque con const usted dice: No cambie los datos que este puntero apunta a.

 1
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 14:12:50

Varias respuestas han sugerido simplemente lanzar a char*. Pero como el.pescado escribió arriba,

Casting const noconst es un síntoma de código de olor.

Hay advertencias del compilador que protegen contra esto, como -Wcast-qual en gcc, que encuentro muy útil. Si realmente tiene un caso válido para liberar un puntero const (contrariamente a lo que muchos han escrito aquí, hay son casos válidos, como señala nlstd), podría definir una macro para eso propósito como este:

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

Esto funciona al menos para gcc. El doble lanzamiento hace que la lógica -Wcast-qual no detecte esto como "lanzar const lejos". Huelga decir que esta macro debe usarse con cuidado. En realidad, solo debería usarse para punteros asignados en la misma función.

 1
Author: uncleremus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-16 14:38:35

No puedes liberar const char * porque es const. Almacene los punteros recibidos de malloc en variables de puntero no constantes, para que pueda pasarlos a free. Puede pasar char * argumentos a funciones tomando const char * argumentos pero lo contrario no siempre es cierto.

void foo (const char *x);
char *ptr = malloc (...);
foo (ptr);
free (ptr);
 0
Author: el.pescado,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 14:12:44

Si está hablando de C puro y tiene el control completo de la asignación de memoria, puede usar el siguiente truco para convertir (const char *) a (char *) que no le dará ninguna advertencia en el compilador:

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;

Ahora puedes usar free(str); para liberar la memoria.

Pero TENGA CUIDADO de que esto es malo más allá de las palabras y solo debe usarse en un entorno estrictamente controlado (por ejemplo, biblioteca que asigna y libera cadenas, pero no quiere permitir que el usuario las modifique) terminará con su programa fallando cuando alguien proporciona tiempo de compilación "CADENA" a su función libre.

 0
Author: MMasterSK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-23 14:48:06

Si echa un vistazo a la firma de la función free, free siempre toma void * ptr como argumento, por lo tanto, debe enviarlo al tipo apropiado, es decir, free ((void *)str); free no permite que los punteros const se desasignen directamente, por lo tanto, debe lanzarlo a un tipo no const

 0
Author: rstalekar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-07 05:51:24

Creo que la verdadera respuesta es que free debe tomar un argumento de puntero const y NULL debe definirse como un puntero const. Esto parece ser un error en los estándares. Freeing a const pointer should be implemented as follows:

free(p);
p = NULL;

No veo cómo un compilador podría generar código incorrecto en este caso, el puntero const p ya no es accesible, por lo que no importa si el objeto al que apunta es const, válido, lo que sea. Es const así que no puede haber ninguna copia sucia en registros o en cualquier otro lugar. Es válido establecer un puntero const a otro valor, y el hecho de que ese valor sea NULL no importa porque el valor anterior ya no es accesible.

 0
Author: free,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-24 05:20:09

Creo que incluso si lanzas el puntero a una no-const, el resultado del libre albedrío depende de la implementación. Normalmente const fue diseñado para la variable que no desea modificar !!

 -2
Author: Taoufik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 14:42:02