By Parag


2012-04-10 10:34:17 8 Comments

How many pointers (*) are allowed in a single variable?

Let's consider the following example.

int a = 10;
int *p = &a;

Similarly we can have

int **q = &p;
int ***r = &q;

and so on.

For example,

int ****************zz;

14 comments

@JDługosz 2014-10-14 08:40:04

I'd like to point out that producing a type with an arbitrary number of *'s is something that can happen with template metaprogramming. I forget what I was doing exactly, but it was suggested that I could produce new distinct types that have some kind of meta maneuvering between them by using recursive T* types.

Template Metaprogramming is a slow descent into madness, so it is not necessary to make excuses when generating a type with several thousand level of indirection. It's just a handy way to map peano integers, for example, onto template expansion as a functional language.

@dotslash 2015-11-10 09:21:29

I admit I don't understand your answer fully, but it's given me a new area to explore. :)

@ST3 2013-08-01 20:00:00

It depends on the place where you store pointers. If they are in stack you have quite low limit. If you store it in heap, you limit is much much much higher.

Look at this program:

#include <iostream>

const int CBlockSize = 1048576;

int main() 
{
    int number = 0;
    int** ptr = new int*[CBlockSize];

    ptr[0] = &number;

    for (int i = 1; i < CBlockSize; ++i)
        ptr[i] = reinterpret_cast<int *> (&ptr[i - 1]);

    for (int i = CBlockSize-1; i >= 0; --i)
        std::cout << i << " " << (int)ptr[i] << "->" << *ptr[i] << std::endl;

    return 0;
}

It creates 1M pointers and at the shows what point to what it is easy to notice what the chain goes to the first variable number.

BTW. It uses 92K of RAM so just imagine how deep you can go.

@ST3 2013-07-30 07:15:19

There isn't such a thing like real limit but limit exists. All pointers are variables that are usually storing in stack not heap. Stack is usually small (it is possible to change its size during some linking). So lets say you have 4MB stack, what is quite normal size. And lets say we have pointer which is 4 bytes size (pointer sizes are not the same depending on architecture, target and compiler settings).

In this case 4 MB / 4 b = 1024 so possible maximum number would be 1048576, but we shouldn't ignore the fact that some other stuff is in stack.

However some compilers may have maximum number of pointer chain, but the limit is stack size. So if you increase stack size during linking with infinity and have machine with infinity memory which runs OS which handles that memory so you will have unlimited pointer chain.

If you use int *ptr = new int; and put your pointer into heap, that is not so usual way limit would be heap size, not stack.

EDIT Just realize that infinity / 2 = infinity. If machine has more memory so the pointer size increases. So if memory is infinity and size of pointer is infinity, so it is bad news... :)

@user142019 2013-07-30 07:23:52

A) Pointers can be stored on the heap (new int*). B) An int* and an int********** have the same size, at least on reasonable architectures.

@ST3 2013-07-30 07:28:03

@rightfold A) Yes pointers can be stored in heap. But it would be very different thing like creating container which hold pointers what are pointing to the next previous pointer. B) Of course int* and an int********** have the same size, I didn't said that they have different.

@user142019 2013-07-30 07:28:53

Then I don't see how stack size is even remotely relevant.

@ST3 2013-07-30 07:29:01

Just realized new *int, sorry, for A you are right

@ST3 2013-07-30 07:31:55

@rightfold I've been thinking about usual way of data distribution when all data is in heap and on stack it is just pointers to that data. It would be usual way, but I agree that it is possible to put pointers in stack.

@Martin Bonner 2018-03-22 09:12:31

"Of course int* and an int********** have the same size" - the standard doesn't guarantee that (although I know of no platform where it isn't true).

@Sachin Mhetre 2012-04-11 10:39:52

There is no limit. A pointer is a chunk of memory whose contents are an address.
As you said

int a = 10;
int *p = &a;

A pointer to a pointer is also a variable which contains an address of another pointer.

