简体   繁体   中英

Why pointer to pointer?

A very general question: I was wondering why we use pointer to pointer? A pointer to pointer will hold the address of a pointer which in turn will point to another pointer. But, this could be achieved even by using a single pointer.

Consider the following example:

{
  int number = 10;
  int *a = NULL;

  a = &number;

  int *b = a;

  int *pointer1 = NULL;
  pointer1 = b;  //pointer1 points to the address of number which has value 10

  int **pointer2 = NULL;
  pointer2 = &b;  //pointer2 points to the address of b which in turn points to the address of number which has value 10. Why **pointer2??

  return 0;
}

I think you answered your own question, the code is correct, what you commented isn't.

int number = 10; is the value

int *pointer1 = b; points to the address where int number is kept

int **pointer2 = &b; points to the address where address of int number is kept

Do you see the pattern here??

address = * (single indirection)

address of address = ** (double  indirection)

First of all, a pointer doesn't point to a value. It point to a memory location (that is it contains a memory address) which in turn contains a value. So when you write

pointer1 = b;

pointer1 points to the same memory location as b which is the variable number . Now after that is you execute

pointer2 = &b;

Then pointer2 point to the memory location of b which doesn't contains 10 but the address of the variable number

The following expressions are true:

*pointer2 == b 
**pointer2 == 10 

The following is not!

*pointer2 == 10 

Pointer to pointer can be useful when you want to change to what a pointer points to outside of a function. For example

void func(int** ptr)
{
    *ptr = new int;
    **ptr = 1337;
}

int main()
{
    int* p = NULL;
    func(&p);
    std::cout << *p << std::endl;   // writes 1337 to console
    delete p;
}

A stupid example to show what can be achieved :) With just a pointer this can not be done.

Your assumption is incorrect. pointer2 does not point to the value 10, but to the (address of the) pointer b . Dereferencing pointer2 with the * operator produces an int * , not an int .

You need pointers to pointers for the same reasons you need pointers in the first place: to implement pass-by-reference parameters in function calls, to effect sharing of data between data structures, and so on.

A simple example is an implementation of a matrix (it's an example, it's not the best way to implement matrices in C++).

int nrows = 10;
int ncols = 15;
double** M = new double*[nrows];
for(unsigned long int i = 0; i < nrows; ++i)
  M[i] = new double[ncols];
M[3][7] = 3.1416;

You'll rarely see this construct in normal C++ code, since C++ has references. It's useful in C for "passing by reference:"

int allocate_something(void **p)
{
  *p = malloc(whatever);
  if (*p)
    return 1;
  else
    return 0;
}

The equivalent C++ code would use void *&p for the parameter.

Still, you could imagine eg a resource monitor like this:

struct Resource;

struct Holder
{
  Resource *res;
};

struct Monitor
{
  Resource **res;

  void monitor(const Holder &h) { res = &h.res; }
  Resource& getResource() const { return **res; }
}

Yes, it's contrived, but the idea's there - it will keep a pointer to the pointer stored in a holder, and correctly return that resource even when the holder's res pointer changes.

Of course, it's a dangling dereference waiting to happen - normally, you'd avoid code like this.

In c such construction made sense, with bigger data structures. The OOP in C, because of lack of possibility to implement methods withing structures, the methods had c++ this parameter passed explicitly. Also some structures were defined by a pointer to one specially selected element, which was held in the scope global to the methods.

So when you wanted to pass whole stucture, Eg a tree, and needed to change the root, or 1st element of a list, you passes a pointer-to-a-pointer to this special root / head element, so you could change it.

Note: This is c-style implementation using c++ syntax for convienience.

void add_element_to_list(List** list, Data element){
  Data new_el = new Data(element); // this would be malloc and struct copy
  *list = new_el; //move the address of list, so it begins at new element
}

In c++ there is reference mechanismm and you generally you can implement nearly anything with it. It basically makes usage of pointers at all obsolete it c++, at least in many, many cases. You also design objects and work on them, and everything is hidden under the hood those two.

There was also a nice question lately "Why do we use pointers in c++?" or something like that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM