Search code examples
c++pointersconstants

const pointer and pointer to const value as parameter


I have a program like below and expect that:

  1. with function void myFunc1 ( const int *x) ==> I cannot change the value of at the memory location that x points to, but can change the memory location that x points to.

  2. with function void myFunc2 ( int const *x) ==> I cannot change the location that x points to as it is a const pointer. But I could change the value at the memory location that x points to.

However, upon compiling the code, I don't see the difference between const int *x vs int const *x:

  1. in both function, the lines *x=8 in both function return error. I didn't expect error from myFunc2 because it is a const pointer, not a pointer to a const value.
  2. in myFunc1, I expected to see value 5 after myFunc1 is close.

Could the experts here explain my 2 unexpected results above ? Here is my code:

#include "stdio.h"

int a = 5;                      // declared a global,

void myFunc1 ( const int *x) {  // const parameter: pointer to a const int value.
    // *x= 8;                   // error: assignment of read-only location ‘* x’ ==> cannot change the value at the location pointed by pointer. This is expected
    printf("%d \n ", *x);       
    x = &a;                     // can change where the pointer point to. 
                                // a is global and is not loss after closing myFunc2
    printf("value in myFunc1: %d \n ", *x);                           
}


void myFunc2 ( int const *x) {   // const parameter: const pointer, cannot change the address that x points to. 
    //  *x= 8;                  // error: assignment of read-only location ‘* x’ 
    printf("%d \n ", *x);       
    x = &a;                     // no compiling error here. This is not expected.
                                
    printf("value in myFunc2: %d \n ", *x);                           
}

int main() {
    int *y;
    int z = 6;
    y = &z;
    printf("value before myFunc1: %d \n", *y);     
    myFunc1(y);
    printf("value after  myFunc1: %d \n", *y);        // expect to print 5. Result: print 6.
    
    printf("value before myFunc2: %d \n", *y);     
    myFunc2(y);
    printf("value after  myFunc2: %d \n", *y);        // expect to print 8 if the line *x=8 could be compiled . Result: print 6.
    return 1;
}

Solution

  • I don't see the different between having 2 parameters (const int *x) vs (int const *x):

    That's because int const* and const int* are the same thing.

    If you want to make the pointer const, you have to put a const on its right, like this: int * const, a constant pointer to (non-constant) integer.


    Unrelated (is it?) note on East const

    I am one of those in favour of the so called East const, which means I prefer writing the const always on the right of what it applies to. For instance,

    • for a "pointer to constant int", I write int const *,
    • for a "constant pointer to constant int", I write int const * const.

    As you see, the sentences in quotes map to the types if you read them right-to-left:

    //  1    2   3   4             4       3           2     1
       int const * const    // constant pointer to constant int
    

    Furthermore, always thinking of const as something that can be put on the right of what it applies to has also other advantages, sometimes in terms of peculiarities of the language that you can discover.

    For instance, the following is how I discovered something more about references.

    Take the declaration of a function parameter taken by reference to constant: int const& p. If you write it like this and think of it the East const way, it is clear that it declaring a p which is a reference to a constant int, not a constant reference to int.

    After all, thinking East const, what would a constant reference to int look like? It'd be int & const, with the const on the right of what we'd like it to apply to, the reference &. However, this syntax is incorrect.

    Why is that? Why can't I make a reference constant? Because it always is, as references cannot rebind. The standard simply doesn't let you write something totally redundant as a const applied to a reference.