int **q = &p;

Here q is pointer to pointer holding the address of p which is already holding the address of a.

There is nothing particularly special about a pointer to a pointer.
So there is no limit on chain of poniters which are holding the address of another pointer.
ie.

 int **************************************************************************z;

is allowed.

@Mare Infinitus 2012-06-12 12:27:17

Every C++ developer should have heard of the (in)famous Three star programmer

And there really seems to be some magic "pointer barrier" that has to be camouflaged

Quote from C2:

Three Star Programmer

A rating system for C-programmers. The more indirect your pointers are (i.e. the more "*" before your variables), the higher your reputation will be. No-star C-programmers are virtually non-existent, as virtually all non-trivial programs require use of pointers. Most are one-star programmers. In the old times (well, I'm young, so these look like old times to me at least), one would occasionally find a piece of code done by a three-star programmer and shiver with awe. Some people even claimed they'd seen three-star code with function pointers involved, on more than one level of indirection. Sounded as real as UFOs to me.

@Jeff 2015-04-17 05:26:29

github.com/psi4/psi4public/blob/master/src/lib/libdpd/… and the like was written by a 4-star programmer. He's also a friend of mine and, if you read the code enough, you will understand the reason why it's worthy of 4 stars.

@kostmo 2012-05-07 03:59:57

Rule 17.5 of the 2004 MISRA C standard prohibits more than 2 levels of pointer indirection.

@Cole Johnson 2014-02-07 02:16:00

Pretty sure that's a recommendation for programmers, not for compilers.

@Francis Cugler 2017-11-24 04:48:43

I read the document with rule 17.5 about more than 2 levels of pointer indirection. And it doesn't necessarily prohibit more than 2 levels. It does state that the ruling should be followed as more than 2 levels is "non-compliant" to their standards. The important word or phrase in their ruling is the use of the word "should" from this statement: Use of more than 2 levels of indirection can seriously impair the ability to understand the behavior of the code, and should therefore be avoided. These are guidelines set by this organization as opposed to rules set by the language standard.

@P.P. 2012-04-10 10:45:00

The C standard specifies the lower limit:

5.2.4.1 Translation limits

276 The implementation shall be able to translate and execute at least one program that contains at least one instance of every one of the following limits: [...]

279 — 12 pointer, array, and function declarators (in any combinations) modifying an arithmetic, structure, union, or void type in a declaration

The upper limit is implementation specific.

@James Kanze 2012-04-10 10:52:03

The C++ standard "recommends" that an implementation support at least 256. (Readability recommends that you not exceed 2 or 3, and even then: more than one should be exceptional.)

@Kaz 2012-04-10 11:37:51

This limit is about how many in a single declaration; it does not impose an upper bound on how much indirection you can achieve via multiple typedefs.

@luis.espinal 2012-04-10 16:00:55

@Kaz - yes, that is true. But since the spec is (no pun intended) specifying a mandatory lower limit, it is the effective upper bound all spec-compliant compilers are required to support. It could be lower than the vendor-specific upper bound, of course. Rephrased differently (to align it with the OP's question), it is the maximum allowed by the spec (anything else would be vendor-specific.) A bit off the tangent, programmers should (at least in the general case) treat that as their upper limit (unless they have a valid reason to rely on a vendor-specific upper bound)... me thinks.

@luis.espinal 2012-04-10 16:03:49

On another note, I would start to cut myself if I had to work with code that had long-ass dereferencing chains (specially when liberally peppered all over the place.)

@beryllium 2012-04-13 08:00:06

ok, but why exactly 12? Why not 5 or 40. Is there some explanation for this?

@user79758 2012-04-15 14:48:34

@beryllium: Usually these numbers come from taking a survey of pre-standardization software. In this case presumably they looked at common C programs and existent C compilers, and found at least one compiler that would have trouble with more than 12 and/or no programs that broke if you restricted it to 12.

@Suraj Jain 2016-08-24 13:02:03

I don't understand why a answer get more upvotes just because the writer has more reputation. This way answers which are actually good but by low reputation are hided.This answer was not as much constructive , but its upvotes are massive. Above Sachin Mhetra Answer was good but has so low upvotes.

@P.P. 2016-08-26 09:34:17

@SurajJain When I posted my answer my rep was about 1500. All the existing answers were all wrong at that time. Hence, it got many upvotes. Later on, others edited their answers and/or improved after I posted my answer. You can see this from the edit history and time stamps of the answers. For example, see Alok Save's initial answer from the edit history, which was competely wrong.

@Suraj Jain 2016-08-26 18:08:52

@P.P. Still , sachin mehra answer was constructive and i saw its edit history , no massive change, you jut posted some standard not explaining in your words , and it has above 300 upvotes .Maybe because OP did not asked why and just ask what is the upper limit and best way to tell is show the standard , but it would be nicer if you would explain reasoning also. Like Theoretically And Practically , down mihai user checked it, and showed what is limit and it is implementation specific , all these things in one answer makes it deserving for all those upvote ,not just referring to the standard.

@P.P. 2016-08-27 16:01:44

@SurajJain If it's not upto what your standard, you can post a better answer. If you are concerned about "deservedness" of upvotes you can flag it to a moderator and explain the right number of upvotes this should have and see if they can help you.

@Nandkumar Tekale 2012-04-10 10:37:38

There is no limit, check example here.

The answer depends on what you mean by "levels of pointers." If you mean "How many levels of indirection can you have in a single declaration?" the answer is "At least 12."

int i = 0;

int *ip01 = & i;

int **ip02 = & ip01;

int ***ip03 = & ip02;

int ****ip04 = & ip03;

int *****ip05 = & ip04;

int ******ip06 = & ip05;

int *******ip07 = & ip06;

int ********ip08 = & ip07;

int *********ip09 = & ip08;

int **********ip10 = & ip09;

int ***********ip11 = & ip10;

int ************ip12 = & ip11;

************ip12 = 1; /* i = 1 */

If you mean "How many levels of pointer can you use before the program gets hard to read," that's a matter of taste, but there is a limit. Having two levels of indirection (a pointer to a pointer to something) is common. Any more than that gets a bit harder to think about easily; don't do it unless the alternative would be worse.

If you mean "How many levels of pointer indirection can you have at runtime," there's no limit. This point is particularly important for circular lists, in which each node points to the next. Your program can follow the pointers forever.

@James Kanze 2012-04-10 11:12:44

There's almost certainly a limit, since the compiler has to keep track of the information in a finite amount of memory. (g++ aborts with an internal error at 98242 on my machine. I expect that the actual limit will depend on the machine and the load. I also don't expect this to be a problem in real code.)

@Nandkumar Tekale 2012-04-10 11:20:42

Yeah @MatthieuM. : I just considered theoretically :) Thanks James for completing answer

