Why does passing char** as const char** generate a warning? - c

I've been getting this warning:
note: expected ‘const char **’ but argument is of type ‘char **’
For now, I'm passing the arguments by casting them to const char **. Is there any other way I can get rid of it?

Short Answer
Can you safely typecast char ** to const char**? No. (Not safely anyway), and the reason is far more subtle than you may think. Can you get rid of it another way? Sure. Load an array of const char* values from your char* values and pass that instead. (or change the callee prototype, but thats cheating =P).
Consider the following code, which essentially does everything you're wishing except invoke a function. The marked line demonstrates the equivalent point-of-cast
const char *s = "Test";
char *p = NULL;
char **pp = &p; // Put address of our pointer in our pointer-to-pointer.
const char **cpp = pp; // Here: assigning char** to const char**
*cpp = s; // perfectly legal; pp and s both finish "char const"
*p = 0; // ru ro raggy
It takes awhile to really stare at this, and admittedly I didn't see it at first either. #sheu did a solid job of catching it about 24 hours before I really thought about it long enough to realize he was right all along (and I actually upvoted that answer before writing this one). Then I thought he was wrong about the same time he thought his answer wasn't applicable. Turns out we were both wrong on that leap, because he was right the first time, I was wrong the second time, and now... ugh.
On VS2012 and VS2010 both the marked line will flag an error without a cast. clang will compile it with a warning in C, but allow it (which I found surprising). Given, you do have to really step out of your happy place to break it, but it is still none-the-less broken.
The rest of this is a diatribe on identifying pointer types, their constness, and what is equivalent to what.
Long Diatribe on Pointers And Const
The warning is because char ** and const char ** are not equivalent (duh). To be correct, you could fix the prototype (callee), or fix the caller (by loading an array of const char * and passing that). But can you safely typecast the first to the second? Hmmm....
Remember, by the standard const goes to the item immediately to its left. Declaring it on the most-left of a data type is a nicety that the language supports, but often introduces confusion or problems. As a rule-of-thumb, if const appears on the far-left of a decl immediately before the type, it applies to the data type; not the subsequent pointer (if any). When it appears to the right of anything it applies to the immediate-left decl-part, be it a data type part or a pointer part, but no matter what it only applies to a single part.
A plethora of samples follows:
No Indirection:
const char ch; // const character. must be initialized.
char const ch; // same as above
Single-Indirection:
char *p; // p is mutable, *p is mutable
const char *p; // p is mutable, *p is const
char const *p; // same as above.
char *const p; // p is const, *p is mutable, must be initialized.
char const *const p; // p is const, *p is const, must be initialized.
Double Indirection:
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are ALL mutable
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable, **p is const
char const **p; // same as above
char *const *p; // ptr-to-const-ptr-to-char
// p is mutable, *p is const, **p is mutable.
char **const p; // const-ptr-to-ptr-to-char
// p is const, *p is mutable, **p is mutable.
// must be initialized.
const char **const p; // const-ptr-to-ptr-to-const-char
// p is const, *p is mutable, **p is const.
// must be initialized.
char const **const p; // same as above
char const *const *p; // ptr-to-const-ptr-to-const-char
// p is mutable, *p is const, **p is const.
const char *const *p; // same as above.
char *const *const p; // const-ptr-to-const-ptr-to-char
// p is const, *p is const, **p is mutable.
// must be initialized.
And of course who can leave home without...
char const *const *const p; // const-ptr-to-const-ptr-to-const-char
// everything is const.
// must be initialized.
const char *const *const p; // same as above
So how does this affect your question? When compiling that code in C, without a cast you'll get a compiler warning (or error if compiling with -Werror). When compiling in C++, you'll just plain error because the parameter signature doesn't match. But why?
Because these have no direct equivalence:
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable **p is const
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are all mutable
When compiling with clang, the exact warning in C is given as:
main.c:15:9: Passing char ** to parameter of type const char ** discards qualifiers in nested pointer types.
VS2010 and VS2012 both, on the other hand, toss an error:
error C2440: 'initializing' : cannot convert from 'char **' to 'const char **'
It seems odd, but VS is actually more correct (wonders never cease).
And that makes perfect sense. Nestled down in the type declaration is the fact that the first of these does not allow modification to the final data, the second does. From above we know that char ** and const char ** (aka. char const **), are not the same. At the bottom of one is a pointer to a const char, while the other has a pointer to char.

edit: I even answered the wrong question. My answer is completely irrelevant! Ignore me please.
edit 2: after the gentleman question asker clarifies his question, it turns out that my answer is in fact relevant. C'est la vie.
This is a fun bit of C, which makes sense if you think hard enough about it.
Basically, the conversion:
char** ptr;
const char** const_ptr;
const_ptr = ptr; // <-- BAD!
is not allowed.
Why, you might ask? "I'm making things more const! This is obviously a good thing!"
Well, think about this. If that were allowed, then:
const char c = 'A';
char* ptr;
const char** const_ptr = &ptr; // <-- ILLEGAL, but what if this were legal?
*const_ptr = &c;
*ptr = 'B'; // <- you just assigned to "const char c" above.
BAM you're dead. So... no :-)

