I often see the following function declaration:
some_func(const unsigned char * const buffer)
{
}
Any idea why the const is repeated before the pointer name?
Thanks.
The first const says that the data pointed to is constant and may not be changed whereas the second const says that the pointer itself may not be changed:
char my_char = 'z';
const char* a = &my_char;
char* const b = &my_char;
const char* const c = &my_char;
a = &other_char; //fine
*a = 'c'; //error
b = &other_char; //error
*b = 'c'; //fine
c = &other_char; //error
*c = 'c'; //error
type declarations should(?) be read RTL. const modifies the thing on its left, but the rule is complicated by the fact that you can write both const T and T const (they mean the same thing).
T * const is a constant pointer to mutable T
T & const would be constant reference to mutable T, except references are constant by definition
T const * is a mutable pointer to constant T
T const & is a reference to constant T
T const * const is constant pointer to constant T
It's a constant pointer to a constant unsigned char. You can't change the pointer nor the thing it points to.
In a declaration like const * const T, the first const (before the *) means that what the pointer points at is const (i.e. it's a pointer to a const T). The const after the * means that the pointer itself is const (i.e. can't be modified to point at anything else).
You can read the declaration from the object being declared outward, so const unsigned char * const buffer is read as: "buffer is a const pointer to a const unsigned char" (this is why const should always being placed after what it modifies--with it before, you have to rearrange things to make the sentence--with it declared as unsigned char const * const buffer, translation to English is simple and straighforward (or perhaps "straightbackward", since you actually read from right to left in this case).
assuming const unsigned char * const
Everyone is correct that its a const pointer to a const unsigned char.
C++ types read mostly right to left unless there are any modifiers on the far left then these read left to right.
This makes it a const pointer to a const value, rather than a mutable pointer to a const value or a const pointer to a mutable value.
const * unsigned char const buffer means that you cannot modify the pointer buffer nor the memory that buffer points to.
A couple of articles to help you understand const correctness in C++:
Wikipedia
Possibility.com
Related
So I am learning C++ right now, and I just started to get into Pointers, and I thought I would understand the semantics pretty well till iI saw this in one of the recommended solutions to an exercise int the Book I am learning with:
const char* sa = * ( static_cast < const char* const* > (a));
I understand everything aside the const* in the Type Parameter. Why is it there, what does it do?
EDIT: corrected unclear formulation
* in a type means that the type is a pointer to the type on the left side of the asterisk.
const in a type means that the type to the left of const is constant. For an object, const means that the value may not be modified. For a reference, const means that the object may not be modified through the reference.
char is a type that represents an integer encoded narrow character object.
const char is a const char.
const char* is a pointer to a const char.
const char* const is a const pointer to a const char.
const char* const* is a pointer to a const char* const.
Note that the pointer is indirected:
* ( static_cast < const char* const* > (a));
^ indirection operator
When a pointer is indirected, the result is a reference (lvalue) to the pointed object. If a const char* were indirected, the resulting lvalue would have the type const char. Clearly such lvalue couldn't be used to initialize the object const char* sa.
When a const char* const* is indirected, the result will be a reference (lvalue) to an object of type const char* const. Such value can be used to initialize const char* sa.
A simpler example without casts:
const char c; // c cannot be modified
const char* const a = &c; // a points to charcter object c
// a cannot be modified
const char* sa = *a; // sa points to a as well
sa = nullptr; // sa can be modified; it no longer points to a
I just wondered what's the difference between having a constructor with const char* c or char* const c as a parameter?
If I swap char* and const in header and source file it isn't a problem but when I mix them it won't compile, saying there is no such overloaded constructor.
When I use my own class for a copy constructor the compiler doesn't seem to bother if I have MyClass const &other and const MyClass &other mixed..
Can anyone enlighten me please? :)
This record const char *c declares pointer c that points to an object of type const char. That is using this pointer you may not change the object that refered to by the pointer.
This record char * const c declares const pointer c that points to a non-const object of type char. You may not change the pointer itself but you may change the object refered to by the pointer.
There is a difference between declaring pointers and references. Though there is used term "constant reference" strictly speaking references themselves may not be constant. According to the C++ grammar
ptr-operator:
* attribute-specifier-seqopt cv-qualifier-seq
& attribute-specifier-seqopt
references do not contain cv-qualifier-seq. So for example this record
Airplane & const other
will be incorrect and the compiler shall issue an error.
As for these records
const Airplane & other
Airplane const & other
then they are equivalent the same way as equivalent the recirds below
const char *c
char const *c
Think of the * as a "fence". What's before it in the declaration defines the type that the pointer refers to. What's after the * defines the pointer itself. For this case, it's easiest to read things backwards (translating * as "pointer to"), so char const *t is read (from back to front) as: "t is a pointer to a const char". Likewise, char *const t is read as: "t is a const pointer to a char."
char *const means the pointer itself is const (can't be modified), but the char(s) it points at can be modified.
char const * or const char * are equivalent to each other. Both mean the pointer itself can be modified, but what it points at cannot.
Substituting a different type for char doesn't change that basic idea.
The same is true with a reference: const T & means a reference to a const T, so you can't modify the T that it refers to. In the case of a reference, you can't modify the reference itself to refer to a different object, so T & const doesn't make any real sense (and isn't allowed).
const applies to the type to its left (or to its right if there is nothing on its left), so const char * and char const * are the same and mean that the characters cannot change, but the pointer can, whereas char * const means that the characters can change but the pointer cannot
The order in which const and char* are written actually make a difference. If you have const char* in your header but char* const in your source file, you will get an error because the compiler won't regard these as the same.
const char* p means that p points to a char that is constant. We can alter where p points to, but we can never alter the contents stored at p.
char* const p means that p is a constant pointer and is pointing to a char. We can alter the contents stored at p, but we cannot alter where p points to.
const char* const p means that p is a constant pointer to a constant char. We cannot alter where p points to nor can we alter the contents at p. Hope this is helpful!
In the following piece of code, to calculate strlen,
int s(const char* str)
{
int count=0;
while(*str++) count++;
return count;
}
You can see that the argument str is const. But, the compiler does not complain when I do a str++. My question is
When passing pointers as arguments to a C function, if is is qualified with const, How can I still perform pointer arithmetic on it? What is const in the above function?
const char* str;
means a non-const pointer to a const data.
char* const str;
means a const pointer to a non-const data.
const char* const str;
means a const pointer to a const data.
The reason for this is that in C++ the variable type declarations are parsed from right to left, which results in that the word "const" always defines the constness of the thing that it's closest to.
It's not declaring the pointer const, it's declaring the thing pointed to as const. Try this:
int s(const char* const str)
With this declaration, you should get a compile error when you modify str.
const char * ch; // non-const pointer to const data
char * const ch; // const pointer to non-constant data.
const char * const ch; // const pointer to const data
Note:
Also
const char * ch;
equals to
char const * ch;
The pointer points to a const char, a read-only character array.
In running this C++ code, I expected the output to be Abc, but, it was FFF, why is that? Isn't name pointing to a constant char?
#include <iostream>
int main()
{
const char* name = "Abc";
name = "FFF";
std::cout<<name<<std::endl;
return 0;
}
Yes, it's pointing to a const char as you say, but it is not a constant pointer. You are changing what you are pointing to, not the contents of what you are pointing to. In other words, the memory holding "Abc" still holds the characters "Abc" after you reassign the pointer.
For a constant pointer, you want const char* const name = "Abc";. In this case, it won't compile since you can't change what the pointer points to.
In general, with const and pointers in C++, you can read the type name from right-to-left to get a feel for what is going on. For example, in the const char* const case, you can read this as "a constant pointer to a character constant". A little weird, but it works.
const char* name = "Abc"; -> Non const pointer-> name, but data (Abc) is constant
name = "FFF" -> changing pointer(name) to point to FFF.
char *p = "Hello"; // non-const pointer,
// non-const data
const char *p = "Hello"; // non-const pointer,
// const data
char * const p = "Hello"; // const pointer,
// non-const data
const char * const p = "Hello"; // const pointer,
// const data
With const char* name = "Abc"; you are telling compiler you will not change the contents of "Abc" using name. However, you are free to change the pointer to point to a different memory location. See this FAQ for details.
It is a known issue with const and English speakers.
The syntax allows both:
const T
T const
and both have the same meaning.
However it becomes complicated once you throw a pointer in the mix:
const T* should be read (const T)*
T const* should be read (T const)*
T* const should be read (T*) const
For that reason I am an adept of always using const on the immediate right of the object. This is more consistent.
Note that the same issue can be found with typedef, let's define typedef T* pointer:
const pointer means T* const, not const T* (as a macro would imply)
pointer const means T* const, like the textual replacement
If you take the habit of putting the const after the name, and not before like an adjective in English, then you won't fall into those traps.
in deed the most correct syntax is
char const * pName;
because const keyword apply namely to the part on the left hand side.
if you want a const poitner to a const char you would write it:
char const * const pName;
and a const pointer to an int;
int * const pInt;
PS: but I still write the const at the begining of the line whenever I can, an anchored habbit ;-)
const char* name = "Abc";
Actually this means, name is a pointer to the const data. Means, it's the data which is const, not the pointer itself. So it's perfectly valid if you write:
name = "FFF"; //ok : changing the pointer
However, the following will not compile:
char * const name = "Abc"; //const pointer to the non-const data!
name = "FFF"; //error: trying to change the pointer itself!
See the compiler error:
prog.cpp:5: error: assignment of
read-only variable ‘name’
See yourself here : http://www.ideone.com/KyNXx
When you declare a variable as
const T* ptr = /*...*/
You are declaring a pointer saying that the object being pointed at, not the pointer, must not change. In other words, it's a "pointer to a T that's const."
If you want to make it impossible to reassign the pointer, you can write
T* const ptr = /*...*/
This is now an immutable pointer to a T, which can be modified.
You can combine these together like this:
const T* const ptr = /*...*/
To get an immutable pointer to an immutable T.
As a fun hint, you can usually determine what parts of a pointer/pointed pair can be modified by reading the type right-to-left. Try that out on the above and see what you get.
First, const is only checked at compilation time. If it compiles, all operations will be done normally at runtime.
In your example, const applies to the content pointed by name. So you are allowed to change the pointer, but not the content.
strcpy(name, "FFF");
would be refused, but not changing the pointer like you did.
The literal strings "Abc" and "FFF" are constant, but name is a variable (pointer to constant data). You have simply changed the variable to point to different constant data.
Moreover while in this case the data was necessarily constant, a pointer to constant data only means that the data cannot be modified by dereferencing that pointer, the data might also be modified directly or through a different pointer. E.g.
int i = 0 ;
const int* p = &i ;
i++ ; // valid
(*p)++ // error.
In C++ whats the difference between
char const *ptr=&ch;
and
const char *ptr=&ch;
They are the same, i.e. pointer to const char.
However char * const ptr is different, being a const pointer to (non-const) char.
And just to complete the set, const char * const ptr is a const pointer to const char.
No difference in C++.
It is important const is before * or after *.
Const applies to whatever is on its immediate left (other than if there is nothing there in which case it applies to whatever is its immediate right). So there is no difference.
char * const ptr would be a const pointer to variable value though.
Other answers have covered the technical solution - your two examples are the same.
Many people prefer to read from right to left when dealing with const in C++. In English, we like to think of a constant X, while C++ likes to parse an X const. Reading right to left yields a more English result.
A rather extreme example:
C const * bar(A * const, B const * const) const;
From right to left this reads as 'A constant function bar taking as parameters a constant pointer to an A and a constant pointer to a constant B, returning a pointer to a constant C'. Note that all three kinds of pointers are different.
char const *ptr=&ch; and const char *ptr=&ch; means char is const, where as the pointer is variable (or it can be changed).
But In case of char * const ptr, you cannot re-assign the pointer once you set it. so its a const pointer to a char string.