@Random832 2012-04-10 13:58:36

Well, linked lists aren't really a pointer to a pointer, they're a pointer to a struct that contains a pointer (either that or you end up doing a lot of unnecessary casting)

@Nandkumar Tekale 2012-04-10 14:11:10

@Random832 : Yeah! but don't you think it is well structured?

@LarsH 2012-04-10 15:46:45

@Random832: Nand said 'If you mean "How many levels of pointer indirection can you have at runtime,"' so he was explicitly removing the restriction of just talking about pointers to pointers (*n).

@Alberto 2012-04-11 14:18:11

I don't get your point: 'There is no limit, check example here.' The example is no proof that there is no limit. It only proves that a 12 star indirection is possible. Neither proves anything the circ_list example regarding the OP's question: The fact that you can traverse a pointers list doesn't imply that the compiler can compile a n-stars indirection.

@Nandkumar Tekale 2012-04-11 14:40:52

I mean, There is no limit and for more info check that example. Think on circ_list example.

@mihai 2012-04-10 18:36:16

Sounds fun to check.

  • Visual Studio 2010 (on Windows 7), you can have 1011 levels before getting this error:

    fatal error C1026: parser stack overflow, program too complex

  • gcc (Ubuntu), 100k+ * without a crash ! I guess the hardware is the limit here.

