What is the difference between const int*, const int * const, and int const *?
Solution 1
Read it backwards (as driven by Clockwise/Spiral Rule):
-
int*
- pointer to int -
int const *
- pointer to const int -
int * const
- const pointer to int -
int const * const
- const pointer to const int
Now the first const
can be on either side of the type so:
-
const int *
==int const *
-
const int * const
==int const * const
If you want to go really crazy you can do things like this:
-
int **
- pointer to pointer to int -
int ** const
- a const pointer to a pointer to an int -
int * const *
- a pointer to a const pointer to an int -
int const **
- a pointer to a pointer to a const int -
int * const * const
- a const pointer to a const pointer to an int - ...
And to make sure we are clear on the meaning of const
:
int a = 5, b = 10, c = 15;
const int* foo; // pointer to constant int.
foo = &a; // assignment to where foo points to.
/* dummy statement*/
*foo = 6; // the value of a can´t get changed through the pointer.
foo = &b; // the pointer foo can be changed.
int *const bar = &c; // constant pointer to int
// note, you actually need to set the pointer
// here because you can't change it later ;)
*bar = 16; // the value of c can be changed through the pointer.
/* dummy statement*/
bar = &a; // not possible because bar is a constant pointer.
foo
is a variable pointer to a constant integer. This lets you change what you point to but not the value that you point to. Most often this is seen with C-style strings where you have a pointer to a const char
. You may change which string you point to but you can't change the content of these strings. This is important when the string itself is in the data segment of a program and shouldn't be changed.
bar
is a constant or fixed pointer to a value that can be changed. This is like a reference without the extra syntactic sugar. Because of this fact, usually you would use a reference where you would use a T* const
pointer unless you need to allow NULL
pointers.
Solution 2
For those who don't know about Clockwise/Spiral Rule: Start from the name of the variable, move clockwisely (in this case, move backward) to the next pointer or type. Repeat until expression ends.
Here is a demo:
Solution 3
I think everything is answered here already, but I just want to add that you should beware of typedef
s! They're NOT just text replacements.
For example:
typedef char *ASTRING;
const ASTRING astring;
The type of astring
is char * const
, not const char *
. This is one reason I always tend to put const
to the right of the type, and never at the start.
Solution 4
Like pretty much everyone pointed out:
What’s the difference between const X* p
, X* const p
and const X* const p
?
You have to read pointer declarations right-to-left.
const X* p
means "p points to an X that is const": the X object can't be changed via p.
X* const p
means "p is a const pointer to an X that is non-const": you can't change the pointer p itself, but you can change the X object via p.
const X* const p
means "p is a const pointer to an X that is const": you can't change the pointer p itself, nor can you change the X object via p.
Solution 5
-
Constant reference:
A reference to a variable (here int), which is constant. We pass the variable as a reference mainly, because references are smaller in size than the actual value, but there is a side effect and that is because it is like an alias to the actual variable. We may accidentally change the main variable through our full access to the alias, so we make it constant to prevent this side effect.
int var0 = 0; const int &ptr1 = var0; ptr1 = 8; // Error var0 = 6; // OK
-
Constant pointers
Once a constant pointer points to a variable then it cannot point to any other variable.
int var1 = 1; int var2 = 0; int *const ptr2 = &var1; ptr2 = &var2; // Error
-
Pointer to constant
A pointer through which one cannot change the value of a variable it points is known as a pointer to constant.
int const * ptr3 = &var2; *ptr3 = 4; // Error
-
Constant pointer to a constant
A constant pointer to a constant is a pointer that can neither change the address it's pointing to and nor can it change the value kept at that address.
int var3 = 0; int var4 = 0; const int * const ptr4 = &var3; *ptr4 = 1; // Error ptr4 = &var4; // Error
flamingo
Updated on May 01, 2022Comments
-
flamingo about 2 years
I always mess up how to use
const int*
,const int * const
, andint const *
correctly. Is there a set of rules defining what you can and cannot do?I want to know all the do's and all don'ts in terms of assignments, passing to the functions, etc.
-
James McNellis almost 14 yearsYou can use the "Clockwise/Spiral Rule" to decipher most C and C++ declarations.
-
Dave over 13 yearscdecl.org is a great website which auto-translates C declarations for you.
-
Mark K Cowan almost 9 years@Calmarius: start where the type-name is / should be, move right when you can, left when you must.
int *(*)(char const * const)
. Start to the right of the parenthesized*
then we have to move left:pointer
. Outside the parens, we can move right:pointer to function of ...
. Then we have to move left:pointer to function of ... that returns pointer to int
. Repeat to expand the parameter (the...
):pointer to function of (constant pointer to constant char) that returns pointer to int
. What would the equivalent one-line declaration be in a easy-reading language like Pascal? -
Calmarius almost 9 years@MarkKCowan In Pascal it would be something like
function(x:^char):^int
. There function types are imply a pointer to a function so no need to specify it, and Pascal doesn't enforce const correctness. It can be read from left to right. -
Mark K Cowan almost 9 years@Calmarius: In Pascal though, more complex types often can't be represented in a single expression, and have to be composed by declaring various simpler sub-type-expressions.
-
Cupcake almost 8 yearsThe first thing to the left of the "const" is what's constant. If "const" is the thing the farthest to the left, then the first thing to the right of it is what's constant.
-
willem over 4 yearsIt seems that, even though many good answers are given, the part of the question which asks: "passing to functions" is not really answered yet?
-
willem over 4 yearsE.g. I am still left wondering if it is ever sensible to have a function declaration f(const Class * const obj) instead of f(const Class * obj)? Does the second const in the first declaration ever add anything? I would say no, since the pointer is passed by value anyhow..
-
Admin almost 4 yearsHow come it says your name but it's as if you suicided your account?
-
legends2k over 3 years
-
Paul J. Lucas about 3 yearscdecl.org uses an ancient version of cdecl; a version of cdecl that understands modern C and C++ is here: github.com/paul-j-lucas/cdecl
-
Encipher over 2 years@MarkKCowan Can you please take a look stackoverflow.com/questions/70921574/…
-
-
Matt Price almost 15 yearsI'm torn on this issue. Logically it makes sense. However most c++ developers would write
const T*
and it has become more natural. How often do you ever use aT* const
anyways, usually a reference will do just fine. I got bit by all this once when wanting aboost::shared_ptr<const T>
and instead wroteconst boost::shared_ptr<T>
. Same issue in a slightly different context. -
T.E.D. almost 15 yearsActually, I use constant pointers more often than I use constants. Also, you have to think about how you are going to react in the presence of pointers to pointers (etc.) Admittedly those are rarer, but it would be nice to think about things in a way where you can handle these situations with applomb.
-
Michael almost 15 yearsI would like to append a rule of thumb which may help you remember how to discover whether 'const' applies to pointer or to pointed data: split the statement at asterix sign, then, if the const keyword appears in the left part (like in 'const int * foo') - it belongs to pointed data, if it's in the right part ('int * const bar') - it's about the pointer.
-
sivabudh over 14 years@Michael: Kudos to Michael for such a simple rule for remembering/understanding const rule.
-
Mephane over 13 yearsAnd for me this is the reason to never typedef pointers. I don't see the benefit in things like
typedef int* PINT
(I assume its something that came from practices in C and many developers kept doing it). Great, I replaced that*
with aP
, it doesn't speed up typing, plus introducing the issue you mention. -
T.E.D. over 11 years@Mephane - I can see that. However, to me it seems kind of backwards to avoid a nice language feature in order to keep using an exceptional syntactical rule (about "const" placement), rather than avoiding using the exceptional syntactic rule so you can safely make use of this language feature.
-
Mooing Duck almost 11 years@Jeffrey: read it backwards works well as long as there are no parenthesis. Then, well... use typedefs
-
ApproachingDarknessFish over 10 years@Mephane
PINT
is indeed a rather dumb usage of a typedef, especially cuz it makes me think that the system stores uses beer for memory. typedef s are pretty useful for dealing with pointers to functions, though. -
David Lee about 10 years@KazDragon THANKS! Without it, I would've messed up with all those typedefed
PVOID
,LPTSTR
stuff in Win32 api! -
David Lee about 10 years+1 to @Michael for simplicity. With your rule of thumb, I'll never get confused even after a decade or so.
-
Wolf almost 10 years+1, though a better summary would be: read pointer declarations backwards, that means, close to @Michael 's statement: stop the normal left-to-right reading at the first asterisk.
-
sergiol almost 10 yearsA line with 3 consts on a method declaration: inline const CSomeClass* const GetSomeClass() const { return m_pSomeClass;} — And assuming that m_pSomeClass is declared as: const CSomeClass* m_pSomeClass;
-
Artur about 9 yearsWhy no C/C++ book presents it this way? It's great
-
jcwenger almost 9 years@legends2k, flagged your comment for stale link -- Please edit and update to isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-const
-
R71 about 8 years@Jan the link for the complex example does not have permissions. can you post it directly here, or remove the viewing restrictions?
-
Jan Rüegg about 8 years@Rog it used to have all open access permissions... I didn't write the article and don't have access permissions myself, unfortunately. However, here is an archived version of the article that still works: archive.is/SsfMX
-
gedamial almost 8 yearsWhy doesn't
const int * const * const p
work? Const pointer to const pointer to const int! -
RastaJedi almost 8 years@gedamial it does, it works fine, but you must assign it at the same time you declare it (because you can't reassign a "const pointer").
const int x = 0; const int *const px = &x; const int *const *const p = &px;
works just fine. -
Jayesh Bhoi over 7 yearsin case of of
const
pointer can't we point to NULL after initialisation? -
sp2danny over 7 yearsdo you have a quote for the first sentence?
-
Cheers and hth. - Alf over 7 years@sp2danny: Googling “C syntax failed experiment” only coughs up a number of interviews with Bjarne Stroustrup where he expresses his opinion in that direction, e.g. “I consider the C declarator syntax an experiment that failed” in the Slashdot interview. So I have no reference for the claim about the viewpoints of the original designers of C. I guess it can be found by a sufficiently strong research effort, or maybe disproved simply by asking them, but I think it's better the way it is now. with that part of the claim, still undecided and likely true:)
-
Cheers and hth. - Alf over 7 yearsOh, Dennis Ritchie has passed away. Brian Kernighan still going strong. But Wikipedia's article about him says, " Kernighan affirmed that he had no part in the design of the C language ("it's entirely Dennis Ritchie's work").".
-
Matthew Read over 7 yearsThe complex example is still just right to left, but includes resolving parentheses the way one would normally. The whole clockwise spiral thing doesn't make that any easier.
-
Aadishri over 7 yearsThanks for completely clarifying with colours and arrows. I found this intersting for further practice
-
naXa stands with Ukraine about 7 yearsUltimate example:
void (*signal(int, void (*fp)(int)))(int);
from archive.is/SsfMX -
Groo about 7 years@Mephane: I've had to use pSomething a couple of times when using certain legacy macros which were written to accept a type, but would break apart if the type wasn't a single alphanumeric identifier. :)
-
haccks about 7 yearsDo not rely on this rule. This is not universal. There are some cases where it fails.
-
Stargateur over 6 years"The C and C++ declaration syntax has repeatedly been described as a failed experiment, by the original designers." wrong for C please change your sentence about C or provide some quotes.
-
Cheers and hth. - Alf over 6 years@Stargateur: Apparently you have read the preceding comments and found something you could leverage for pedantry. Good luck with your life. Anyway, old-timers like me remember a lot that we can't prove without engaging in very time-consuming research. You could just take my word.
-
dgnuff about 6 years@T.E.D. The problem comes when you start mixing pointers, consts and other qualifiers. You either have a half baked solution, or you go into typedef overload. See the Win32 API for the horrible unsightly mess that this can lead to. LPCTSTR is an example of a Win32 typedef. Just what exactly is it? Yeah, I have to look it up as well, and I spend a good chunk of my time programming to the Win32 API.
-
dgnuff about 6 yearsThe one other nice advantage of placing the const on the right of the type is that now everything to the left of any
const
is the type of that which is const, and everything to its right is that which is actually const. Takeint const * const * p;
as an example. No I don't normally write like that, this is just an example. Firstconst
: type int, And the int that is const is the contents of the const pointer that is the contents ofp
. Second const: type is pointer toconst
int, const oblect is the contents ofp
-
foodtooth about 6 years
constexpr int *q
is declared asa const pointer to int
. Why is this not following the rule? -
Jiří over 5 years@haccks naturally, it works when there's something on the left. So if you wanna write something like "const int", then the const takes the first right value... so the rule is "take first left if there's any, take first right otherwise"
-
Jesse Chisholm over 5 years@foodtooth It doesn't follow the
const
rule because it usesconstexpr
, notconst
.constexpr
is a different keyword to meanit is const at compile time
. -
Jesse Chisholm over 5 yearsre:
spiral not easier than right-to-left
True, but it gets me dizzy, and as any three-year-old can tell you, getting dizzy is fun. ;-) -
Jesse Chisholm over 5 yearsDon't forget that
const X* p;
==X const * p;
as in"p points to an X that is const": the X object can't be changed via p.
-
Francis Cugler about 5 years@dgnuff I've done some Windows API stuff when doing both DirectX 9 - 11 and Legacy OpenGL 1.0 type of applications. I've seen it a dozen times, and the same I originally had to look it up, but if my memory serves me correctly
LPCTSTR
I believe stands for a Long Pointer to a Const TCHAR STRing. Yeah the win32 API is crazy with typedefs! And this was seen a lot in the 32bit pc era that was carried over from the 16bit days of DOS and Win 3.11 etc. Back then they use to call them far pointers. They kept it for around for compatibility reasons. -
Antti Haapala -- Слава Україні over 4 years@Stargateur "Sethi (...) observed that many of the nested declarations and expressions would become simpler if the indirection operator had been taken as a postfix operator instead of prefix, but by then it was too late to change." is from DMR. Of course DMR did not invent const and volatile keywords, they came from C++ / X3J11, as evidenced on that page.
-
Forbin over 4 years@JayeshBhoi, no. The entire point (no pun intended) of a constant pointer is that you cannot change where it points! In C and C++ this is entirely independent of the value of the pointer. NULL doesn't earn any special priveleges here.
-
RobertS supports Monica Cellio over 4 years@MattPrice I´ve edited the example you have shown because it was majorly lacking in its showcase about illustrating the difference between a pointer to an constant
int
(foo
) and a constant pointer to anint
(bar
) and how they do behave in contrast to each other. I hope you feel comfortable with the edit; else let me know what you would change. -
abetancort almost 4 yearsA copy of the whole article (verbatim) about the “Clockwise/Spiral Rule” by David Anderson is keep in txt format at c-faq.com.
-
BattleTested_закалённый в бою over 3 yearsWhat is the differences between "reassign" and "modify" for a pointer exactly?
-
flonk about 3 yearsapart from the mentioned fact, that the spiral-shape is just misleading, why are is
* const
in the 2nd example colored in one color but with two colors in the 5th example where in the latter it is still interpreted asconstant pointer
? what is the meaning of the colors at all? -
Human-Compiler over 2 yearsThe diagrams in this answer do not play nice with Dark Mode, given the transparent backgrounds
-
Jean-Baptiste Yunès about 2 years
foo
is a variable pointer to a constant integer is misleading.foo
is a pointer from which you can't modify theint
it points to (foo
can point to a "regular" int, but you can't modify it through the usage offoo
). Isn't it?