By ultraman

2009-07-17 13:28:09 8 Comments

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.


@blue_note 2019-07-31 17:55:45

  • if const is to the left of *, it refers to the value (it doesn't matter whether it's const int or int const)
  • if const is to the right of *, it refers to the pointer itself
  • it can be both at the same time

An important point: const int *p does not mean the value you are referring to is constant!!. It means that you can't change it through that pointer (meaning, you can't assign $*p = ...`). The value itself may be changed in other ways. Eg

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

This is meant to be used mostly in function signatures, to guarantee that the function can't accidentally change the arguments passed.

@ufukgun 2009-07-17 13:31:45

Simple Use of const.

The simplest use is to declare a named constant. To do this, one declares a constant as if it was a variable but add const before it. One has to initialize it immediately in the constructor because, of course, one cannot set the value later as that would be altering it. For example:

const int Constant1=96; 

will create an integer constant, unimaginatively called Constant1, with the value 96.

Such constants are useful for parameters which are used in the program but are do not need to be changed after the program is compiled. It has an advantage for programmers over the C preprocessor #define command in that it is understood & used by the compiler itself, not just substituted into the program text by the preprocessor before reaching the main compiler, so error messages are much more helpful.

It also works with pointers but one has to be careful where const to determine whether the pointer or what it points to is constant or both. For example:

const int * Constant2 

declares that Constant2 is variable pointer to a constant integer and:

int const * Constant2

is an alternative syntax which does the same, whereas

int * const Constant3

declares that Constant3 is constant pointer to a variable integer and

int const * const Constant4

declares that Constant4 is constant pointer to a constant integer. Basically ‘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).


@Shijing Lv 2015-07-10 02:15:22

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

@Dave 2015-09-25 16:52:10

thats just reading it right to left.

@R71 2016-04-08 12:03:44

@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 2016-04-08 13:34:41

@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:

@Matthew Read 2016-09-18 23:04:27

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.

@rfcoder89 2016-10-01 07:10:35

I like the colours. Just a simple man passing through

@Aadishri 2016-10-26 09:22:23

Thanks for completely clarifying with colours and arrows. I found this intersting for further practice

@naXa 2017-05-03 19:04:49

Ultimate example: void (*signal(int, void (*fp)(int)))(int); from

@haccks 2017-05-12 07:17:04

Do not rely on this rule. This is not universal. There are some cases where it fails.

@Jiří 2018-10-30 09:51:11

@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 2019-01-17 20:01:52

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. ;-)

@Hunter 2018-09-23 08:44:06

The const with the int on either sides will make pointer to constant int:

const int *ptr=&i;


int const *ptr=&i;

const after * will make constant pointer to int:

int *const ptr=&i;

In this case all of these are pointer to constant integer, but none of these are constant pointer:

 const int *ptr1=&i, *ptr2=&j;

In this case all are pointer to constant integer and ptr2 is constant pointer to constant integer. But ptr1 is not constant pointer:

int const *ptr1=&i, *const ptr2=&j;

@Undefined Behavior 2019-02-17 16:30:04

Just for the sake of completeness for C following the others explanations, not sure for C++.

  • pp - pointer to pointer
  • p - pointer
  • data - the thing pointed, in examples x
  • bold - read-only variable


  • p data - int *p;
  • p data - int const *p;
  • p data - int * const p;
  • p data - int const * const p;

Pointer to pointer

  1. pp p data - int **pp;
  2. pp p data - int ** const pp;
  3. pp p data - int * const *pp;
  4. pp p data - int const **pp;
  5. pp p data - int * const * const pp;
  6. pp p data - int const ** const pp;
  7. pp p data - int const * const *pp;
  8. pp p data - int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N-levels of Dereference

Just keep going, but may the humanity excommunicate you.

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);

@srivatsahc 2019-02-04 07:48:16

For me, the position of const i.e. whether it appears to the LEFT or RIGHT or on both LEFT and RIGHT relative to the * helps me figure out the actual meaning.

  1. A const to the LEFT of * indicates that the object pointed by the pointer is a const object.

  2. A const to the RIGHT of * indicates that the pointer is a const pointer.

The following table is taken from Stanford CS106L Standard C++ Programming Laboratory Course Reader.

enter image description here

@Kaz Dragon 2009-07-17 13:39:47

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.

@Mephane 2011-01-28 13:01:06

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. 2012-10-17 14:06:02

@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.

@ApproachingDarknessFish 2013-12-26 21:07:47

@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 2014-05-08 12:29:28

@KazDragon THANKS! Without it, I would've messed up with all those typedefed PVOID, LPTSTR stuff in Win32 api!

@Groo 2017-05-08 16:37:00

@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. :)

@dgnuff 2018-03-15 07:07:36

@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.

@Francis Cugler 2019-03-05 07:21:42

@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.

@AProgrammer 2009-07-17 13:30:06

The general rule is that the const keyword applies to what precedes it immediately. Exception, a starting const applies to what follows.

  • const int* is the same as int const* and means "pointer to constant int".
  • const int* const is the same as int const* const and means "constant pointer to constant int".

Edit: For the Dos and Don'ts, if this answer isn't enough, could you be more precise about what you want?

@Matt Price 2009-07-17 13:29:58

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

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

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.

@Michael 2009-07-17 17:26:53

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 2010-02-11 19:00:31

@Michael: Kudos to Michael for such a simple rule for remembering/understanding const rule.

@Mooing Duck 2013-05-28 19:53:36

@Jeffrey: read it backwards works well as long as there are no parenthesis. Then, well... use typedefs

@David Lee 2014-05-08 12:32:59

+1 to @Michael for simplicity. With your rule of thumb, I'll never get confused even after a decade or so.

@Wolf 2014-06-18 09:21:28

+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 2014-07-28 16:52:35

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 2015-03-26 10:19:39

Why no C/C++ book presents it this way? It's great

@jcwenger 2015-08-12 23:01:58

@legends2k, flagged your comment for stale link -- Please edit and update to

@gedamial 2016-07-05 10:01:36

Why doesn't const int * const * const p work? Const pointer to const pointer to const int!

@RastaJedi 2016-08-08 23:15:10

@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 2016-09-05 08:39:32

in case of of const pointer can't we point to NULL after initialisation?

@foodtooth 2018-05-10 12:28:41

constexpr int *q is declared as a const pointer to int. Why is this not following the rule?

@Jesse Chisholm 2019-01-17 19:57:51

@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.

@Forbin 2019-10-08 23:50:48

@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.

@dgnuff 2018-03-15 07:59:23

This mostly addresses the second line: best practices, assignments, function parameters etc.

General practice. Try to make everything const that you can. Or to put that another way, make everything const to begin with, and then remove exactly the minimum set of consts necessary to allow the program to function. This will be a big help in attaining const-correctness, and will help ensure that subtle bugs don't get introduced when people try and assign into things they're not supposed to modify.

Avoid const_cast<> like the plague. There are one or two legitimate use cases for it, but they are very few and far between. If you're trying to change a const object, you'll do a lot better to find whoever declared it const in the first pace and talk the matter over with them to reach a consensus as to what should happen.

Which leads very neatly into assignments. You can assign into something only if it is non-const. If you want to assign into something that is const, see above. Remember that in the declarations int const *foo; and int * const bar; different things are const - other answers here have covered that issue admirably, so I won't go into it.

Function parameters:

Pass by value: e.g. void func(int param) you don't care one way or the other at the calling site. The argument can be made that there are use cases for declaring the function as void func(int const param) but that has no effect on the caller, only on the function itself, in that whatever value is passed cannot be changed by the function during the call.

Pass by reference: e.g. void func(int &param) Now it does make a difference. As just declared func is allowed to change param, and any calling site should be ready to deal with the consequences. Changing the declaration to void func(int const &param) changes the contract, and guarantees that func can now not change param, meaning what is passed in is what will come back out. As other have noted this is very useful for cheaply passing a large object that you don't want to change. Passing a reference is a lot cheaper than passing a large object by value.

Pass by pointer: e.g. void func(int *param) and void func(int const *param) These two are pretty much synonymous with their reference counterparts, with the caveat that the called function now needs to check for nullptr unless some other contractual guarantee assures func that it will never receive a nullptr in param.

Opinion piece on that topic. Proving correctness in a case like this is hellishly difficult, it's just too damn easy to make a mistake. So don't take chances, and always check pointer parameters for nullptr. You will save yourself pain and suffering and hard to find bugs in the long term. And as for the cost of the check, it's dirt cheap, and in cases where the static analysis built into the compiler can manage it, the optimizer will elide it anyway. Turn on Link Time Code Generation for MSVC, or WOPR (I think) for GCC, and you'll get it program wide, i.e. even in function calls that cross a source code module boundary.

At the end of the day all of the above makes a very solid case to always prefer references to pointers. They're just safer all round.

@luke 2009-07-17 13:36:54

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.

@Jesse Chisholm 2019-01-17 20:06:58

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.

@Edison Lo 2019-09-17 15:05:29

simple and nice explaintion!

@Cheers and hth. - Alf 2016-01-06 00:12:59

The C and C++ declaration syntax has repeatedly been described as a failed experiment, by the original designers.

Instead, let's name the type “pointer to Type”; I’ll call it Ptr_:

template< class Type >
using Ptr_ = Type*;

Now Ptr_<char> is a pointer to char.

Ptr_<const char> is a pointer to const char.

And const Ptr_<const char> is a const pointer to const char.


enter image description here

@sp2danny 2016-09-14 07:20:05

do you have a quote for the first sentence?

@Cheers and hth. - Alf 2016-09-14 10:42:47

@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 2016-09-14 10:47:07

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").".

@Stargateur 2018-01-01 14:22:05

"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 2018-01-01 14:25:33

@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.

@Antti Haapala 2019-08-25 05:00:18

@Abhijit Sahu 2015-01-04 13:10:45

It's simple but tricky. Please note that we can swap the const qualifier with any data type (int, char, float, etc.).

Let's see the below examples.

const int *p ==> *p is read-only [p is a pointer to a constant integer]

int const *p ==> *p is read-only [p is a pointer to a constant integer]

int *p const ==> Wrong Statement. Compiler throws a syntax error.

int *const p ==> p is read-only [p is a constant pointer to an integer]. As pointer p here is read-only, the declaration and definition should be in same place.

const int *p const ==> Wrong Statement. Compiler throws a syntax error.

const int const *p ==> *p is read-only

const int *const p1 ==> *p and p are read-only [p is a constant pointer to a constant integer]. As pointer p here is read-only, the declaration and definition should be in same place.

int const *p const ==> Wrong Statement. Compiler throws a syntax error.

int const int *p ==> Wrong Statement. Compiler throws a syntax error.

int const const *p ==> *p is read-only and is equivalent to int const *p

int const *const p ==> *p and p are read-only [p is a constant pointer to a constant integer]. As pointer p here is read-only, the declaration and definition should be in same place.

@rgk 2015-03-21 13:56:12

I had the same doubt as you until I came across this book by the C++ Guru Scott Meyers. Refer the third Item in this book where he talks in details about using const.

Just follow this advice

  1. If the word const appears to the left of the asterisk, what's pointed to is constant
  2. If the word const appears to the right of the asterisk, the pointer itself is constant
  3. If const appears on both sides, both are constant

@Behrooz Tabesh 2014-05-17 20:21:03

  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

@Jeff Burdges 2011-09-13 10:50:54

There are many other subtle points surrounding const correctness in C++. I suppose the question here has simply been about C, but I'll give some related examples since the tag is C++ :

  • You often pass large arguments like strings as TYPE const & which prevents the object from being either modified or copied. Example :

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    But TYPE & const is meaningless because references are always const.

  • You should always label class methods that do not modify the class as const, otherwise you cannot call the method from a TYPE const & reference. Example :

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • There are common situations where both the return value and the method should be const. Example :

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    In fact, const methods must not return internal class data as a reference-to-non-const.

  • As a result, one must often create both a const and a non-const method using const overloading. For example, if you define T const& operator[] (unsigned i) const;, then you'll probably also want the non-const version given by :

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, there are no const functions in C, non-member functions cannot themselves be const in C++, const methods might have side effects, and the compiler cannot use const functions to avoid duplicate function calls. In fact, even a simple int const & reference might witness the value to which it refers be changed elsewhere.

@T.E.D. 2009-07-17 13:52:23

This question shows precisely why I like to do things the way I mentioned in my question is const after type id acceptable?

In short, I find the easiest way to remember the rule is that the "const" goes after the thing it applies to. So in your question, "int const *" means that the int is constant, while "int * const" would mean that the pointer is constant.

If someone decides to put it at the very front (eg: "const int *"), as a special exception in that case it applies to the thing after it.

Many people like to use that special exception because they think it looks nicer. I dislike it, because it is an exception, and thus confuses things.

@Matt Price 2009-07-17 14:08:15

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. 2009-07-17 14:19:20

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.

@dgnuff 2018-03-15 07:18:06

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

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] What is the "-->" operator in C++?

37 Answered Questions

27 Answered Questions

[SOLVED] Easiest way to convert int to string in C++

43 Answered Questions

[SOLVED] How do I convert a String to an int in Java?

10 Answered Questions

[SOLVED] Improve INSERT-per-second performance of SQLite?

32 Answered Questions

[SOLVED] What is the difference between const and readonly in C#?

28 Answered Questions

[SOLVED] Get int value from enum in C#

  • 2009-06-03 06:46:39
  • jim
  • 1410082 View
  • 1689 Score
  • 28 Answer
  • Tags:   c# enums casting int

27 Answered Questions

7 Answered Questions

Sponsored Content