(tested with just a variable declaration)

@Kaz 2012-04-10 19:15:19

Indeed, the productions for unary operators are right-recursive, which means that a shift-reduce parser will shift all of the * nodes onto the stack before being able to make a reduction.

@Alok Save 2012-04-10 10:35:59

Theoretically:

You can have as many levels of indirections as you want.

Practically:

Of course, nothing that consumes memory can be indefinite, there will be limitations due to resources available on the host environment. So practically there is a maximum limit to what an implementation can support and the implementation shall document it appropriately. So in all such artifacts, the standard does not specify the maximum limit, but it does specify the lower limits.

Here's the reference:

C99 Standard 5.2.4.1 Translation limits:

— 12 pointer, array, and function declarators (in any combinations) modifying an arithmetic, structure, union, or void type in a declaration.

This specifies the lower limit that every implementation must support. Note that in a footenote the standard further says:

18) Implementations should avoid imposing fixed translation limits whenever possible.

@Basile Starynkevitch 2012-04-10 10:37:37

indirections don't overflow any stacks!

@Péter Török 2012-04-10 10:38:09

How does the stack relate to pointer indirection?

@Alok Save 2012-04-10 10:39:28

Corrected, I had this errie feeling of reading & answering the q as limit of parameters being passed to the function. I don't know why?!

@Steve314 2012-04-11 00:14:39

@basile - I'd expect stack-depth to be an issue in the parser. Many formal parsing algorithms have a stack as a key component. Most C++ compilers probably use a variant of recursive descent, but even that relies on the processor stack (or, pedantically, on the language acting as if there was a processor stack). More nesting of grammar rules means a deeper stack.

@Pavan Manjunath 2012-04-11 07:15:14

indirections don't overflow any stacks!--> No! parser stack can overflow. How does the stack relate to pointer indirection? Parser stack!

@Nawaz 2012-05-27 05:10:52

If * is overloaded for a number of classes in a row, and each overload returns an object of other type in the row, then there can be stackoverflow for such chained function calls.

@Grijesh Chauhan 2013-07-03 08:03:40

@PéterTörök may be stack matter while compiler parse an expression consist of many *s

@supercat 2018-08-15 19:16:16

From a practical perspective, the translation limits are at best recommendations, since the Standard says nothing about what combinations of limits must be supported. Many real-world implementations would die if code tried to include the maximum allowable number of parameters and automatic objects in a function, and they all took 32767 bytes each. On the other hand, nothing in the Standard would forbid a conforming-but-useless implementation from saying that no function can both contain more than one automatic object and have any automatic object which is larger than one byte in size.

@supercat 2018-08-15 19:20:29

The authors of the Standard acknowledged the possibility of conforming-but-useless implementations, but expected that (1) people making a bona fide effort to produce a usable implementation won't do stupid things merely because the Standard would allow them to, and (2) it wasn't worth worrying about what kinds of compilers might be produced by people who weren't making such an effort.

@Kaz 2012-04-10 15:44:27

Actually, C programs commonly make use of infinite pointer indirection. One or two static levels are common. Triple indirection is rare. But infinite is very common.

Infinite pointer indirection is achieved with the help of a struct, of course, not with a direct declarator, which would be impossible. And a struct is needed so that you can include other data in this structure at the different levels where this can terminate.

struct list { struct list *next; ... };

now you can have list->next->next->next->...->next. This is really just multiple pointer indirections: *(*(..(*(*(*list).next).next).next...).next).next. And the .next is basically a noop when it's the first member of the structure, so we can imagine this as ***..***ptr.

There is really no limit on this because the links can be traversed with a loop rather than a giant expression like this, and moreover, the structure can easily be made circular.

