90

How can I free a const char*? I allocated new memory using malloc, and when I'm trying to free it I always receive the error "incompatible pointer type"

The code that causes this is something like:

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

free(str); // error here
Brian
  • 14,610
  • 7
  • 35
  • 43
lego69
  • 1,403
  • 3
  • 12
  • 15
  • Is there a particular reason you need to do it this way? Usually, string constants are you know of ahead of time, so to be dynamically allocating space for a string constant seems strange. – James Kingsbery May 12 '10 at 14:20
  • yes the problem is that it's my homework we are studying ADT, so I'm limited – lego69 May 12 '10 at 14:23
  • 6
    Basically a C language problem. The signature of free() should have been `void free(const void* p);`. Fixed in C++ (with `delete`) – MSalters May 12 '10 at 14:26
  • What ADT are you studying that requires a dynamically instantiated constant? – James Kingsbery May 12 '10 at 14:53
  • 9
    @James Kingsbery: interned strings, maybe: once you've populated your char buffer initially, it makes sense to treat it thereafter as a `const char*`. Do questioners really need our permission to have problems? ;-) – Steve Jessop May 12 '10 at 15:16
  • 7
    However, it makes no sense whatsoever. Once the memory is allocated to `str`, it's impossible to change it through `str`, which means that it is permanently whatever was in the memory when `malloc()` grabbed it. It isn't possible to copy the name in without casting `str`. (Also, assigning a string literal to a `char *` is not good, as trying to modify a string literal is undefined behavior. I think you just got your `const`s mixed up.) – David Thornley May 12 '10 at 15:32
  • @Steve Jessop - I was just trying to understand what problem lego69 was trying to solve. – James Kingsbery May 12 '10 at 16:48
  • 4
    @DavidThornley: The `const char *` you get may have been converted from `char *` after the contents are filled; e.g. from `const char* foo() { char* s = malloc(...); strcpy(s, ...); return s; }`. – musiphil Mar 07 '14 at 01:06
  • *Unable to free const pointers in C*: Where is `const` pointer in the given snippet? – haccks Aug 31 '16 at 14:29

12 Answers12

