it-swarm.com.ru

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

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

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

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

free(str); // error here
58
lego69

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

free((char*)str);
74
Michael Mrozek

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

Это:

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

23
Tim Post

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

Впрочем, 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
$ 

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

6
Paul R

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

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

3
Puppy

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

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

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

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

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

1
uncleremus

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

free((char *) p);

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

1
Felix Kling

Если вы говорите о чистом 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" для вашей свободной функции.

0
MMasterSK

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

free(p);
p = NULL;

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

0
free

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

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