Thus, in other words, linked lists may be the ultimate example of adding another level of indirection to solve a problem, since you're doing it dynamically with every push operation. :)

@fluffy 2012-04-11 17:22:54

That's a completely different issue, though - a struct containing a pointer to another struct is very different than a pointer-pointer. An int***** is a distinct type from an int****.

@Kaz 2012-04-11 18:28:32

It is not "very" different. The difference is fluffy. It is closer to syntax than semantics. A pointer to a pointer object, or a pointer to a structure object which contains a pointer? It's the same kind of thing. Getting to the tenth element of a list is ten levels of addressing indirection. (Of course, the ability to express an infinite structure depends on the struct type being able to point to itself via the incomplete struct type so that list->next and list->next->next are the same type; otherwise we would have to construct an infinite type.)

@Kaz 2012-04-11 18:29:27

I didn't consciously notice that your name is fluffy when I used the word "fluffy". Subsconscious influence? But I am sure I have used the word in this way before.

@nitro2k01 2012-04-11 22:01:03

Hmmm! I'm not sure this is really an infinite pointer indirection. Semantically speaking you're dealing with only one type (struct list *) and only one pointer is dereferenced at a time, each padded by an "almost no op". (As has already been practically pointed out, but hey.)

@Kaz 2012-04-11 22:04:55

In C, one pointer is dereferenced at a time no matter what. You cannot dereference the next pointer until you load the previous one. *******x is one at a time, exactly like x->next->next->next->next.

@Kaz 2012-04-12 03:56:28

Also remember that in machine language, you could just iterate on something like LOAD R1, [R1] as long as R1 is a valid pointer at every step. There are no types involved other than "word which holds an address". Whether or not there are declared types doesn't determine the indirection and how many levels it has.

@Agnius Vasiliauskas 2012-04-19 10:44:39

+1. But in the strict sense - for having infinite number of indirections - we must have infinite address space, which isn't the case.

@Kaz 2012-04-19 19:11:08

Not if the structure is circular. If R1 holds the address of a location which points to itself then LOAD R1, [R1] can be executed in an infinite loop.

@Bryan 2014-04-30 09:28:22

This answer is not answering the question asked, which is about declarations.

@Kaz 2014-04-30 17:51:43

@Bryan it certainly is about a declarations. The struct declaration is self-referential ("I contain a pointer to myself"), something which C painstakingly allows via the incomplete struct type mechanism. This creates an infinite level of pointer indirection.

@TripeHound 2015-07-20 13:03:07

@Kaz the point is that traversal of a long chain of ->next elements is controlled by the programmer; to handle *****....*****int the compiler has to internally represent the depth of the pointers (so it can detect incorrect dereferencing). Some ways of storing this representation may only be limited by memory (used by the compiler) but some methods may have hard limits.

@Kaz 2015-07-21 14:23:11

@TripeHound P->memb and *P are both syntax. How deeply that syntax is nested is controlled by the programmer. The compiler has to represent P->memb->memb->memb->memb... and it has to represent ***..P.

@TripeHound 2015-07-21 14:31:14

There is a difference, mainly during compilation. For P->next that happens to point to another P, the compiler only needs to know that it is a pointer to the parent structure. At compile time it doesn't care how long a string of linked elements you create at runtime. For *****int, the compiler at compile time has to represent the type for every level ... that is *****int is a pointer to a ****int which points to ***int ... to a *int which finally points to an int. For some compilers, under some conditions, it may run out of space to do so.

@Kaz 2015-07-21 16:25:27

@TripeHound You can get avoid constructing a deep static type by using something like DEREFI(DEREFV(DEREFV...(DEREFV(P)) ...)) where P is a void * pointer, DEREFV is #define DEREFV(P) (*((void **) (P))) and DEREFI is similar, but with a cast to int *. I.e. an arbitrarily long chain of void * pointers that point to void *, and finally an int.

