char *msg;
msg = "hello";
msg = "good-bye";
(Of course, real code would have these three statements interspersed
with other, meaningful, code.)This code will give you warning messages for the two assignment statements, saying "deprecated conversion from string constant to 'char *'" The explanation is that your code should not be able to modify the contents of string literals, like "hello", but the above code, if allowed to compile, would allow you to write statements like the following:
char *msg = "hello";
*msg = 'j';
printf( "%s\n", "hello" );
This would let you change the literal "hello" into "jello"! In fact,
if you compile this code on forbin, you will get a warning message from
the compiler, but will get an executable program that actually prints
"jello" when you run it. Clearly, this is not a good thing to have
happening in your programs. (If you run the same code on a Linux
system, you will get a memory fault when the program tries to modify
the string constant. The difference has to do with how the two
different operating systems protect different regions of memory.)
Correct Solution
The correct solution to the problem is to declare msg to be a pointer to
a constant string:
const char *msg;
msg = "hello";
msg = "good-bye";
That code compiles with no warning messages, and probably does just
what you wanted to accomplish. But, having done this, you will get an
error message (not just a warning) from the compiler if you try
something like:
*msg = 'j';
... which is also what you want! It would be wrong to try to change a
string constant.Note that the following code also compiles without any warnings and executes without any problems:
const char *msg;
char buf[ 10 ];
sprintf( buf, "%03d\n", 7 );
msg = buf;
It's okay to change the contents of the buf array because it has
not been declared to be constant. In this case, msg will point
to the string, "007\n". Then statements like
*buf = 'x';
will compile and execute okay, but statements like
*msg = 'x';
will generate a warning from the compiler because you have declared that
msg points to characters that are not to be modified.
char *msg;
msg = (char *) "hello";
That is, this code "casts away" the const-ness of the literal "hello"
when assigning a pointer to it to the variable msg.But if you put in this cast, the compiler will then compile the following statement with no error or warning messages:
*msg = 'j';
and you won't know about your mistake until run-time, when your
program will either generate a memory fault (on Linux) or produce wrong
results, like "jello", (on forbin). It's a lot easier to fix problems
if the compiler tells you where you made your mistake than trying to
figure out what went wrong at run time, but casting away const-ness
is a way of getting the compiler to suppress useful warning messages.The moral is:
| Never cast away the const-ness of character strings! |
|---|
const char* const msg_0;
const char *msg_1;
char* const msg_2;
char *msg_3;
Here, msg_0 is a constant pointer to a constant string. The
statement shown will give a compile-time error because msg_0 is
not made to point to anything, and there is no way to assign a pointer
to it later on because of the const*. For example:
const char const *msg_0 = "hello";
would compile okay, and there would then be no way
either to execute either:
*msg_0 = 'j';
or
msg_0 = "good-bye";
Basically, this makes msg_0 synonymous with the string constant,
"hello".We have already looked at code equivalent to msg_1 earlier. This pointer can be assigned pointers to both constant and variable strings, but cannot be used to modify any string that it points to.
There will also be an error if you try to compile the definition of msg_2 for the same reason there would be an error for msg_0. Because the pointer itself is constant, it has to be given a value when the variable is declared. But having done so, it would be syntactically correct to change the string pointed to by this variable:
char buf[ 10 ];
char const *msg_2 = buf;
With this code, msg_2 points to buf[ 0 ], and it must do
so forever.And there's not much to say about msg_3. You can change the pointer, and you can change what the pointer points to.