Невозможно освободить константные указатели в C

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

Код, вызывающий это, выглядит примерно так:

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

free(str); // error here

Ответ 1

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

free((char*)str);

Ответ 2

Ваш код отменен.

Это:

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() будет работать так, как ожидалось, так как вы действительно можете изменить выделенную память.

Ответ 3

Нет смысла переводить указатель на 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

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

Ответ 5

Есть случаи, когда вы хотите освободить 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;
}

Ответ 6

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

free((char *) p);

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

Ответ 7

Вы не можете освободить const char *, потому что это const. Указатели хранилища, полученные от malloc в переменных, не являющихся константными, так что вы можете передать их в free. Вы можете передать аргументы char * для функций, принимающих аргументы const char *, но противоположное не всегда верно.

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

Ответ 8

Если вы говорите о чистом 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;

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

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

Ответ 9

Я думаю, что даже если вы укажете указатель на неконстантный, результат свободной воли будет зависеть от реализации. Обычно const был предназначен для переменной, которую вы не хотите изменять!