The warning tells you that the function you're calling expects the given parameter as const char** but you're passing a char** parameter. To get rid of this warning you could
really pass in a const char**
cast your parameter to a const char** (like you're currently doing)
change the function prototype so that the function expects a char**

I still don't think this is right. In the example:
const char c = 'A';
char* ptr;
const char** const_ptr = &ptr; // <-- ILLEGAL, but what if this were legal?
*const_ptr = &c;
*ptr = 'B'; // <- you just assigned to "const char c" above.
The line which breaks this is:
*const_ptr = &c;
Because we are setting a non const sub-pointer to a const pointer. If this where:
const char *const *const_ptr
Then
*const_ptr = &c
would be correct and it wouldn't let you assign to the const char c.
I don't think the compiler should stop you from making something more const.

Related

How is this const being used?

I was studying "C complete reference" by Herbert Schildt and got stuck on the "const" explanation due by the pointer * he used at the same time with the const explanation.
here is the code he used:
#include <stdio.h>
void dash(const char *str);
int main()
{
dash("this is a test");
return 0;
}
void dash(const char *str)
{
while (*str)
{
if (*str == ' ')
{
printf("%c", '-');
}
else
{
printf("%c", *str);
}
str++;
}
}
I've tried to search about the pointer * and got some answers about adresses but why did he use it in this example? His book didn't explain this and i haven't found other examples with this kinda use of pointer *.
Other question is, why is the loop "while (*str)" correct if it has no condition?
const char *str in a parameter declaration indicates that the function will not try to modify the values that the str pointer points to. This means that you can call the function with a constant string. If you don't have const in the declaration, it means that the function might modify the string, so you can only call it with writable strings.
As an example, a function like strcpy() declares has const on the second parameter (the source string), but not on the first parameter (the destination). It can (and usually does) modify the destination, but not the source.
Many people are confused when start learning C
const char *ptr
It is a pointer which is referencing the const char. The pointer can be modified. But is you try to write to the referenced object the compiler will complain: https://godbolt.org/z/d9znF-
Example:
const char c;
const char *ptr = &c;
*ptr = 'p'; // -- illegal - the compiler will complain
ptr++; // -- legal
to declare the constant pointer to the not constant object:
char * const ptr;
now ptr cannot be changed but the referenced object can: https://godbolt.org/z/h7WWex
char c;
char * const ptr = &c;
*ptr = 'p'; // -- legal
ptr++; // -- illegal - the compiler will complain
to declare const pointer to const object
const char * const ptr;
now the pointer and the referenced object cannot be modified: https://godbolt.org/z/x2xBcZ
const char c;
const char * const ptr = &c;
*ptr = 'p'; // -- illegal - the compiler will complain
ptr++; // -- illegal - the compiler will complain
It's a way of promising that the content the pointer is pointing at will not be altered. It's also a way of suppressing warnings without explicit casts.
Consider this:
void dash(char *str) // Removed const
{
// Code
}
int main() {
const char p[] = "this is a test";
dash(p);
}
Now the compiler will emit this:
k.c: In function ‘main’:
k.c:23:10: warning: passing argument 1 of ‘dash’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
23 | dash(p);
| ^
k.c:4:17: note: expected ‘char *’ but argument is of type ‘const char *’
4 | void dash(char *str)
| ~~~~~~^~~
Since you're not writing to it, this warning is nothing to worry about. But it's good practice to avoid warnings. In this case, we have two alternatives. Either the function may modify the string or it may not. If there's no way it will modify it, then there's no reason to explain to the compiler and the reader that this indeed is the case.
Sidenote. String literals, like "this is a test" has undefined behavior if you modify them, so the program might crash (or not). However, their type is is of type (char*) with no const. The reason is backwards compability. In C++, their type is const char*
Note that the const is a promise by convention, not by the compiler. This code will modify the original string and also compile without warnings:
#include <stdio.h>
void foo(const char *str)
{
// Casting comes with great responsibility
// You're just saying to the compiler
// "Trust me and shut up"
char *ptr = (char*) str;
ptr[2]='A';
ptr[3]='T';
}
int main()
{
const char p[] = "this is a test";
foo(p);
puts(p);
}
output:
$ ./a.out
thAT is a test
As I said, the above will compile without warning. If you remove the cast, you'll get this:
k.c:5:17: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
5 | char *ptr = str;
| ^~~
Do note that since p is declared as const this is undefined behavior. However, you instead write main like this:
int main()
{
char p[] = "this is a test";
foo(p);
puts(p);
}
then, the program is completely valid. And even though you pass a writable string to the function foo, you'd expect it to not change, since foo takes a constant pointer as argument. But as you can see, such things can be bypassed.
Be very careful with void pointers
Note that this is perfectly valid for ANY type T:
T x;
T *p;
p = (void*) &x;
This is because you can safely cast a pointer to void and back. However, this is NOT valid in the general case:
T x;
Q *p;
p = (void*) &x;
However, because of the cast, you will not get a warning. But this code invokes undefined behavior.
Moral lesson
Casting is NOT the goto solution for warnings. Instead, you should REALLY carefully consider if your cast match your intentions. If you're intentions here is to just get rid of the warning, the right solution is to remove the const for the parameter. If you're intentions with adding the cast is "I know that this function promises to not modify the argument, but I have good reasons for both promising that and then instantly break that promise" then a cast is correct.
Real world example
Just to give a real world example of how it can go wrong. I looked in this question where I saw this:
void * func_return();
void (*break_ptr)(void) = (void *)func_return;
I told OP that the cast is wrong. I got the response that without a cast, the compiler complained. Well, it complained because the pointer is WRONG. The function prototype declares a function taking an unspecified number of arguments and returning a void pointer. The function pointer is a pointer to a function taking NO arguments returning nothing. So in this case, the proper pointer declaration and initialization would be this:
void * func_return();
void *(*break_ptr)() = func_return;
But this would probably be better:
void * func_return(void);
void *(*break_ptr)(void) = func_return;
Note that since a pointer of any type can be safely cast to void* and back. But in this case OP was not casting it back, but to another type. If OP had done it correctly, the cast would just be clutter, but in this case it did hide the REAL error.
In c we can manipulate an array like a pointer with the right pointer arithmatic like he used and we can manipulate it like an array!
const char *str
is a pointer to const char OR an array of const char data types!
In a function, all parameters are passed by value (arrays are no exception). When you pass an array in a function it "decays into a pointer". And when you compare an array to something else, again it "decays into a pointer"
so we can write the while loop again in different way:
void dash(const char *str)
{
int i = 0;
while (str[i])
{
if (str[i] == ' ')
{
printf("%c", '-');
}
else
{
printf("%c", str[i]);
}
++i;
}
}
Now, the first syntax (with the pointer deref operator * is more effecient than array syntax).
in general array name or the address of the first array element (of any type), can decays to a pointer of the same data type!
In his implementation, he behaves the str as a const char pointer, in the while loop he is derefrence the pointer (like str[i], with the brackets) and in the last line (str++) he is moving the pointer to points to the next char element (which usualy knwon as pointer arithmetics).
In this case, read the definition from right to left:
const char *str // str is a pointer to a const char
The address of str can change while the char it points to cannot.
To answer you other question, while (*str) will continue to interate until *str == '\0'. '\0' is used to mark the end of a string in C.
What the program does, if you're unsure, is print it, replacing ' ' with '-'. In your example, "this-is-a-test" would be printed. Note: the string "this is a test" is not modified.
The * is related to pointers but it has two uses.
In the declaration, * is used to declare the pointer type, as in:
const char *str;
Where str is a pointer to a const char (or multiple const char stored in sequence, C doesn't care about the difference).
In an expression, * is used to dereference a pointer, get the value it points to. As in:
printf("%c", *str);
Where *str is that const char itself that the pointer str is pointing to.
Related to pointers, there's also & that does the other way around. It gets the pointer of any value you have stored in memory.
The importance of const here is not related to pointers, it's related to the fact you're passing a string literal to dash(). Unlike strings that are stored in the heap or the stack, string literals cannot be modified and should be treated as const for their immutability.

Why is const used in function declarations [duplicate]

What's the difference between:
char * const
and
const char *
The difference is that const char * is a pointer to a const char, while char * const is a constant pointer to a char.
The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).
There is also a
const char * const
which is a constant pointer to a constant char (so nothing about it can be changed).
Note:
The following two forms are equivalent:
const char *
and
char const *
The exact reason for this is described in the C++ standard, but it's important to note and avoid the confusion. I know several coding standards that prefer:
char const
over
const char
(with or without pointer) so that the placement of the const element is the same as with a pointer const.
To avoid confusion, always append the const qualifier.
int * mutable_pointer_to_mutable_int;
int const * mutable_pointer_to_constant_int;
int *const constant_pointer_to_mutable_int;
int const *const constant_pointer_to_constant_int;
const always modifies the thing that comes before it (to the left of it), EXCEPT when it's the first thing in a type declaration, where it modifies the thing that comes after it (to the right of it).
So these two are the same:
int const *i1;
const int *i2;
they define pointers to a const int. You can change where i1 and i2 points, but you can't change the value they point at.
This:
int *const i3 = (int*) 0x12345678;
defines a const pointer to an integer and initializes it to point at memory location 12345678. You can change the int value at address 12345678, but you can't change the address that i3 points to.
const char* is a pointer to a constant character
char* const is a constant pointer to a character
const char* const is a constant pointer to a constant character
const * char is invalid C code and is meaningless. Perhaps you meant to ask the difference between a const char * and a char const *, or possibly the difference between a const char * and a char * const?
See also:
What are const pointers (as opposed to pointers to const objects)?
Const in C
Difference between const declarations in C++
C++ const question
Why can I change the values of a const char* variable?
Rule of thumb: read the definition from right to left!
const int *foo;
Means "foo points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; is allowed.
int *const foo;
Means "foo cannot change (const) and points (*) to an int".
To the programmer this means "I will not change the memory address that foo refers to".
*foo = 123; or foo[0] = 123; is allowed.
foo = &bar; would be invalid.
const int *const foo;
Means "foo cannot change (const) and points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to, nor will I change the address that foo refers to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; would be invalid.
const char* x Here X is basically a character pointer which is pointing to a constant value
char* const x is refer to character pointer which is constant, but the location it is pointing can be change.
const char* const x is combination to 1 and 2, means it is a constant character pointer which is pointing to constant value.
const *char x will cause a compiler error. it can not be declared.
char const * x is equal to point 1.
the rule of thumb is if const is with var name then the pointer will be constant but the pointing location can be changed , else pointer will point to a constant location and pointer can point to another location but the pointing location content can not be change.
Another thumb rule is to check where const is:
before * => value stored is constant
after * => pointer itself is constant
First one is a syntax error. Maybe you meant the difference between
const char * mychar
and
char * const mychar
In that case, the first one is a pointer to data that can't change, and the second one is a pointer that will always point to the same address.
Lots of answer provide specific techniques, rule of thumbs etc to understand this particular instance of variable declaration. But there is a generic technique of understand any declaration:
Clockwise/Spiral Rule
A)
const char *a;
As per the clockwise/spiral rule a is pointer to character that is constant. Which means character is constant but the pointer can change. i.e. a = "other string"; is fine but a[2] = 'c'; will fail to compile
B)
char * const a;
As per the rule, a is const pointer to a character. i.e. You can do a[2] = 'c'; but you cannot do a = "other string";
Here is a detailed explanation with code
/*const char * p;
char * const p;
const char * const p;*/ // these are the three conditions,
// const char *p;const char * const p; pointer value cannot be changed
// char * const p; pointer address cannot be changed
// const char * const p; both cannot be changed.
#include<stdio.h>
/*int main()
{
const char * p; // value cannot be changed
char z;
//*p = 'c'; // this will not work
p = &z;
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
char * const p; // address cannot be changed
char z;
*p = 'c';
//p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
const char * const p; // both address and value cannot be changed
char z;
*p = 'c'; // this will not work
p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
char * const and const char *?
Pointing to a constant value
const char * p; // value cannot be changed
Constant pointer to a value
char * const p; // address cannot be changed
Constant pointer to a constant value
const char * const p; // both cannot be changed.
I presume you mean const char * and char * const .
The first, const char *, is a pointer to a constant character. The pointer itself is mutable.
The second, char * const is a constant pointer to a character. The pointer cannot change, the character it points to can.
And then there is const char * const where the pointer and character cannot change.
// Some more complex constant variable/pointer declaration.
// Observing cases when we get error and warning would help
// understanding it better.
int main(void)
{
char ca1[10]= "aaaa"; // char array 1
char ca2[10]= "bbbb"; // char array 2
char *pca1= ca1;
char *pca2= ca2;
char const *ccs= pca1;
char * const csc= pca2;
ccs[1]='m'; // Bad - error: assignment of read-only location ‘*(ccs + 1u)’
ccs= csc; // Good
csc[1]='n'; // Good
csc= ccs; // Bad - error: assignment of read-only variable ‘csc’
char const **ccss= &ccs; // Good
char const **ccss1= &csc; // Bad - warning: initialization from incompatible pointer type
char * const *cscs= &csc; // Good
char * const *cscs1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc= &pca1; // Good
char ** const cssc1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc2= &csc; // Bad - warning: initialization discards ‘const’
// qualifier from pointer target type
*ccss[1]= 'x'; // Bad - error: assignment of read-only location ‘**(ccss + 8u)’
*ccss= ccs; // Good
*ccss= csc; // Good
ccss= ccss1; // Good
ccss= cscs; // Bad - warning: assignment from incompatible pointer type
*cscs[1]= 'y'; // Good
*cscs= ccs; // Bad - error: assignment of read-only location ‘*cscs’
*cscs= csc; // Bad - error: assignment of read-only location ‘*cscs’
cscs= cscs1; // Good
cscs= cssc; // Good
*cssc[1]= 'z'; // Good
*cssc= ccs; // Bad - warning: assignment discards ‘const’
// qualifier from pointer target type
*cssc= csc; // Good
*cssc= pca2; // Good
cssc= ccss; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cscs; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cssc1; // Bad - error: assignment of read-only variable ‘cssc’
}
Constant pointer: A constant pointer can point only to a single variable of the respective data type during the entire program.we can change the value of the variable pointed by the pointer. Initialization should be done during the time of declaration itself.
Syntax:
datatype *const var;
char *const comes under this case.
/*program to illustrate the behaviour of constant pointer */
#include<stdio.h>
int main(){
int a=10;
int *const ptr=&a;
*ptr=100;/* we can change the value of object but we cannot point it to another variable.suppose another variable int b=20; and ptr=&b; gives you error*/
printf("%d",*ptr);
return 0;
}
Pointer to a const value: In this a pointer can point any number of variables of the respective type but we cannot change the value of the object pointed by the pointer at that specific time.
Syntax:
const datatype *varor datatype const *var
const char* comes under this case.
/* program to illustrate the behavior of pointer to a constant*/
#include<stdio.h>
int main(){
int a=10,b=20;
int const *ptr=&a;
printf("%d\n",*ptr);
/* *ptr=100 is not possible i.e we cannot change the value of the object pointed by the pointer*/
ptr=&b;
printf("%d",*ptr);
/*we can point it to another object*/
return 0;
}
The const modifier is applied to the term immediately to its left. The only exception to this is when there is nothing to its left, then it applies to what is immediately on its right.
These are all equivalent ways of saying "constant pointer to a constant char":
const char * const
const char const *
char const * const
char const const *
Two rules
If const is between char and *, it will affect the left one.
If const is not between char and *, it will affect the nearest one.
e.g.
char const *. This is a pointer points to a constant char.
char * const. This is a constant pointer points to a char.
I would like to point out that using int const * (or const int *) isn't about a pointer pointing to a const int variable, but that this variable is const for this specific pointer.
For example:
int var = 10;
int const * _p = &var;
The code above compiles perfectly fine. _p points to a const variable, although var itself isn't constant.
I remember from Czech book about C: read the declaration that you start with the variable and go left.
So for
char * const a;
you can read as: "a is variable of type constant pointer to char",
char const * a;
you can read as: "a is a pointer to constant variable of type char. I hope this helps.
Bonus:
const char * const a;
You will read as a is constant pointer to constant variable of type char.

