TARS
TARS

Reputation: 47

How to initialize read only memory locations in heap in C?

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

Answers (2)

klutt
klutt

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

Steve Summit
Steve Summit

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

Related Questions