4

In c++, we know that we can't convert const int* into int*. But I have a code snippet where I am able to convert const int* into int*. I am a beginner in c++, i googled for this but i just got the links mentioning const int* can't be converted into int* to avoid const violation. I am not able to figure out why is it compiling without errors

#include <iostream>
using namespace std;

int main(void)
{
    const int a1 = 40;
    const int* b1 = &a1;
    int* c1 = (int *)(b1);
    *c1 = 43;
    cout<< c1<<" "<< &a1<<endl;
    cout<< *c1<<" "<< a1<<endl;
 }

Also, the problem is the output of the above program is:

0x7fff5476db8c 0x7fff5476db8c
43 40

Can someone please explain c1 integer pointer is pointing to the same address for a1 but having different values 43 and 40 respectively.

Raktim Biswas
  • 4,011
  • 5
  • 27
  • 32
Mukesh
  • 283
  • 3
  • 11

4 Answers4

6

In C++, an object is const or it isn't. If it is const than any attempt to modify it will invoke undefined behaviour. That's what you did. At that point anything can happen. If you're lucky, it crashes. If you're less lucky, it works fine until your code is in the hand of a customer where it causes the greatest possible damage.

You can easily convert a const int* to an int* in C++. You just did. However, "const int*" and "int*" don't mean that the thing pointed to is const or not. It just means that the compiler won't let you assign in one case, and will let you assign in the other case. *c1 is const. Casting the pointer to int* doesn't change the fact that it is const. Undefined behaviour.

melpomene
  • 84,125
  • 8
  • 85
  • 148
gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • I din't understand "You can easily convert a const int* to an int*". How? If I execute this code const int a =40; int *b = &a1; It returns error: cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'. Also can you please explain how the output is different 40 and 43. – Mukesh Jun 25 '16 at 09:18
  • I got the reason for different outputs from other answers. – Mukesh Jun 25 '16 at 09:22
2

It's undefined behaviour.

But, in this case what's happened is that the compiler has realised that it can replace a1 in cout statement with the actual value 40, because it's meant to be const.

Never, ever rely on this though. It could just have easily tattoed your cat.

Roddy
  • 66,617
  • 42
  • 165
  • 277
1

A const int variable will occupy memory in stack, but compiler will simply replace all instance of a1 with 40. The expression &a1 will not be replaced, and how somehow magically point to the memory on stack. When you change the contents, the content at memory will get changed, but those constants 40 will not change. Hence they differ in output.

This is nothing but undefined behaviour and may vary from compiler. One compiler may cause 43 to be displayed, another may always display 40 and some other may generate code to cause crash (writing to read-only memory). Don't do it!

Ajay
  • 18,086
  • 12
  • 59
  • 105
  • 1
    There's no reason why a `const` should be on the stack. Compilers for micros with read only memory may legally place it there. e.g. arm, avr. – Andy Brown Jun 25 '16 at 09:02
  • Yes, there is no reason. But it does. Try passing address of const to a function by non-const reference or non-const pointer. The called function will be able to change and enjoy this. If it doesn't work, it won't work in all cases. – Ajay Jun 25 '16 at 09:04
  • @AndyBrown http://ideone.com/5MfBxP – Ajay Jun 25 '16 at 09:06
0

Run this, maybe it helps.

const int a1 = 40;
std::cout<<"__________ const int a1 = 40; ____________________________________"<<std::endl;
std::cout<<"a1: "<< a1<<std::endl;
std::cout <<"&a1 "<< &a1<<std::endl;
std::cout <<"*a1: INVALID"<<std::endl;

const int* b1 = &a1;
std::cout<<"__________ const int* b1 = &a1; ____________________________________"<<std::endl;
std::cout<<"b1: "<< b1<<std::endl;
std::cout <<"&b1 "<< &b1<<std::endl;
std::cout <<"*b1 "<< *b1<<std::endl;

int* c1 = (int *)(b1);
std::cout<<"__________ int* c1 = (int *)(b1); ____________________________________"<<std::endl;
std::cout<<"c1: "<< c1<<std::endl;
std::cout <<"&c1 "<< &c1<<std::endl;
std::cout <<"*c1 "<< *c1<<std::endl;

*c1 = 43;
std::cout<<"__________ *c1 = 43; ____________________________________"<<std::endl;
std::cout<<"c1: "<< c1<<std::endl;
std::cout <<"&c1 "<< &c1<<std::endl;
std::cout <<"*c1 "<< *c1<<std::endl;

std::cout<<"c1: "<< c1<<std::endl;
std::cout<<"*c1: "<< *c1<<" -----> *&a1: "<< *&a1<<" - a1: "<< a1<<std::endl;
std::cout<<"&c1: "<< &c1<<std::endl;
iGian
  • 11,023
  • 3
  • 21
  • 36
  • The ouput is (only after *c1=43): __________ *c1 = 43; ____________________________________ c1: 0x7fff52857a7c &c1 0x7fff52857a68 *c1 43 c1: 0x7fff52857a7c *c1: 43 -----> *&a1: 43 - a1: 40 &c1: 0x7fff52857a68 This suggests the compiler is replacing all instance of a1. But why is it allowing to edit a const variable. – Mukesh Jun 25 '16 at 09:37
  • But the value of a1 is still 40, but somewhere in the memory there is also the value 43. In my run, before assign *c1=43: `| name | value | address` `| a1 | 40| ff240` `| b1 | ff240| ff238` `| c1 | ff240| ff230` After *c1=43 the table does not change in my output. So how can *c1 be equal to 43 if c1 still contains the address of a1? – iGian Jul 02 '16 at 09:45