114

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);
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • 29
    It will work, but casting `const` to non-const is a symptom of code smell. – el.pescado - нет войне May 12 '10 at 14:17
  • 3
    @el. `free()` is something of an exception, because you may not want the pointer to be modified during its lifetime, but you still want to free it at the end – Michael Mrozek May 12 '10 at 14:20
  • 16
    Why the cast to char * ? why not directly free((void *) str) ? – philant May 12 '10 at 14:30
  • 2
    @philippe Either works, I just figured I'd illustrate that the problem isn't passing free a char* instead of a void* (which was one of the answers, although I think it's deleted now), it's passing a const char* instead of a non-const char*/void* – Michael Mrozek May 12 '10 at 14:45
  • 3
    @el. Sure, but that seems rather unnecessary. I'm not going to keep two pointers to the same place around, one const and one not, just so I can free the non-const one at the end without using an evil cast – Michael Mrozek May 12 '10 at 14:49
  • You should still get a warning for casting away const-ness, so I'm not sure that this is any better a solution than just passing the pointer to const as it is. – Paul R May 12 '10 at 15:45
  • 60
    I recall reading about a memory deallocation function in the linux kernel that took a const pointer, and someone asked Linus why, and he defended it as saying it doesn't actually modify the value pointed to, either conceptually or in practice, it merely looks up the memory block using the pointer and deallocates it. I concur with his assessment, and thus view the free() function's specification as incorrect. But alas, it is the standard. – rmeador May 12 '10 at 15:48
  • 1
    It's not the right answer. The whole point of const char* is that what is being pointed to cannot be changed. That includes freeing. – JeremyP May 12 '10 at 15:50
  • 1
    @Paul: Why should you? if this happens implicitly, sure, but the compiler shouldn't interfere with the programmer's (probably legitimate) explicit cast. – Hasturkun May 12 '10 at 16:25
  • 2
    I agree with @Hasturkun, you don't get warnings for casting; casting is specifically to say "trust me, I want the value as this type, and I don't want to argue about it" – Michael Mrozek May 12 '10 at 16:56
  • 2
    @JeremyP I don't think "freeing is a form of changing" is as uncontested as you think; see rmeador's comment, for example – Michael Mrozek May 12 '10 at 16:58
  • 20
    If "freeing" was conceptually changing, then is it OK to declare a `const int` and then leave the scope in which it was declared? That "frees" the automatic variable, in the sense of releasing the resource and making pointers to it no longer valid. It's just a quirk that `free` takes non-const, it's not a commandment from on high. In the rare case that there's only one thing you do with your pointer that's non-const, and that's free it, then pragmatically you probably get more benefit from a const pointer (which you cast to free) than a non-const pointer (which you might accidentally modify). – Steve Jessop May 12 '10 at 19:31
  • 1
    This does not fix the fact that the OP reversed their storage types. – Tim Post May 13 '10 at 06:15
  • 2
    @rmeador Answering 8+ years later, but Linus has been known to be very wrong about the C language in other cases as well. Argument from false authority. – Antti Haapala -- Слава Україні Oct 26 '18 at 10:54
  • 1
    @ MichaelMrozek do you mind putting the reasoning from @SteveJessop's comment to your answer? I think your solution lacks an explanation of "why it's correct to do", and Steve's comment is very on point here. – Hi-Angel Oct 25 '22 at 10:26
29

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.

Community
  • 1
  • 1
Tim Post
  • 33,371
  • 15
  • 110
  • 174
  • 8
    The OP asked how to free a pointer to a const qualified type- the attached code sample reflects his question, where your interpretation contradicts it. As an aside, the const qualifier on the pointed-to type doesn't affect or express any intention as to what will be done to/with an allocated object itself, it only affects what will be done via this pointer. Once/if you discard the pointed-to const qualifier you may modify the allocated object. – Dror K. Mar 03 '17 at 22:38
  • 1
    @DrorK. nevertheless, this is the most useful answer, at least for me, as I have made the same mistake as the OP. Most people encountering this problem are likely similarly confused, so I posit that this is actually the best answer. – Michael Dorst Apr 12 '20 at 21:04
  • 1
    I agree with Michael Dorst that this is the best answer. Being so strictly literal with StackOverflow conventions that you tell someone how to "program wrong better" serves no purpose (See comments on other answers and Puppy's answer). However, using "free" would make this answer complete. – Poikilos Jun 29 '23 at 12:36
6

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 ?

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 16
    Here is one case where you might like to free a pointer-to-const: `char const* s = strdup("hello"); free(s);`. – bobbogo Jul 19 '12 at 09:44
  • 2
    @bobbogo: yes, although it's hard to imagine why you'd want to make a const copy of a string literal in the first place. – Paul R Jul 19 '12 at 10:46
  • 12
    You may wish to take a copy of a string which is about to be freed() or otherwise changed by library code. You are not going to modify your copy, so you mark it const. – bobbogo Aug 27 '12 at 11:44
4

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;
}
nlstd
  • 41
  • 2
3

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.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • What about code like `struct foo { const char *bar; ... }`? This expresses the fact that the memory pointed to by `foo->bar` should be treated as immutable (whereas other members of `struct foo` may be variable). This is useful for ensuring correctness of a program. Still `bar` may need to be malloc'd when the object is first initialized. If you want to free such an object, you need a way to free `bar`, too. – uncleremus Oct 27 '20 at 09:12
  • @uncleremus This is a matter of from whose perspective you're operating. The memory pointed to by foo->bar should be treated as immutable by the recipient. The memory pointed to by foo->bar should not be treated as immutable by whoever owns it, because they need to deallocate that memory, which definitely constitutes a mutation. So you need to show other people an immutable interface whilst retaining a mutable version for yourself. – Puppy Oct 28 '20 at 10:27
  • Are you suggesting using a union? `struct foo { union { const char *bar; char *__bar; }; }` would work, I guess. – uncleremus Oct 29 '20 at 13:19
  • @uncleremus I'm suggesting that you should have two completely different structs, one for internal use and one for external use. – Puppy Oct 30 '20 at 14:33
  • Even the "owner" code may need to modify the `bar` element only in one single place (the destructor), whereas it might pass around `foo` objects a lot and possibly modify other members. Even in the code owning the struct, protecting `bar` against mistaken modification with `const` is desirable. The `const` just needs to be cast away in the destructor. – uncleremus Jan 15 '21 at 13:34
2

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.

uncleremus
  • 317
  • 1
  • 11
1

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.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 4
    `free` doesn't change the pointer. It frees the memory block the pointer is pointing to. This is a mistake in the language specification. `free` should clearly take a const pointer. – Axel Gneiting May 12 '10 at 14:45
  • 6
    @Axel `const` means that you cannot change the contents of the storage object, not the actual value of the pointer... and freeing the pointed memory is a quite dramatic change I'd say! (BTW It seems a little bit pretentious to think that the specification is wrong [and has been wrong for more than 30 years] and suddenly you discover that you're right and all the review board members weren't, isn't it?) – fortran May 12 '10 at 14:56
  • 10
    @fortran: it's not at all pretentious, it's a common difference of opinion. `delete` in C++ can be used on a `const char*`, so if it's a big controversy then one or the other set of standard authors must be wrong. Actually I don't think it really matters - casting away const to free a pointer is hardly a crisis. – Steve Jessop May 12 '10 at 15:31
  • 3
    const char* says that what is being pointed to is a constant and cannot be changed. It is *not* saying that the pointer itself cannot be changed. – JeremyP May 12 '10 at 15:55
  • 1
    Free does not change pointer. It does not change value pointed to directly, *but* it may be returned by subsequent calls to malloc and used by other portions of code, so I think free changes what its argument points to, at least indirectly. – el.pescado - нет войне May 12 '10 at 17:17
  • 4
    @Axel Gneiting: I never said that the pointer is changed. `const` indicates that the *data* at this location should not be changed. But if you free the memory, the data at this location can be overwritten and therefore changed. – Felix Kling May 12 '10 at 18:41
  • But free() actually changes the pointer. It becomes invalid, and using it in any way (even reading its value) is then undefined behaviour. Annex J.2: "The behavior is undefined in the following circumstances: [...] The value of a pointer to an object whose lifetime has ended is used (6.2.4)." – Secure May 13 '10 at 08:37
  • It is not pretentious. The standard is old. People did not think about so much back then. And it cannot be changed, no matter if we decide it is wrong. – Jay K May 25 '21 at 06:32
