-1

I know that int *p is a pointer but what does int **p mean exactly? What type of value is that? When I say now p= something, how is that working? I am seeing this in the creation of two-dimensional arrays with pointers.

rayo7
  • 13
  • 4
  • Welcome to Stack Overflow! Please take the [tour] (you get a badge!), have a look around, and read through the [help], in particular [*How do I ask a good question?*](/help/how-to-ask) I also recommend Jon Skeet's [Writing the Perfect Question](https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/) and [Question Checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – T.J. Crowder Dec 02 '21 at 08:32
  • 2
    This should be covered by any decent C tutorial or course. As you say, `int *` is a pointer to `int`. `int **` is a pointer to a pointer to `int`. (`int ***` is a pointer to a pointer to a pointer to `int`, and so on.) – T.J. Crowder Dec 02 '21 at 08:34
  • @T.J Crowder as far as I know the process of a pointer is to store the adress of another variable so you can acces the variable with *p and change its value from the pointer. But I don't understand how **p works, could you explain me how would be an example or the process please? It is really confusing – rayo7 Dec 02 '21 at 08:37
  • 2
    Can you clarify (i.e. show us some code) what you mean with "I am seeing this in the creation of two-dimensional arrays with pointers."? – Allan Wind Dec 02 '21 at 08:47

2 Answers2

2

In short, int **p; is a pointer to a pointer to an int. So, for example:

  int i, j;      // Integers;
  int *p = &i;   // Pointer to i
  *p = 1;        // i is now 1
  int *q = &j;   // Pointer to j
  int **s = &p;  // Pointer to p
  **s = 2;       // i is now 2
  s = &q;        // s now points to q (pointing to j)
  **s = 16;      // j is now 16
  s = &p;        // s now points to p (pointing to i)
  **s = 3;       // i is now 3
  p = &j;        // p now points to j
  **s = 17;      // j is now 17

One use case for a pointer to pointer could be a function which needs to output a pointer to an int and return a success/failure status:

  #include <stdbool.h>

  bool getIntHandle(unsigned handleId, int **handle)
  {
     static int handles[] = {12, 23, 34, 45};

     bool success = (handleId < sizeof(handles)/sizeof(handles[0])); // Check that handleId is in range
     if(success)
     {
         *handle = &handles[handleId];
     }
     return success;
  }

  int main(void)
  {
      int *handle;
      bool success = getIntHandle(2, &handle); // Get a pointer to the integer at index 2
      printf("*handle = %d\n", *handle);
      return 0;
  }
nielsen
  • 5,641
  • 10
  • 27
  • 1
    By the way, `int **p` could be used for 2D arays because you can interpret `*p` like a pointer to an `int` array, so `**p` points to array of arrays of `int`. – tony_merguez Dec 02 '21 at 08:44
  • That is not the same as this? Int *p int *s int i p=&i s=p *s=2 and now i=2. Why Can't i do that? – rayo7 Dec 02 '21 at 08:46
  • @rayo7 - First, it's really hard to read that code without any `;` (and please use backticks around code in comments). Second, what is `y` in that code? It appears out of nowhere in `p = &y;`. – T.J. Crowder Dec 02 '21 at 08:49
  • @rayo7 your example is confusing, : in `p = &y`, `y` isn't defined. – tony_merguez Dec 02 '21 at 08:49
  • @rayo7 If you mean `p=&i;` (and add `;`s), then your example should be fine. – nielsen Dec 02 '21 at 08:50
  • @rayo7 of course you can do that, but `p` and `s` are used for the same purpose, so they are duplicated. – tony_merguez Dec 02 '21 at 08:52
  • Yes I mean that, so if that is fine what is the pointe of using **s? Also I dont understand the line of **s=&p. I don't understand because p is an adress because it is a pointer, and the & is to access an adress so you are accessing the adress of an adress.. I don't understand – rayo7 Dec 02 '21 at 08:53
  • @rayo7 Pointer to pointers are not needed very often. I will try to add an example in the answer. – nielsen Dec 02 '21 at 08:55
  • @rayo7 `**s` is a pointer which points to a pointer. `p` stores an adress (pointed value), `&p` is where this adress is stored. But you're not allowed to write `int * s = &p;`. If you don't understand why because you think `&p` is anyway an adress so it can also be stored in a simple pointer, you're wrong. I am sorry for not having the adequate words to explain you why, but what you're writing have a concrete meaning for the compiler. The compiler will allow you writing `*p` but not writing `**p`, and that will be what you will trying to do if you write `int * s = &p. – tony_merguez Dec 02 '21 at 09:01
  • I have to see a clear example, when was p defined? Is it int *p? p is not an adress itself because it is a pointer or is something that can store an adress? This is why it is confusing me to acces the adress os a pointer because i think that a pointer is an adress by itself so what is the reason of accesing the adress of a pointer if a pointer is an adress already? Sl ylu are accesing the adress of an adress? – rayo7 Dec 02 '21 at 09:16
  • @rayo7 `s` and `p` both store an address. The difference is that `p` stores the address of an `int` while `s` stores the address of another address (which is then the address of an `int`). So even though they are both addresses, C also needs to keep track of which data type the addresses are pointing to know the resulting data type when a pointer is dereferenced. I.e., it must know that `*s` is an address while `*p` is an integer such that expressions can be interpreted correctly... – nielsen Dec 02 '21 at 09:23
  • ... e.g. `(*s)++` means "increase the pointer that `s` points to such that it points to the next integer" while `(*p)++` means "increase the integer that `p` points to". – nielsen Dec 02 '21 at 09:24
1

p is a pointer to a pointer to an int. It's the type int **p and the variable p stores an address.

Here is an example of its use. p is an array of two integer pointers. The first of the pointers p[0] points to an array of 3 integers, and the 2nd to an array of 4 integers (combined this is known as ragged array):

#include <stdio.h>
#include <stdlib.h>

int main() {
    int **p = malloc(2 * sizeof(int *));
    printf("p = %p\n", p);

    p[0] = malloc(3 * sizeof(int));
    printf("p[0] = %p\n", p[0]);
    p[0][0] = 0;
    p[0][1] = 1;
    p[0][2] = 2;

    p[1] = malloc(4 * sizeof(int));
    printf("p[1] = %p\n", p[1]);
    p[1][0] = 3;
    p[1][1] = 4;
    p[1][2] = 5;
    p[1][3] = 6;

    free(p[0]);
    free(p[1]);
    free(p);
    return 0;
}

The most common use, however, is with a regular 2d array that is passed to a function which degrades to a pointer to a pointer.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • But to store the adress in a pointer of other pointer it is not easier to maje int *p int *l and p=l? I am not understanding it :( – rayo7 Dec 02 '21 at 08:40
  • 1
    Using a 2d array here really makes your answer confusing. Not (yet) my downvote. – Jabberwocky Dec 02 '21 at 08:42
  • @Jabberwocky fair point, op mentioned "two-dimensional arrays with pointers." which was the only reason I brought it up. Added a better example, I think, but open to further feedback. – Allan Wind Dec 02 '21 at 09:28
  • @AllanWind OK, that makes more sense now. Upvoted. – Jabberwocky Dec 02 '21 at 10:37