Why am I able to modify this const char* array? [duplicate]

What's the difference between:
char * const
and
const char *
The difference is that const char * is a pointer to a const char, while char * const is a constant pointer to a char.
The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).
There is also a
const char * const
which is a constant pointer to a constant char (so nothing about it can be changed).
Note:
The following two forms are equivalent:
const char *
and
char const *
The exact reason for this is described in the C++ standard, but it's important to note and avoid the confusion. I know several coding standards that prefer:
char const
over
const char
(with or without pointer) so that the placement of the const element is the same as with a pointer const.
To avoid confusion, always append the const qualifier.
int * mutable_pointer_to_mutable_int;
int const * mutable_pointer_to_constant_int;
int *const constant_pointer_to_mutable_int;
int const *const constant_pointer_to_constant_int;
const always modifies the thing that comes before it (to the left of it), EXCEPT when it's the first thing in a type declaration, where it modifies the thing that comes after it (to the right of it).
So these two are the same:
int const *i1;
const int *i2;
they define pointers to a const int. You can change where i1 and i2 points, but you can't change the value they point at.
This:
int *const i3 = (int*) 0x12345678;
defines a const pointer to an integer and initializes it to point at memory location 12345678. You can change the int value at address 12345678, but you can't change the address that i3 points to.
const char* is a pointer to a constant character
char* const is a constant pointer to a character
const char* const is a constant pointer to a constant character
const * char is invalid C code and is meaningless. Perhaps you meant to ask the difference between a const char * and a char const *, or possibly the difference between a const char * and a char * const?
See also:
What are const pointers (as opposed to pointers to const objects)?
Const in C
Difference between const declarations in C++
C++ const question
Why can I change the values of a const char* variable?
Rule of thumb: read the definition from right to left!
const int *foo;
Means "foo points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; is allowed.
int *const foo;
Means "foo cannot change (const) and points (*) to an int".
To the programmer this means "I will not change the memory address that foo refers to".
*foo = 123; or foo[0] = 123; is allowed.
foo = &bar; would be invalid.
const int *const foo;
Means "foo cannot change (const) and points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to, nor will I change the address that foo refers to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; would be invalid.
const char* x Here X is basically a character pointer which is pointing to a constant value
char* const x is refer to character pointer which is constant, but the location it is pointing can be change.
const char* const x is combination to 1 and 2, means it is a constant character pointer which is pointing to constant value.
const *char x will cause a compiler error. it can not be declared.
char const * x is equal to point 1.
the rule of thumb is if const is with var name then the pointer will be constant but the pointing location can be changed , else pointer will point to a constant location and pointer can point to another location but the pointing location content can not be change.
Another thumb rule is to check where const is:
before * => value stored is constant
after * => pointer itself is constant
First one is a syntax error. Maybe you meant the difference between
const char * mychar
and
char * const mychar
In that case, the first one is a pointer to data that can't change, and the second one is a pointer that will always point to the same address.
Lots of answer provide specific techniques, rule of thumbs etc to understand this particular instance of variable declaration. But there is a generic technique of understand any declaration:
Clockwise/Spiral Rule
A)
const char *a;
As per the clockwise/spiral rule a is pointer to character that is constant. Which means character is constant but the pointer can change. i.e. a = "other string"; is fine but a[2] = 'c'; will fail to compile
B)
char * const a;
As per the rule, a is const pointer to a character. i.e. You can do a[2] = 'c'; but you cannot do a = "other string";
Here is a detailed explanation with code
/*const char * p;
char * const p;
const char * const p;*/ // these are the three conditions,
// const char *p;const char * const p; pointer value cannot be changed
// char * const p; pointer address cannot be changed
// const char * const p; both cannot be changed.
#include<stdio.h>
/*int main()
{
const char * p; // value cannot be changed
char z;
//*p = 'c'; // this will not work
p = &z;
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
char * const p; // address cannot be changed
char z;
*p = 'c';
//p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
const char * const p; // both address and value cannot be changed
char z;
*p = 'c'; // this will not work
p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
char * const and const char *?
Pointing to a constant value
const char * p; // value cannot be changed
Constant pointer to a value
char * const p; // address cannot be changed
Constant pointer to a constant value
const char * const p; // both cannot be changed.
I presume you mean const char * and char * const .
The first, const char *, is a pointer to a constant character. The pointer itself is mutable.
The second, char * const is a constant pointer to a character. The pointer cannot change, the character it points to can.
And then there is const char * const where the pointer and character cannot change.
// Some more complex constant variable/pointer declaration.
// Observing cases when we get error and warning would help
// understanding it better.
int main(void)
{
char ca1[10]= "aaaa"; // char array 1
char ca2[10]= "bbbb"; // char array 2
char *pca1= ca1;
char *pca2= ca2;
char const *ccs= pca1;
char * const csc= pca2;
ccs[1]='m'; // Bad - error: assignment of read-only location ‘*(ccs + 1u)’
ccs= csc; // Good
csc[1]='n'; // Good
csc= ccs; // Bad - error: assignment of read-only variable ‘csc’
char const **ccss= &ccs; // Good
char const **ccss1= &csc; // Bad - warning: initialization from incompatible pointer type
char * const *cscs= &csc; // Good
char * const *cscs1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc= &pca1; // Good
char ** const cssc1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc2= &csc; // Bad - warning: initialization discards ‘const’
// qualifier from pointer target type
*ccss[1]= 'x'; // Bad - error: assignment of read-only location ‘**(ccss + 8u)’
*ccss= ccs; // Good
*ccss= csc; // Good
ccss= ccss1; // Good
ccss= cscs; // Bad - warning: assignment from incompatible pointer type
*cscs[1]= 'y'; // Good
*cscs= ccs; // Bad - error: assignment of read-only location ‘*cscs’
*cscs= csc; // Bad - error: assignment of read-only location ‘*cscs’
cscs= cscs1; // Good
cscs= cssc; // Good
*cssc[1]= 'z'; // Good
*cssc= ccs; // Bad - warning: assignment discards ‘const’
// qualifier from pointer target type
*cssc= csc; // Good
*cssc= pca2; // Good
cssc= ccss; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cscs; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cssc1; // Bad - error: assignment of read-only variable ‘cssc’
}
Constant pointer: A constant pointer can point only to a single variable of the respective data type during the entire program.we can change the value of the variable pointed by the pointer. Initialization should be done during the time of declaration itself.
Syntax:
datatype *const var;
char *const comes under this case.
/*program to illustrate the behaviour of constant pointer */
#include<stdio.h>
int main(){
int a=10;
int *const ptr=&a;
*ptr=100;/* we can change the value of object but we cannot point it to another variable.suppose another variable int b=20; and ptr=&b; gives you error*/
printf("%d",*ptr);
return 0;
}
Pointer to a const value: In this a pointer can point any number of variables of the respective type but we cannot change the value of the object pointed by the pointer at that specific time.
Syntax:
const datatype *varor datatype const *var
const char* comes under this case.
/* program to illustrate the behavior of pointer to a constant*/
#include<stdio.h>
int main(){
int a=10,b=20;
int const *ptr=&a;
printf("%d\n",*ptr);
/* *ptr=100 is not possible i.e we cannot change the value of the object pointed by the pointer*/
ptr=&b;
printf("%d",*ptr);
/*we can point it to another object*/
return 0;
}
The const modifier is applied to the term immediately to its left. The only exception to this is when there is nothing to its left, then it applies to what is immediately on its right.
These are all equivalent ways of saying "constant pointer to a constant char":
const char * const
const char const *
char const * const
char const const *
Two rules
If const is between char and *, it will affect the left one.
If const is not between char and *, it will affect the nearest one.
e.g.
char const *. This is a pointer points to a constant char.
char * const. This is a constant pointer points to a char.
I would like to point out that using int const * (or const int *) isn't about a pointer pointing to a const int variable, but that this variable is const for this specific pointer.
For example:
int var = 10;
int const * _p = &var;
The code above compiles perfectly fine. _p points to a const variable, although var itself isn't constant.
I remember from Czech book about C: read the declaration that you start with the variable and go left.
So for
char * const a;
you can read as: "a is variable of type constant pointer to char",
char const * a;
you can read as: "a is a pointer to constant variable of type char. I hope this helps.
Bonus:
const char * const a;
You will read as a is constant pointer to constant variable of type char.

