I was writing a C function that takes int**
as input and the function itself does not modify the data (i.e. matrix elements). So I decided to make the argument a const int**
type (Is that an acceptable practice?). A sample code is like this:
void func1(const int* k) {
std::cout << *k << '\n';
}
void func2(const int** k) {
std::cout << **k << '\n';
}
int main() {
int m = 0;
int* p1 = &m;
func1(p1);
int** p2 = &p1;
func2((const int**)p2); // compilation error unless explicit type conversion
// func2(p2); /* [*] compilation error */
(**p2) = 1;
func1(p1);
func2((const int**)p2);
return 0;
}
My question is, when calling func2
, I have to explicitly convert the double-pointer p2
to const int**
, otherwise it gives the following error:
error: invalid conversion from ‘int**’ to ‘const int**’ [-fpermissive]
Whereas func1
has no such issue. I tested this with both g (10.2.0) on Cygwin and Intel's icpc. Could someone explain why the compiler behaves this way and what is a good practice in this situation?
CodePudding user response:
In a sense, having a const int **
is saying "this pointer points to a pointer to an integer that won't be modified". The problem with implicitly casting an int **
to const int **
is that that promise is easy to mistakenly not keep. For example:
const int c = 1;
int *p1;
const int **p2 = &p1; /* implicit cast from int** to const int** */
*p2 = &c; /* change what the pointed-to pointer points to */
*p1 = 2; /* change a value pointed to by a const int** */
So the requirement for an explicit cast is to make you think about this, I guess.
Example adapted from here.
CodePudding user response:
With multiple levels of pointers, a type is only more const
-qualified if every level of pointer from the right has const
added. This is for const-correctness reasons so that when you assign to the pointer, you can't accidentally assign a more const
-qualified pointer at the "lower" levels of pointers when you have multiple pointers.
For example:
int *** * * * i;
int ***const*const*const* j = i;
// ^ All levels after this have to be const-qualified
This includes the left-most type, const int
. So, if your data is not modified, you should have int const* const* k
.
This is the case in C (as a qualification conversion), but this is still allowed implicitly in C because all pointers can be implicitly converted.