@Matthieu M. 2012-04-10 14:16:47

It's actually even funnier with pointer to functions.

#include <cstdio>

typedef void (*FuncType)();

static void Print() { std::printf("%s", "Hello, World!\n"); }

int main() {
  FuncType const ft = &Print;
  ft();
  (*ft)();
  (**ft)();
  /* ... */
}

As illustrated here this gives:

Hello, World!
Hello, World!
Hello, World!

And it does not involve any runtime overhead, so you can probably stack them as much as you want... until your compiler chokes on the file.

@BoBTFish 2012-04-10 11:12:01

As people have said, no limit "in theory". However, out of interest I ran this with g++ 4.1.2, and it worked with size up to 20,000. Compile was pretty slow though, so I didn't try higher. So I'd guess g++ doesn't impose any limit either. (Try setting size = 10 and looking in ptr.cpp if it's not immediately obvious.)

g++ create.cpp -o create ; ./create > ptr.cpp ; g++ ptr.cpp -o ptr ; ./ptr

create.cpp

#include <iostream>

int main()
{
    const int size = 200;
    std::cout << "#include <iostream>\n\n";
    std::cout << "int main()\n{\n";
    std::cout << "    int i0 = " << size << ";";
    for (int i = 1; i < size; ++i)
    {
        std::cout << "    int ";
        for (int j = 0; j < i; ++j) std::cout << "*";
        std::cout << " i" << i << " = &i" << i-1 << ";\n";
    }
    std::cout << "    std::cout << ";
    for (int i = 1; i < size; ++i) std::cout << "*";
    std::cout << "i" << size-1 << " << \"\\n\";\n";
    std::cout << "    return 0;\n}\n";
    return 0;
}

@James Kanze 2012-04-10 11:31:38

I couldn't get more than 98242 when I tried it. (I did the script in Python, doubling the number of * until I got one that failed, and the preceding one that passed; I then did a binary search over that interval for the first one that failed. The whole test took less than a second to run.)

@Kaz 2012-04-10 11:41:37

Note that there are two possible questions here: how many levels of pointer indirection we can achieve in a C type, and how many levels of pointer indirection we can stuff into a single declarator.

The C standard allows a maximum to be imposed on the former (and gives a minimum value for that). But that can be circumvented via multiple typedef declarations:

typedef int *type0;
typedef type0 *type1;
typedef type1 *type2; /* etc */

So ultimately, this is an implementation issue connected to the idea of how big/complex can a C program be made before it is rejected, which is very compiler specific.

Related Questions

Sponsored Content

27 Answered Questions

[SOLVED] How do you set, clear, and toggle a single bit?

10 Answered Questions

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

76 Answered Questions

[SOLVED] How do I iterate over the words of a string?

  • 2008-10-25 08:58:21
  • Ashwin Nanjappa
  • 2108663 View
  • 2829 Score
  • 76 Answer
  • Tags:   c++ string split

13 Answered Questions

[SOLVED] What is a smart pointer and when should I use one?

12 Answered Questions

[SOLVED] What exactly is nullptr?

20 Answered Questions

[SOLVED] Can a local variable's memory be accessed outside its scope?

21 Answered Questions

[SOLVED] Why should I use a pointer rather than the object itself?

  • 2014-03-03 11:54:16
  • gEdringer
  • 284085 View
  • 1468 Score
  • 21 Answer
  • Tags:   c++ pointers c++11

34 Answered Questions

17 Answered Questions

[SOLVED] Why use pointers?

  • 2008-10-02 15:19:20
  • Anonymous
  • 214919 View
  • 323 Score
  • 17 Answer
  • Tags:   c++ c pointers

28 Answered Questions

[SOLVED] What are the barriers to understanding pointers and what can be done to overcome them?

  • 2008-08-08 06:17:51
  • David McGraw
  • 72323 View
  • 443 Score
  • 28 Answer
  • Tags:   c++ c pointers

Sponsored Content