What is the difference between const int*, const int * const, and int const *?

627,031

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:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int

Solution 3

I think everything is answered here already, but I just want to add that you should beware of typedefs! 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

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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
    
Share:
627,031
flamingo
Author by

flamingo

Updated on May 01, 2022

Comments

  • flamingo
    flamingo about 2 years

    I always mess up how to use const int*, const int * const, and int 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
      James McNellis almost 14 years
      You can use the "Clockwise/Spiral Rule" to decipher most C and C++ declarations.
    • Dave
      Dave over 13 years
      cdecl.org is a great website which auto-translates C declarations for you.
    • Mark K Cowan
      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
      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
      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
      Cupcake almost 8 years
      The 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
      willem over 4 years
      It 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
      willem over 4 years
      E.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
      Admin almost 4 years
      How come it says your name but it's as if you suicided your account?
    • legends2k
      legends2k over 3 years
    • Paul J. Lucas
      Paul J. Lucas about 3 years
      cdecl.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
      Encipher over 2 years
      @MarkKCowan Can you please take a look stackoverflow.com/questions/70921574/…
  • Matt Price
    Matt Price almost 15 years
    I'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 a T* const anyways, usually a reference will do just fine. I got bit by all this once when wanting a boost::shared_ptr<const T> and instead wrote const boost::shared_ptr<T>. Same issue in a slightly different context.
  • T.E.D.
    T.E.D. almost 15 years
    Actually, 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
    Michael almost 15 years
    I 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
    sivabudh over 14 years
    @Michael: Kudos to Michael for such a simple rule for remembering/understanding const rule.
  • Mephane
    Mephane over 13 years
    And 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 a P, it doesn't speed up typing, plus introducing the issue you mention.
  • T.E.D.
    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
    Mooing Duck almost 11 years
    @Jeffrey: read it backwards works well as long as there are no parenthesis. Then, well... use typedefs
  • ApproachingDarknessFish
    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
    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
    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
    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
    sergiol almost 10 years
    A 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
    Artur about 9 years
    Why no C/C++ book presents it this way? It's great
  • jcwenger
    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
    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
    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
    gedamial almost 8 years
    Why doesn't const int * const * const p work? Const pointer to const pointer to const int!
  • RastaJedi
    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
    Jayesh Bhoi over 7 years
    in case of of const pointer can't we point to NULL after initialisation?
  • sp2danny
    sp2danny over 7 years
    do you have a quote for the first sentence?
  • Cheers and hth. - Alf
    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
    Cheers and hth. - Alf over 7 years
    Oh, 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
    Matthew Read over 7 years
    The 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
    Aadishri over 7 years
    Thanks for completely clarifying with colours and arrows. I found this intersting for further practice
  • naXa stands with Ukraine
    naXa stands with Ukraine about 7 years
    Ultimate example: void (*signal(int, void (*fp)(int)))(int); from archive.is/SsfMX
  • Groo
    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
    haccks about 7 years
    Do not rely on this rule. This is not universal. There are some cases where it fails.
  • Stargateur
    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
    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
    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
    dgnuff about 6 years
    The 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. Take int const * const * p; as an example. No I don't normally write like that, this is just an example. First const: type int, And the int that is const is the contents of the const pointer that is the contents of p. Second const: type is pointer to const int, const oblect is the contents of p
  • foodtooth
    foodtooth about 6 years
    constexpr int *q is declared as a const pointer to int. Why is this not following the rule?
  • Jiří
    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
    Jesse Chisholm over 5 years
    @foodtooth It doesn't follow the const rule because it uses constexpr, not const. constexpr is a different keyword to mean it is const at compile time.
  • Jesse Chisholm
    Jesse Chisholm over 5 years
    re: 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
    Jesse Chisholm over 5 years
    Don'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
    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 -- Слава Україні
    Antti Haapala -- Слава Україні over 4 years
  • Forbin
    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
    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 an int (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
    abetancort almost 4 years
    A copy of the whole article (verbatim) about the “Clockwise/Spiral Rule” by David Anderson is keep in txt format at c-faq.com.
  • BattleTested_закалённый в бою
    BattleTested_закалённый в бою over 3 years
    What is the differences between "reassign" and "modify" for a pointer exactly?
  • flonk
    flonk about 3 years
    apart 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 as constant pointer? what is the meaning of the colors at all?
  • Human-Compiler
    Human-Compiler over 2 years
    The diagrams in this answer do not play nice with Dark Mode, given the transparent backgrounds
  • Jean-Baptiste Yunès
    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 the int it points to (foo can point to a "regular" int, but you can't modify it through the usage of foo). Isn't it?