Implicit conversion from char** to const char**
Why my compiler(GCC) doesnt implicitly cast from char**
to const char**
?
Thie following code:
#include <iostream>
void print(const char** thing) {
std::cout << thing[0] << std::endl;
}
int main(int argc, char** argv) {
print(argv);
}
Gives the following error:
oi.cpp: In function ‘int main(int, char**)’:
oi.cpp:8:12: error: invalid conversion from ‘char**’ to ‘const char**’ [-fpermissive]
oi.cpp:3:6: error: initializing argument 1 of ‘void print(const char**)’ [-fpermissive]
Such a conversion would allow you to put a const char*
into your array of char*
, which would be unsafe. In print
you could do:
thing[0] = "abc";
Now argv[0]
would point to a string literal that cannot be modified, while main
expects it to be non-const (char*
). So for type safety this conversion is not allowed.
@Fred Overflow's link to the FAQ is a complete answer. But (sorry Marshall) it's not the most clear explanation. I don't know if mine is more clear, but I hope so.
The thing is, if p
is a char*
pointer, then it can be used to modify whatever it's pointing at.
And if you could obtain a pointer pp
that points to p
, but with pp
of type char const**
, then you could use pp
to assign to p
the address of a const char
.
And with that, you could then use p
to modify the const char
. Or, you would think you could. But that const char
could even be in read-only memory…
In code:
char const c = 'a';
char* p = 0;
char const** pp = &p; // Not allowed. :-)
*pp = &c; // p now points to c.
*p = 'b'; // Uh oh.
As a practical solution to your code that does not compile, …
#include <iostream>
void print(const char** thing) {
std::cout << thing[0] << std::endl;
}
int main(int argc, char** argv) {
print(argv); // Dang, doesn't compile!
}
just do …
#include <iostream>
void print( char const* const* thing )
{
std::cout << thing[0] << std::endl;
}
int main( int argc, char** argv )
{
print( argv ); // OK. :-)
}
Cheers & hth.,
Note, that although
void dosmth(const char** thing);
int main(int argc, char** argv) {
dosmth(argv);
is forbidden, you can and should do
void dosmth(const char* const* thing);
int main(int argc, char** argv) {
dosmth(argv);
Which is probably what you wanted anyway. The point here is that thing
now refers to a const char*
array which is itself immutable and which referenced values char
are themselves immutable.
So, for a "look at it, but do not change it" scenario, const char* const*
is the type to use.
Note: I used the more common (but in my opinion inferior) standard of trying to write the const
modifier as left as possible. Personally, I recommend writing char const* const*
instead of const char* const*
as it is hugely more concise that way.
Because it might allow us to modify a constant value. Read here to understand why: http://c-faq.com/ansi/constmismatch.html