cgccmalloclinux-mint

How do compilers treat CONST qualifier when the pointer points to a memory location obtained with malloc()?


I really do not know how to put a better title so please be patient with me and have mercy.

What I know.

When I do something like this:

#include <stdio.h>

int main ( void ){
    const char *arr = "Hello";

    arr[0] = 'B';
    printf( "Arr = %s\n", arr );
}

I won't get a segfault because applying that const qualifier I made a promise to the compiler that I am not going to touch that value where arr points to.

At least on my system ( Linux mint 18.3 with GCC 7.2.0) I get:

program.c:6:16: error: assignment of read-only location ‘*arr’
         arr[0] = 'B';
                ^

NEXT

When I do:

const char *const arr = "Hello";

Like in the following program:

#include <stdio.h>

int main ( void ){
    const char *const arr = "Hello";

    while ( *arr != '\0' ){
        arr++;
    }
    printf( "Arr = %s\n", arr );
}

The compiler also knows that I promise to not increment the pointer and it see it:

program.c:7:16: error: increment of read-only variable ‘arr’
             arr++;
                ^~

What I do not Understand.

How exactly do compilers treat a situation like this one:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( void ){
    const char *const arr = calloc( 256 * sizeof( *arr ), sizeof( *arr ) );

    strcpy ( (char*)arr , "Hello" );
    printf( "Arr = %s\n", arr );

    free ( (char*)arr );
}

Here I am forced to cast arr when I call strcpy() and same for free().
But why the compiler does not see (ignores) the fact that even if I made a "promise" that I will not try to modify that variable it ignores the const qualifier?

Moreover, when I do the following:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( void ){
    const char *const arr;

    while ( *arr != '\0' ){
        arr++;
    }

    free ( (char*)arr );
}

The compiler sees that I am trying to increment the pointer:

program.c:9:16: error: increment of read-only variable ‘arr’
             arr++;
                ^~

But ignores the fact that I made a promise that I will not modify the value.

Does the fact that the malloc is involved here have a meaning somehow to the compiler that it needs to ignore all those const qualifiers`? ...
Or am I missing something important here?


Solution

  • You are allowed to remove const from a pointer if it was not const originally.

    calloc returns a void *. When you assign it to a const char *, you add const. But the rules of C allow you to add const temporarily and remove it later. You might want to do this, for example, when some routines create data, then give the data to some other routines that should only read the data, but, later, the pointer is passed back to be freed or further changed, in which case const must be removed.

    In short, const is a convenience for software that wants to obey the rules. It asks the compiler to notify you when you accidentally try to write with a const pointer. It does necessarily stop you from deliberately breaking the rules by removing const inappropriately.

    (To be more precise about the opening sentence: C is very flexible about pointer conversions. You can largely convert different types of pointers, as long as alignment requirements are met. It is actually using pointers to access memory that runs into trouble when done incorrectly.)