constness and pointers to pointers

I'm very much confused about the const keyword. I have a function accepting an array of strings as input parameter and a function accepting a variable number of arguments.
void dtree_joinpaths(char* output_buffer, int count, ...);
void dtree_joinpaths_a(char* output_buffer, int count, const char** paths);
dtree_joinpaths internally invokes dtree_joinpaths_a after it has built an array of strings from the argument list.
void dtree_joinpaths(char* output_buffer, int count, ...) {
int i;
va_list arg_list;
va_start(arg_list, count);
char** paths = malloc(sizeof(char*) * count);
for (i=0; i < count; i++) {
paths[i] = va_arg(arg_list, char*);
}
va_end(arg_list);
dtree_joinpaths_a(output_buffer, count, paths);
}
But the gcc compiler gives me the following error message:
src/dtree_path.c: In function 'dtree_joinpaths':
src/dtree_path.c:65: warning: passing argument 3 of 'dtree_joinpaths_a' from incompatible pointer type
When I change char** paths = malloc(count); to const char** paths = malloc(count);, this error is not showing up anymore. What I don't understand is, that
I thought a pointer to an address can always be casted to a const pointer, but not the other way round (which is what is happening here imo).
This example works: http://codepad.org/mcPCMk3f
What am I doing wrong, or where is my missunderstanding?
Edit
My intent is to make the memory of the input data immutable for the function. (in this case the paths parameter).
The reason char ** -> const char** is a "dangerous" conversion is the following code:
const char immutable[] = "don't modify this";
void get_immutable_str(const char **p) {
*p = immutable;
return;
}
int main() {
char *ptr;
get_immutable_str(&ptr); // <--- here is the dangerous conversion
ptr[0] = 0;
}
The above code attempts to modify a non-modifiable object (the global array of const char), which is undefined behavior. There is no other candidate in this code for something to define as "bad", so const-safety dictates that the pointer conversion is bad.
C does not forbid the conversion, but gcc warns you that it's bad. FYI, C++ does forbid the conversion, it has stricter const-safety than C.
I would have used a string literal for the example, except that string literals in C are "dangerous" to begin with -- you're not allowed to modify them but they have type array-of-char rather than array-of-const char. This is for historical reasons.
I thought a pointer to an address can always be casted to a const pointer
A pointer-to-non-const-T can be converted to a pointer-to-const-T. char ** -> const char** isn't an example of that pattern, because if T is char * then const T is char * const, not const char * (at this point it's probably worthwhile not writing the const on the left any more: write char const * and you won't expect it to be the same as T const where T is char *).
You can safely convert char ** to char * const *, and (for reasons that require a little more than just the simple rule) you can safely convert char ** to char const * const *.
The key is that not the pointer is const. To declare a const pointer, use char *const ptr; or to declare a const pointer to a const pointer, char *const *const ptr;. const char **ptr is a pointer to pointer to const char.
Actually if there is a function that accepts a const char** and you pass a char** , this can lead to a problematic situation and viceversa.
In your specific case you expect that the memory is immutable, but it's not immutable and may change at any time. In a multithreading environment you would expect this memory to be thread safe, and as long as it's living in the stack or heap, you wouldn't need a mutex to access to it.
All this is oriented to avoiding errors, but if you are sure that this wouldn't lead to an error you can simply cast the pointer to const char** .
You cannot pass char ** into const char ** because the compiler cannot guarantee const correctness.
Suppose you had the following code (and it compiled):
void foo(const char **ppc, const char* pc)
{
*ppc = pc; // Assign const char* to const char*
}
void bar()
{
const char c = 'x';
char* pc;
foo(&pc, &c); // Illegal; converting const char* to const char**. Will set p == &c
*pc = 'X'; // Ooops! That changed c.
}
See here for the same example without the function calls.

