Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer to Pointer. How far we can go? [duplicate]

Tags:

c++

pointers

In C/C++ we know pointers. That is, a variable memory address.

say, this code bellow will not compile, but the idea is this:

#include <iostream>
using namespace std;

main() {
    int* pi;
    int i = 1;
    pi = &i;
    
    while (true) {
        cout<<"i = " << i++ << "; pi = " << pi;
        pi = &pi;
    }
}

how far can we go with the address of the address. Where is the "final address"?

int* pi = &i;
int** ppi = &pi;
int*** pppi = &ppi;
int**** ppppi = &pppi;
.....
like image 754
serge Avatar asked Oct 12 '20 08:10

serge


People also ask

What is the maximum level that we can create pointer to pointer?

This is called levels of pointers. According to ANSI C, each compiler must have at least 12 levels of pointers. This means we can use 12 * symbols with a variable name. Level of pointers or say chain can go up to N level depending upon the memory size.

Can you have a pointer to a pointer to a pointer?

A pointer to a pointer is a form of multiple indirection, or a chain of pointers. Normally, a pointer contains the address of a variable. When we define a pointer to a pointer, the first pointer contains the address of the second pointer, which points to the location that contains the actual value as shown below.

Can a pointer point to two addresses?

No, a single pointer can only point to one thing.

Is pointer faster than reference?

It's much faster and memory-efficient to copy a pointer than to copy many of the things a pointer is likely to point to. A reference is stored in as many bytes as required to hold an address on the computer. This often makes reference much smaller than the things they refer to.


3 Answers

There's no theoretical limit, but bear in mind:

  1. You cannot legally use pi = &pi;, since that's a strict aliasing violation. The behaviour on reading pi subsequent to that is undefined.

  2. The behaviour on reading or dereferencing a pointer that is not initialised is undefined.

  3. The behaviour on reading a pointer that used to point to valid memory but no longer does is indeterminate. But it is not undefined. So the fact that your pseudo code will produce an infinite number of dangling pointers is moot.

You could engineer a working example with templates by the way (which keeps all the pointers in scope), much in the way as you can implement a factorial function using templates.

like image 185
Bathsheba Avatar answered Nov 03 '22 07:11

Bathsheba


For fun, here's an example where you can generate long pointer types using templates. The compiler will generate types with hundreds of levels of indirection.

#include <iostream>

template<size_t N, typename T>
struct PointerVariable
{
    T* myPtr;
    PointerVariable<N - 1, T*> ptrToMyPtr;

    PointerVariable(T* p) :
        myPtr(p),
        ptrToMyPtr(&myPtr)
    {
        // display pointer value
        std::cout << "ptr:" << ((void*)myPtr) << std::endl;
    }
};

template<typename T>
struct PointerVariable<0, T>
{
    PointerVariable(T* p) {
        int a = 3.3; // generate a compiler warning so we can see the names of types
    }
};

int main()
{
    int val = 0;
    auto pp = PointerVariable<499, int>{ &val };
    return 0;
}

On MSVC++2019, this produces a compiler warning:

warning C4244: 'initializing': conversion from 'double' to 'int', possible loss of data
message : while compiling class template member function 'PointerVariable<0,T *>::PointerVariable(int ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************)'

And when N=500, a compiler error occurs:

fatal error C1202: recursive type or function dependency context too complex

Using an explicit type, VC++2019 allows 1491 levels of indirection:

int
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128

    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    ******************************************************************************************************************************** // 128
    **************************************************************** // 64
    **************** // 16
    *** // 3
    x = nullptr;

Adding one more pointer level emits:

fatal error C1026: parser stack overflow, program too complex

This is an exercise of the compiler's abilities regarding variable storage and type complexity. Ignoring these 2 limitations, for example by just working with uintptr_t instead of real pointer types, then your limitation is system memory.

like image 39
tenfour Avatar answered Nov 03 '22 08:11

tenfour


In this construction, there is no theoretical limit, since you take addresses of different variables:

int* pi = &i;
int** ppi = &pi;
int*** pppi = &ppi;
int**** ppppi = &pppi;
.....

You have a variable i. You have a variable pi that contains the address of i. You have a variable ppi that contains the address of the variable pi. You have a variable pppi that contains the address of the variable ppi. And so on. This can go indefinitely, although of course this is never needed in practice.

like image 33
printf Avatar answered Nov 03 '22 08:11

printf