1

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.

user12205
  • 2,684
  • 1
  • 20
  • 40
free
  • 11
  • 1
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.

MMasterSK
  • 17
  • 1
  • 2
    Why on Earth would you use this ugly hack with a pointless `union` when a plain cast can alter `const`ness just fine on its own? – underscore_d May 24 '17 at 10:09
  • I have not tested it, but this answer is fully C-standards compliant and will never trigger warnings from the compiler, not even gcc's -Wcast-qual. And it will work even on pointer-provenance hardware like CHERRI, which I am not so sure about if you do pointer--pointer conversions: depends on the optimizer noticing it is a NOP *always* and not screwing up the provenance metadata kept by the processor. – anonymous Aug 03 '23 at 12:58
  • Lost the edit window. I just tested it on gcc 12.2, and this answer is actually the better one for the reasons I pointed out in my previous comment. It avoids all warnings, even -Wcast-qual, and it has zero chance of screwing up with pointer provenance since it does not attempt to cast an integer to a pointer. The alternative is to #pragma away the stricter warnings, I suppose... – anonymous Aug 03 '23 at 13:06
-1

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

rstalekar
  • 309
  • 1
  • 2
  • 7
-2

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 !!

-3

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);
  • 6
    In C++, you can `delete` a `const char*`. And why shouldn't you? The fact that the pointer prevents the characters from being modified shouldn't disallow to delete the string once it isn't needed anymore. I don't know C well enough, though. Anyone with a quote from the std here? – sbi May 12 '10 at 14:19
  • 3
    -1, the constness of a pointer doesn't affect your ability to `free` it in any way. – Hasturkun May 12 '10 at 14:24
  • 1
    `void free(void *ptr);` - you cannot pass const pointer to it. Unless, you cast it to non-const. – el.pescado - нет войне May 12 '10 at 14:27
  • @el.pecado: `gcc -Wall` just gives a warning when you pass a pointer to const to `free()` - what compiler are you using that does not allow this ? – Paul R May 12 '10 at 14:34
  • 2
    @Paul "just gives a warning"? It's not like warnings don't matter or something. Personally I think it should be an error, passing a const to something that takes a non-const is not ok; in C++ they did upgrade it – Michael Mrozek May 12 '10 at 14:51
  • @Michael: I agree that, in general, warnings should always be fixed, but there is a big different between a warning and saying that you "cannot" do something. – Paul R May 12 '10 at 14:57
  • @Paul R: Warnings are usually signals that the compiler thinks it knows how to proceed, but thinks you might have made a mistake or are doing something nonstandard. In this case, it's nonstandard, which means that you cannot do something in a conforming way. At this point, you seem to be using a compiler extension. – David Thornley May 12 '10 at 15:24
  • @Paul True, I was looking at Hasturkun's "the constness of a pointer doesn't affect your ability to free it in any way" and wrongly assuming you were saying the same – Michael Mrozek May 12 '10 at 15:33
  • 1
    Hastturkun is wrong. `const char *` means that what the pointer is pointing to is constant, not that the pointer itself is constant. It is wrong to try to free a `const char *`. Consider `const char* foo = "bar"; free((void*) foo);` What is going to happen? – JeremyP May 12 '10 at 15:59
  • 2
    @JeremyP: The answer is Undefined Behavior (or possibly nasal demons), but that's not caused by the `const` so much as by trying to free a string constant. – Hasturkun May 12 '10 at 16:29
  • 2
    @JeremyP That example is specious; it's wrong, but not because the string is const, it's just a special case of string literals – Michael Mrozek May 12 '10 at 17:02
  • It's not *caused* by the `const` but the `const` ells the compiler something about what it is allowed to do to the string or not. If you see a function declaration `void foo(const char* bar)` that is a contract between the caller of foo and foo that says "foo will not change the char that bar points to. If foo passes bar to free, then foo is breaking the contract. You should never free a const char*. – JeremyP May 13 '10 at 07:46
  • In my example, at run time you are likely to get some sort of memory protection error that terminates your program. Had I left out the cast to void* I would have got a compile time warning to show that I have done something wrong. The example is trivial, but imagine a few thousand lines between the definition and the call to free or the pointeer being passed to another function that frees whatever is passed to it. – JeremyP May 13 '10 at 07:48
  • 2
    @JeremyP: "You should never free a `const char*`." I disagree. If that was true, you should never have `const` strings that are dynamically allocated, because you couldn't delete them. And that's just stupid. Whether something is allocated dynamically and whether it should not be altered are orthogonal questions. I can have dynamically allocated strings which I don't want to have altered, but which have to be freed at some point. I consider this a bug in the C std lib, probably stemming from the fact that C adopted `const` from C++ only later and it's now somewhat like a red-haired step child. – sbi May 14 '10 at 16:08
  • const-ness isn't some absolute statement about the memory. It is a possibly varying interface presented to the memory. It is writable by the creator, and maybe even "friend" functions, but then read only to clients. strdup is a simplification of this. Example in next comment. – Jay K May 25 '21 at 06:33
  • const T* CreateState() { T* p = (T*)malloc(sizeof(T)); ... fill in p ... return p; } void SomethingState(const T* p) { ... } void FreeState(const T* p) { free((T*)p); } Consider that in C++, some type might have a mix of const and not-const functions. Const, again, is not a statement about readonly-ness of memory (sometimes it is), it is a statement of intended "permission" any one client might have to the state. – Jay K May 25 '21 at 06:43