Невозможно освободить константные указатели в C - PullRequest
62 голосов
/ 12 мая 2010

Как я могу освободить const char*? Я выделил новую память, используя malloc, и когда я пытаюсь освободить ее, я всегда получаю сообщение об ошибке «несовместимый тип указателя»

Код, который вызывает это что-то вроде:

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

free(str); // error here

Ответы [ 12 ]

78 голосов
/ 12 мая 2010

Несколько человек опубликовали правильный ответ, но почему-то продолжают его удалять. Вам нужно привести его к неконстантному указателю; free занимает void*, а не const void*:

free((char*)str);
23 голосов
/ 13 мая 2010

Ваш код перевернут.

Это:

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

Должно выглядеть так:

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

Тип хранения const сообщает компилятору, что вы не собираетесь изменять блок памяти после выделения (динамически или статически). Освобождение памяти изменяет это. Обратите внимание, вам не нужно приводить возвращаемое значение malloc () , но это всего лишь отступление.

Мало пользы в динамическом выделении памяти (которую вы делаете, исходя из длины name) и сообщении компилятору о том, что вы не собираетесь ее использовать. Обратите внимание, что с использованием означает запись чего-либо в него, а затем (необязательно) освобождение этого позже.

Приведение к другому типу хранилища не исправляет тот факт, что вы сначала изменили типы хранилищ :) Это просто выводит предупреждение, которое пыталось вам что-то сказать.

Если код перевернут (как и должно быть), free() будет работать, как и ожидалось, поскольку вы можете изменить выделенную вами память.

6 голосов
/ 12 мая 2010

Нет смысла неправильно указывать указатель на const, поскольку вы не сможете изменять его содержимое (без уродливых хаков).

FWIW, однако, gcc просто выдает предупреждение для следующего:

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

Какой компилятор вы используете?

4 голосов
/ 24 апреля 2011

Есть случаи, когда вы хотите освободить const*. Однако вы не хотите делать это, пока не выделите / не назначите его в той же функции. В противном случае вы можете сломать вещи. Посмотрите код ниже для реального примера. Я использую const в объявлениях функций, чтобы показать, что я не изменяю содержимое аргументов. Однако это переназначено с дубликатом в нижнем регистре (strdup), который должен быть освобожден.

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;
}
3 голосов
/ 12 мая 2010

Нет смысла приводить указатель malloc на const. Любая функция, которая принимает указатель const, не должна отвечать за освобождение памяти, которая была ей передана.

1 голос
/ 16 февраля 2018

Несколько ответов предложили просто привести к char*. Но, как писал выше el.pescado,

приведение const к не- const является признаком кодового запаха.

Есть предупреждения компилятора, которые защищают от этого, такие как -Wcast-qual в gcc, что я считаю очень полезным. Если у вас действительно есть действительный регистр для освобождения указателя const (вопреки тому, что многие здесь написали, являются действительными случаями, как указано в nlstd), вы можете определить макрос для этой цели:

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

Это работает по крайней мере для GCC. Двойное приведение заставляет логику -Wcast-qual не обнаруживать это как "отбрасывание конста". Излишне говорить, что этот макрос следует использовать с осторожностью. На самом деле его следует использовать только для указателей, выделенных в одной и той же функции.

1 голос
/ 12 мая 2010

Я могу ошибаться, но я думаю, что проблема заключается в const. Приведите указатель к неконстантному типу:

free((char *) p);

Потому что с const вы говорите: Не меняйте данные, на которые указывает указатель, на .

0 голосов
/ 24 августа 2018

Я думаю, что реальный ответ заключается в том, что free должен принимать аргумент указателя const, а NULL должен определяться как указатель const. Это похоже на ошибку в стандартах. Освобождение указателя const должно быть реализовано следующим образом:

free(p);
p = NULL;

Я не вижу, как компилятор может генерировать неправильный код в этом случае, указатель const p больше не доступен, поэтому не имеет значения, является ли объект, на который он указывал, const, допустимым , что угодно. Это const, поэтому в регистрах или где-либо еще не может быть грязных копий. Допустимо установить указатель const на другое значение, и тот факт, что это значение равно NULL, не имеет значения, поскольку предыдущее значение больше не доступно.

0 голосов
/ 07 марта 2018

Если вы посмотрите на сигнатуру свободной функции, free всегда принимает void * ptr в качестве аргумента, поэтому вам нужно привести его к соответствующему типу, т.е. free ((void *) str); free не позволяет напрямую освобождать указатели констант, поэтому вам нужно привести их к неконстантному типу

0 голосов
/ 23 августа 2013

Если вы говорите о чистом C и полностью контролируете распределение памяти, вы можете использовать следующий трюк для приведения (const char *) к (char *), который не выдаст вам никакого предупреждения в компиляторе:

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;

Теперь вы можете использовать бесплатно (ул); освободить память.

Но ПОМНИТЕ, что это зло за пределами слов и должно использоваться только в строго контролируемой среде (например, библиотека, которая выделяет и освобождает строки, но не хочет позволять пользователю изменять их). В противном случае у вас закончится сбой программы когда кто-то предоставляет время компиляции "STRING" для вашей бесплатной функции.

...