Questions
const int a;
int const a;
const int *a;
int *const a;
int const *a const;
What does them means?
Analysis
Firstly, we should know that the order in which the declaration specifiers appear in declaration does not matter. So for the first two declaration:
const int a;
int const a;
They are equivalent. They both means that a is a constant integer, whose value can not be changed.
However, since pointer declarations read from right-to-left, and T const and volatile are the only declaration specifiers that can also appear in declarators. So for these two declarations,
const int *a;
int const *a;
they are equivalent, they both means a is pointer to constant integer. The value it points can not be modified, but its own value can be changed, it can points to another constant integer as we like.
In the contrast, for the next line
int *const a;
we can know it means that a is constant pointer to an integer. Its value can not change, but we can change the value of integer it points.
When it comes to
int const *a const;
Both the pointer and the value to which it points are constant.
Test
It can be tested whether a is avaliable for change, let's try to see what will happen in the following code.
#include<iostream>
using namespace std;
int main(){
int i = 5;
int a = 10;
const int ci=15;
int const ic = 20;
const int *cip = &ci;
int const *icp = ⁣
int *const ipc = &i;
int const* icpc const = &ci;
cout <<"int i: < "<< &i << " > "<< i <<endl;
cout <<"const int ci: < "<< &ci << " > "<< ci <<endl;
cout <<"int const ic: < "<< &ic << " > "<< ic<< endl;
cout <<"const int *cip = &ci; so cip: < "<< cip << " > "<< *cip <<endl;
cout <<"int const *icp = ⁣ so icp: < "<< icp << " > "<< *icp<< endl;
cout <<"int *const ipc = &i; so ipc: < "<< ipc << " > "<< *ipc<< endl;
cout <<"int const* icpc const = &ci; so icpc: < "<< icpc << " > "<< *icpc<< endl;
cout <<"icpc: < "<<icpc << " > "<< *icpc<< endl;
ci = i;// not avaliable
ic = i;// not avaliable
ipc = ⁣// not avaliable
ipc = &a;// not avaliable
cip = &i;
icp = &i;
ipc = ⁣//not avaliable
icpc = ⁣
cout <<"After operation cip = &i; cip: < "<< cip << " > "<< *cip <<endl;
cout <<"After operation icp = &i; icp: < "<< icp << " > "<< *icp<< endl;
cout <<"The value of icp and cip is changable, ipc can not be modified."<< endl;
*cip = ci;// not avaliable
*icp = ci;// not avaliable
i = ci;
*ipc = ci;
*icpc = ic;
cout <<"After *ipc = ci; ipc < "<< ipc << " > "<< *ipc <<endl;
cout <<"After i=ci; cip: < "<< cip << " > "<< *cip <<endl;
cout <<"After i=ci; icp: < "<< icp << " > "<< *icp <<endl;
cout <<"The integer that icp, cip and ipc point to can be changed, but *cip and *icp can not be modified directly!"<< endl;
return 0;
}
After compilation, we can see these errors:
test.cpp: In function 'int main()':
test.cpp:11:18: error: expected initializer before 'const'
test.cpp:19:55: error: 'icpc' was not declared in this scope
test.cpp:21:7: error: assignment of read-only variable 'ci'
test.cpp:22:7: error: assignment of read-only variable 'ic'
test.cpp:23:9: error: assignment of read-only variable 'ipc'
test.cpp:23:9: error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
test.cpp:24:9: error: assignment of read-only variable 'ipc'
test.cpp:27:9: error: assignment of read-only variable 'ipc'
test.cpp:27:9: error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
test.cpp:32:9: error: assignment of read-only location '* cip'
test.cpp:33:9: error: assignment of read-only location '* icp'
The outcome is funny, first we know that the declaration int const* icpc const = &ci;
is not accepted, and those declarations right commented not avaliable is indeed not avaliable. So we try again, change int const* icpc const = &ci;
to int const* const icpc = &ci;
and comments those unavaliable declarations like the following. We still got an error:
test.cpp: In function 'int main()':
test.cpp:28:10: error: assignment of read-only variable 'icpc'
Actually I have to say I have never seen this kind declaration used in any code, so comment it as well, we got:
#include<iostream>
using namespace std;
int main(){
int i = 5;
//int a = 10;
const int ci=15;
int const ic = 20;
const int *cip = &ci;
int const *icp = ⁣
int *const ipc = &i;
//int const* const icpc = &i;
cout <<"int i: < "<< &i << " > "<< i <<endl;
cout <<"const int ci: < "<< &ci << " > "<< ci <<endl;
cout <<"int const ic: < "<< &ic << " > "<< ic<< endl;
cout <<"const int *cip = &ci; so cip: < "<< cip << " > "<< *cip <<endl;
cout <<"int const *icp = ⁣ so icp: < "<< icp << " > "<< *icp<< endl;
cout <<"int *const ipc = &i; so ipc: < "<< ipc << " > "<< *ipc<< endl;
//cout <<"int const* icpc const = &ci; so icpc: < "<< icpc << " > "<< *icpc<< endl;
//cout <<"icpc: < "<<icpc << " > "<< *icpc<< endl;
//ci = i;// not avaliable
//ic = i;// not avaliable
//ipc = ⁣// not avaliable
//ipc = &a;// not avaliable
cip = &i;
icp = &i;
//ipc = ⁣//not avaliable
//icpc = ⁣
cout <<"After operation cip = &i; cip: < "<< cip << " > "<< *cip <<endl;
cout <<"After operation icp = &i; icp: < "<< icp << " > "<< *icp<< endl;
cout <<"The value of icp and cip is changable, ipc can not be modified."<< endl;
//*cip = ci;// not avaliable
//*icp = ci;// not avaliable
i = ci;
*ipc = ci;
//*icpc = ic;
cout <<"After *ipc = ci; ipc < "<< ipc << " > "<< *ipc <<endl;
cout <<"After i=ci; cip: < "<< cip << " > "<< *cip <<endl;
cout <<"After i=ci; icp: < "<< icp << " > "<< *icp <<endl;
cout <<"The integer that icp, cip and ipc point to can be changed, but *cip and *icp can not be modified directly!"<< endl;
return 0;
}
Outcome
The code above passes the compilation, then we run it, we can see the outcomes like the following:
int i: < 0x64fd64 > 5
const int ci: < 0x64fd60 > 15
int const ic: < 0x64fd5c > 20
const int *cip = &ci; so cip: < 0x64fd60 > 15
int const *icp = ⁣ so icp: < 0x64fd5c > 20
int *const ipc = &i; so ipc: < 0x64fd64 > 5
After operation cip = &i; cip: < 0x64fd64 > 5
After operation icp = &i; icp: < 0x64fd64 > 5
The value of icp and cip is changable, ipc can not be modified.
After *ipc = ci; ipc < 0x64fd64 > 15
After i=ci; cip: < 0x64fd64 > 15
After i=ci; icp: < 0x64fd64 > 15
The integer that icp, cip and ipc point to can be changed, but *cip and *icp can not be modified directly!
Conclusion
The test outcomes proved our analysis, and we can know that we still can modifier the value that const int *p
and int const *p
point to indirectly. Also, it maybe different in other GCC version ,since my version is just 4.7.
Reference
- const T vs T const
- Pointers on C