What is the difference between char * const and const char *?

What's the difference between:
char * const
and
const char *
The difference is that const char * is a pointer to a const char, while char * const is a constant pointer to a char.
The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).
There is also a
const char * const
which is a constant pointer to a constant char (so nothing about it can be changed).
Note:
The following two forms are equivalent:
const char *
and
char const *
The exact reason for this is described in the C++ standard, but it's important to note and avoid the confusion. I know several coding standards that prefer:
char const
over
const char
(with or without pointer) so that the placement of the const element is the same as with a pointer const.
To avoid confusion, always append the const qualifier.
int * mutable_pointer_to_mutable_int;
int const * mutable_pointer_to_constant_int;
int *const constant_pointer_to_mutable_int;
int const *const constant_pointer_to_constant_int;
const always modifies the thing that comes before it (to the left of it), EXCEPT when it's the first thing in a type declaration, where it modifies the thing that comes after it (to the right of it).
So these two are the same:
int const *i1;
const int *i2;
they define pointers to a const int. You can change where i1 and i2 points, but you can't change the value they point at.
This:
int *const i3 = (int*) 0x12345678;
defines a const pointer to an integer and initializes it to point at memory location 12345678. You can change the int value at address 12345678, but you can't change the address that i3 points to.
const char* is a pointer to a constant character
char* const is a constant pointer to a character
const char* const is a constant pointer to a constant character
const * char is invalid C code and is meaningless. Perhaps you meant to ask the difference between a const char * and a char const *, or possibly the difference between a const char * and a char * const?
See also:
What are const pointers (as opposed to pointers to const objects)?
Const in C
Difference between const declarations in C++
C++ const question
Why can I change the values of a const char* variable?
Rule of thumb: read the definition from right to left!
const int *foo;
Means "foo points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; is allowed.
int *const foo;
Means "foo cannot change (const) and points (*) to an int".
To the programmer this means "I will not change the memory address that foo refers to".
*foo = 123; or foo[0] = 123; is allowed.
foo = &bar; would be invalid.
const int *const foo;
Means "foo cannot change (const) and points (*) to an int that cannot change (const)".
To the programmer this means "I will not change the value of what foo points to, nor will I change the address that foo refers to".
*foo = 123; or foo[0] = 123; would be invalid.
foo = &bar; would be invalid.
const char* x Here X is basically a character pointer which is pointing to a constant value
char* const x is refer to character pointer which is constant, but the location it is pointing can be change.
const char* const x is combination to 1 and 2, means it is a constant character pointer which is pointing to constant value.
const *char x will cause a compiler error. it can not be declared.
char const * x is equal to point 1.
the rule of thumb is if const is with var name then the pointer will be constant but the pointing location can be changed , else pointer will point to a constant location and pointer can point to another location but the pointing location content can not be change.
Another thumb rule is to check where const is:
before * => value stored is constant
after * => pointer itself is constant
First one is a syntax error. Maybe you meant the difference between
const char * mychar
and
char * const mychar
In that case, the first one is a pointer to data that can't change, and the second one is a pointer that will always point to the same address.
Lots of answer provide specific techniques, rule of thumbs etc to understand this particular instance of variable declaration. But there is a generic technique of understand any declaration:
Clockwise/Spiral Rule
A)
const char *a;
As per the clockwise/spiral rule a is pointer to character that is constant. Which means character is constant but the pointer can change. i.e. a = "other string"; is fine but a[2] = 'c'; will fail to compile
B)
char * const a;
As per the rule, a is const pointer to a character. i.e. You can do a[2] = 'c'; but you cannot do a = "other string";
Here is a detailed explanation with code
/*const char * p;
char * const p;
const char * const p;*/ // these are the three conditions,
// const char *p;const char * const p; pointer value cannot be changed
// char * const p; pointer address cannot be changed
// const char * const p; both cannot be changed.
#include<stdio.h>
/*int main()
{
const char * p; // value cannot be changed
char z;
//*p = 'c'; // this will not work
p = &z;
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
char * const p; // address cannot be changed
char z;
*p = 'c';
//p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
/*int main()
{
const char * const p; // both address and value cannot be changed
char z;
*p = 'c'; // this will not work
p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
char * const and const char *?
Pointing to a constant value
const char * p; // value cannot be changed
Constant pointer to a value
char * const p; // address cannot be changed
Constant pointer to a constant value
const char * const p; // both cannot be changed.
I presume you mean const char * and char * const .
The first, const char *, is a pointer to a constant character. The pointer itself is mutable.
The second, char * const is a constant pointer to a character. The pointer cannot change, the character it points to can.
And then there is const char * const where the pointer and character cannot change.
// Some more complex constant variable/pointer declaration.
// Observing cases when we get error and warning would help
// understanding it better.
int main(void)
{
char ca1[10]= "aaaa"; // char array 1
char ca2[10]= "bbbb"; // char array 2
char *pca1= ca1;
char *pca2= ca2;
char const *ccs= pca1;
char * const csc= pca2;
ccs[1]='m'; // Bad - error: assignment of read-only location ‘*(ccs + 1u)’
ccs= csc; // Good
csc[1]='n'; // Good
csc= ccs; // Bad - error: assignment of read-only variable ‘csc’
char const **ccss= &ccs; // Good
char const **ccss1= &csc; // Bad - warning: initialization from incompatible pointer type
char * const *cscs= &csc; // Good
char * const *cscs1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc= &pca1; // Good
char ** const cssc1= &ccs; // Bad - warning: initialization from incompatible pointer type
char ** const cssc2= &csc; // Bad - warning: initialization discards ‘const’
// qualifier from pointer target type
*ccss[1]= 'x'; // Bad - error: assignment of read-only location ‘**(ccss + 8u)’
*ccss= ccs; // Good
*ccss= csc; // Good
ccss= ccss1; // Good
ccss= cscs; // Bad - warning: assignment from incompatible pointer type
*cscs[1]= 'y'; // Good
*cscs= ccs; // Bad - error: assignment of read-only location ‘*cscs’
*cscs= csc; // Bad - error: assignment of read-only location ‘*cscs’
cscs= cscs1; // Good
cscs= cssc; // Good
*cssc[1]= 'z'; // Good
*cssc= ccs; // Bad - warning: assignment discards ‘const’
// qualifier from pointer target type
*cssc= csc; // Good
*cssc= pca2; // Good
cssc= ccss; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cscs; // Bad - error: assignment of read-only variable ‘cssc’
cssc= cssc1; // Bad - error: assignment of read-only variable ‘cssc’
}
Constant pointer: A constant pointer can point only to a single variable of the respective data type during the entire program.we can change the value of the variable pointed by the pointer. Initialization should be done during the time of declaration itself.
Syntax:
datatype *const var;
char *const comes under this case.
/*program to illustrate the behaviour of constant pointer */
#include<stdio.h>
int main(){
int a=10;
int *const ptr=&a;
*ptr=100;/* we can change the value of object but we cannot point it to another variable.suppose another variable int b=20; and ptr=&b; gives you error*/
printf("%d",*ptr);
return 0;
}
Pointer to a const value: In this a pointer can point any number of variables of the respective type but we cannot change the value of the object pointed by the pointer at that specific time.
Syntax:
const datatype *varor datatype const *var
const char* comes under this case.
/* program to illustrate the behavior of pointer to a constant*/
#include<stdio.h>
int main(){
int a=10,b=20;
int const *ptr=&a;
printf("%d\n",*ptr);
/* *ptr=100 is not possible i.e we cannot change the value of the object pointed by the pointer*/
ptr=&b;
printf("%d",*ptr);
/*we can point it to another object*/
return 0;
}
The const modifier is applied to the term immediately to its left. The only exception to this is when there is nothing to its left, then it applies to what is immediately on its right.
These are all equivalent ways of saying "constant pointer to a constant char":
const char * const
const char const *
char const * const
char const const *
Two rules
If const is between char and *, it will affect the left one.
If const is not between char and *, it will affect the nearest one.
e.g.
char const *. This is a pointer points to a constant char.
char * const. This is a constant pointer points to a char.
I would like to point out that using int const * (or const int *) isn't about a pointer pointing to a const int variable, but that this variable is const for this specific pointer.
For example:
int var = 10;
int const * _p = &var;
The code above compiles perfectly fine. _p points to a const variable, although var itself isn't constant.
I remember from Czech book about C: read the declaration that you start with the variable and go left.
So for
char * const a;
you can read as: "a is variable of type constant pointer to char",
char const * a;
you can read as: "a is a pointer to constant variable of type char. I hope this helps.
Bonus:
const char * const a;
You will read as a is constant pointer to constant variable of type char.

Resources