Reputation: 47
Consider the following code:
#include<stdio.h>
int main()
{
const char* c = malloc(1);
*c = 'a';
printf("%c\n",*c);
}
This code obviously throws the following compile error:
file1.c:7:3: error: assignment of read-only location ‘*c’
*c = 'a';
^
How do I initialize a const variable in heap memory?
Upvotes: 1
Views: 412
Reputation: 31389
There is no such thing as a read only location in the heap. See Steve Summits answer for a good explanation.
Whatever you do to achieve this, it will still be up to you to make sure that you don't write in those locations. You can protect yourself pretty well, but not 100%.
You could do something like this:
char * x = malloc(1);
*x = 'a';
const char * c = x;
// Promise to not use the pointer x again
printf("%c\n",*c);
Or if you prefer to encapsulate it a little bit:
const char * init()
{
char* c = malloc(1);
if(c == NULL) { // Always check if allocation is successful
// Code for error handling
}
*c = 'a';
return c;
}
int main()
{
const char * p = init();
printf("%c\n",*p);
}
Note that it is still allowed to write char * p = init()
without const
and this will indeed make it possible to write *p = 'a'
, but you will at least trigger this warning:
warning: initialization discards ‘const’ qualifier from pointer target
type [-Wdiscarded-qualifiers]
char * p = init();
Another thing to be aware of here is that you will get a warning if you call free(p)
, because p
is a const
pointer. If you declare p
as just a char *
you will get rid of this warning, but you will instead get the warning I mentioned in the previous paragraph. (And, of course you will also lose all write protection you were trying to get by declaring it as a const)
To get around this, you can free the memory with free((char*)p)
As a side note, if you want to make sure that you never change where p
is pointing, then you can declare it like this const char * const p = init()
. That will make it impossible to make p
point to something else later in the code.
Upvotes: 1
Reputation: 47952
First of all, understand that there is no such thing as "read only locations in the heap". The heap is 100% writable. malloc()
is defined as returning void *
. You are allowed to write to the data pointed to by the pointers which malloc
returns.
But then the second thing to understand is that const
doesn't necessarily mean "read only", either.
There is such a thing as read-only memory, and it will often be pointed to by const
pointers, and if (despite any const
pointer) you do manage to try to write to read-only memory, you will typically get an exception of some kind.
But you can have read-only memory that's pointed to by a non-const
pointer, and you can have a const
pointer that points to writable memory.
So what const
really means is "I promise not to write to this memory" or "I declare my intent not to write to this memory", with the added stipulation that "I would like the compiler to give me compile-time errors if I accidentally try to write to this memory."
If you have an ordinary const
pointer, you can initialize it, once. You can say things like
const str1[] = "hello";
and
const *str2 = "world";
even though later attempts to update the strings like
*str1 = 'x'; /* WRONG */
or
*str2 = 'y'; /* WRONG */
would fail. (You can think of this as the "initialization exception" for const
-qualified data.
But as you've discovered, there's no such exception for a const
pointer which you initialize by calling malloc
. If you want to get some memory from malloc
, and initialize it once, and then promise not to modify it later, and if you want to get the compiler to enforce this promise for you, you can't do it directly, unless you use the two-pointer workaround described in the comments and in klutt's answer.
Upvotes: 5