无法释放 C 中的常量指针

如何释放 const char*?我使用 malloc分配新的内存,当我试图释放它时,我总是收到“不兼容指针类型”错误

导致这种情况的代码类似于:

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


free(str); // error here
61414 次浏览

You cannot free const char * because it is const. Store pointers received from malloc in non-const pointer variables, so that you can pass them to free. You can pass char * arguments to functions taking const char * arguments but opposite is not always true.

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

I could be wrong but I think the problem lies in const. Cast the pointer to non-const like:

free((char *) p);

Because with const you say: Don't change the data this pointer points to.

Several people have posted the right answer, but they keep deleting it for some reason. You need to cast it to a non-const pointer; free takes a void*, not a const void*:

free((char*)str);

It makes no sense to malloc a pointer to const, since you will not be able to modify its contents (without ugly hacks).

FWIW though, gcc just gives a warning for the following:

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

What compiler are you using ?

I think even if you cast the pointer to a non-const, the result of free will depends on the implementation. Normally const was designed for variable that you don't want to modify !!

There's no purpose in casting a malloc'd pointer to const. Any function that takes a const pointer should not be responsible for freeing the memory that was passed to it.

Your code is reversed.

This:

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

Should look like this:

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

The const storage type tells the compiler that you do not intend to modify a block of memory once allocated (dynamically, or statically). Freeing memory is modifying it. Note, you don't need to cast the return value of malloc(), but that's just an aside.

There is little use in dynamically allocating memory (which you are doing, based on the length of name) and telling the compiler you have no intention of using it. Note, using meaning writing something to it and then (optionally) freeing it later.

Casting to a different storage type does not fix the fact that you reversed the storage types to begin with :) It just makes a warning go away, which was trying to tell you something.

If the code is reversed (as it should be), free() will work as expected since you can actually modify the memory that you allocated.

There are cases you want to free a const*. However you don't want to do it unless you allocate/asign it in the same function. Else you are likely to break things. See the code below for a real world example. I use const in the function declarations to show that I am not changing the content of the arguments. However it is reassigned with a lowercased duplicate (strdup) that needs to be freed.

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;
}

If you are talking about pure C and you are in complete control of the memory allocation you can use the following trick to cast (const char *) to (char *) which will not give you any warning in compiler:

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;

Now you can use free(str); to free the memory.

But BEWARE that this is evil beyond words and should be only used in strictly controlled environment (e.g. library which allocates and frees strings, but doesn't want to allow user to modify them) Otherwise you will end up with your program crashing when someone provides compile time "STRING" to your free function.

Several answers have suggested simply casting to char*. But as el.pescado wrote above,

casting const to non-const is a symptom of code smell.

There are compiler warnings that guard against this, such as -Wcast-qual in gcc, which I find very useful. If you really have a valid case for freeing a const pointer (contrary to what many have written here, there are valid cases, as pointed out by nlstd), you could define a macro for that purpose like this:

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

This works at least for gcc. The double cast makes the logic -Wcast-qual not detect this as "casting const away". Needless to say, this macro should be used with care. Actually it should only be used for pointers allocated in the same function.

If you take a look at the signature of free function , free always takes void* ptr as an argument therefore you need to cast it to the appropriate type i.e. free((void *)str); free does not allow const pointers to be deallocated directly therefore you need to cast it to non const type

I think the real answer is that free should take a const pointer argument and NULL should be defined as a const pointer. This seems to be a bug in the standards. Freeing a const pointer should be implemented as follows:

free(p);
p = NULL;

I don't see how a compiler could generate incorrect code in this case, the const pointer p is no longer accessible, so it doesn't matter if the object it pointed to is const, valid, whatever else. Its const so there can't be any dirty copies in registers or anywhere else. It is valid to set a const pointer to another value, and the fact that that value is NULL doesn't matter because the previous value is no longer accessible.