45

I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:

int ** arr = NULL;

How can I know if:

  • arr is a pointer to a pointer of an integer

  • arr is a pointer to an array of pointers to integers

  • arr is a pointer to an array of pointers to arrays of integers

Isn't it all the same with int ** ?


Another question for the same problem:

If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
ChikChak
  • 936
  • 19
  • 44
  • 1
    Use `cdecl`: `cdecl> explain int** a;` -> `declare a as pointer to pointer to int`. – Antti Haapala -- Слава Україні Feb 06 '17 at 10:20
  • 18
    Only one of you above statements is true for `int ** arr`: "*arr is a pointer to a pointer of an integer*" The other two are simply wrong. – alk Feb 06 '17 at 10:30
  • @alk So whats the syntax for the other two? – ChikChak Feb 06 '17 at 10:32
  • 4
    @MooingDuck: I'd appreciate you'd pointed out where I am doing wrong. – alk Feb 06 '17 at 11:33
  • 1
    @alk - If you simplify this to `int* a`, do you know if it points to a single integer, or to an array of integers? – Bo Persson Feb 06 '17 at 11:42
  • 5
    I think alk is referring to the difference between `int **p` (pointer-to-pointer) and `int (*p)[3]` (pointer-to-array of length 3): http://stackoverflow.com/questions/25080413/difference-between-pointer-to-pointer-and-pointer-to-2d-array – Klas Lindbäck Feb 06 '17 at 11:46
  • 7
    @BoPersson I think you are wrong here. `int* a` points to a single integer - always. That you can use pointer arithmetic to access consecutive laid out integers does not change the fact that `int* a` is a pointer to a single integer. It is never ever a pointer to an array. – Support Ukraine Feb 06 '17 at 12:23
  • 1
    @4386427 Well,using `int *`is also how they taught us to declare an array of integers,and also a pointer to an integer... – ChikChak Feb 06 '17 at 12:27
  • 2
    @MooingDuck: They are completely correct and no way missleading. It all becomes clear if one understands that the index-operator only works on pointers. – too honest for this site Feb 06 '17 at 12:28
  • @TakaTiki - How would you declare an `array of int` using `int*` ? – Support Ukraine Feb 06 '17 at 12:32
  • @4386427 First ` int * a =NULL;` later using malloc - `(int*) malloc(sizeof( int*) *size_of_array)) ;` (Of course size_of_array is some other integer) – ChikChak Feb 06 '17 at 12:34
  • @4386427 But does it matter if it works? Or it may cause problems? – ChikChak Feb 06 '17 at 12:44
  • 5
    @TakaTiki - As long as it works, it doesn't matter. It is just that the terminology is very confusing. Your dynamic allocation may look exactly as a 1D array - still your `a` is **not** an array - it is a pointer to int. The difference becomes more visible when you want to dynamic allocate a 2D array. Here you will soon see that `int** a` is nothing like `int a[4][4]`. – Support Ukraine Feb 06 '17 at 13:15
  • @4386427 I actually don't see what's the difference between int**a and int a[4][4]... – ChikChak Feb 06 '17 at 14:00
  • 1
    @TakaTiki: `int ** a;` allocates a pointer variable (4 or 8 bytes, depending on the platfom). `int a[4][4];` allocates 4*4 `int`s which makes `16 * sizeof (int)` bytes. – alk Feb 06 '17 at 14:48
  • Referring [the question in your other comment](http://stackoverflow.com/questions/42065293/differences-when-using-in-c#comment71302553_42065293): "*`arr` is a pointer to an array 3 of pointers to integers*": `int *(*arr)[3]` and "*`arr` is a pointer to an array 3 of pointers to arrays 5 of integers*": `int (*(*arr)[3])[5]` – alk Feb 06 '17 at 17:13
  • 1
    Don't edit with a new question.... ask a new question, so that all answers are about the original question, and the new question is treated properly. – woliveirajr Feb 06 '17 at 18:58
  • @woliveirajr But it is another question about the exact problem – ChikChak Feb 06 '17 at 19:03
  • I've made an edit to clarify what *you all knew perfectly well* he meant by the "array" cases. Any one of you could have explained it instead of falling over each other to correct him on a terminology nitpick. – Random832 Feb 06 '17 at 19:20
  • @Olaf: `int*` is a pointer to zero or more integers. Not 1 integer. `int* a = nullptr;` proves the point. `int&` is a reference to a single integer. – Mooing Duck Feb 06 '17 at 19:54
  • 1
    @MooingDuck: `nullptr` is not a C keyword. C is not C++. And `int *` points to an `int` (which is a specific integer type, as a sidenote). A _null pointer_ does not point **anywhere** by definition, it does not point to zero `int`s. – too honest for this site Feb 06 '17 at 19:59
  • @Olaf: In the same comment, you said that `int*` points to an `int` and that it can point nowhere. Those are contradictory. – Mooing Duck Feb 06 '17 at 20:21
  • @MooingDuck: Point taken. I should have written "either nowhere" or to a single `int`. – too honest for this site Feb 06 '17 at 20:41
  • 1
    @Random832: Your edit changed the semantics of the question, which is not acceptable. The "nit-picks" as you call them are actually the essence of the question. Edits should not go that far, please rool back. – too honest for this site Feb 06 '17 at 20:44
  • @Olaf No, it did not. It's absolutely clear that what I edited it to say is what he actually meant, and the accepted answer entirely avoids semantic nitpicking and answers the question the OP intended. When someone talks about `int *` as "pointer to array", bringing in `int (*)[3]` is not helpful at all, since that is not the type of the pointer you get when an array of ints decays. – Random832 Feb 06 '17 at 21:30
  • 4
    @Random832: It is not. But a pointer to array nevertheless has its uses and OP should be aware of it. And a "pointer to array" **is** `int (*)[N]`. That is not nit-picking, but being precise. Being inexact here just adds to confusion instead of clarifying. And your change of the terms does not help at all. The comments are very helpful if understood correctly. – too honest for this site Feb 06 '17 at 21:57
  • " Being inexact here just adds to confusion instead of clarifying. And your change of the terms does not help at all" - This is a contradiction. I changed the terms to be more precise, to reflect what OP actually meant, which was absolutely not `int (*)[N]`. It was "inexact" _before_. – Random832 Feb 06 '17 at 22:19
  • Possible duplicate: [Correctly allocating multi-dimensional arrays](http://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays). Proof-reading is welcomed! – Lundin Feb 07 '17 at 16:04
  • The accepted answer by StoryTeller is just *wrong*. `arr` is a pointer to a pointer to an int. That int might be one of a sequence of ints that collectively make up all or some of an array. But that does not make `arr` a pointer to an array. People might sloppily call a pointer to the first element of an array a pointer to an array, but sloppiness like that is why you are confused. There are expressions that are of type pointer to array, although they don't ever have associated values, because they "decay" to expressions that are of type pointer to the first element of the array. – philipxy Mar 23 '17 at 02:15
  • PS `int *` does *not* "declare an array of integers". `int [C]` not as a parameter declares an array (of size C) of ints. `int *` or `int [C]` as a parameter each declare a pointer to an int, which might be one of a sequence of ints that are part of an array of ints. – philipxy Mar 23 '17 at 03:24

11 Answers11

44

Isn't it all the same with int **?

You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.

The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.


I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).

What I originally wrote refers to code as follows:

void func(int **p_buff)
{
}

//...

int a = 0, *pa = &a;
func(&pa);

//...

int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);

//...

int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
  a[i] = malloc(i * sizeof *a[i]);
func(a);

Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 29
    "*Every option you specified can be true.*" well, well, no. Just one: "*pointer to pointer to `int`*". – alk Feb 06 '17 at 10:36
  • @alk - A pointer to a pointer to `int` cannot point in effect to each of the options the OP listed? The question wasn't about the static type of `arr`, otherwise the silly suggestion of using `cdecl` would have sufficed. – StoryTeller - Unslander Monica Feb 06 '17 at 10:53
  • 7
    Actually it can't, because a pointer to pointer is not a compatible type with array pointers. It can however be used to emulate a 2D array through a look-up table, which is questionable practice most of the time. – Lundin Feb 06 '17 at 10:56
  • 12
    @Lundin - An array of pointers will decay to a pointer to a pointer. In essence, it points to the first element of the array, which according to the standard shares an address with the entire array. Heck, indexing cannot even be done on arrays (it must decay to a pointer first). The standard goes to great lengths to conflate the two as much as it can get away with. So what discernible difference is there? – StoryTeller - Unslander Monica Feb 06 '17 at 11:00
  • 1
    @Lundin: _because a pointer to pointer is not a compatible type with array pointers_, yes it is, do you mean is not compatible with a 2D array? – David Ranieri Feb 06 '17 at 11:12
  • 2
    "An array of pointers will decay to a pointer to a pointer" - no. It does not decay for 3 specific operators. – too honest for this site Feb 06 '17 at 13:07
  • 1
    @KeineLust It is not! An array is not a pointer, see my other comment ^ – too honest for this site Feb 06 '17 at 13:08
  • @Olaf: By array pointers I understand an array of pointers like `int *arr[3]` and it is compatible with `int **pptr` – David Ranieri Feb 06 '17 at 13:15
  • 3
    @KeineLust: 1) If it was compatible, for `int **p, *a[10];` `sizeof(p) == sizeof(a)` would be guaranteed true. It is not! 2) `int *a[10]` is an array **of** pointers, not an array-pointer (note that in English you typically omit the `-`). – too honest for this site Feb 06 '17 at 13:19
  • @Olaf Oops, then an array of pointers does not mean an array-pointer, then I stand corrected, thanks, and by compatible I understand interchangeable (not with the same sizeof) , my bad – David Ranieri Feb 06 '17 at 13:25
  • 2
    @they are also not interchangeable. Just drop that idea, it just makes understanding pointers and arrays much more complicated. Concentrate on the fact that an array decays for all but 3 operators to a pointer to the first element. This includes the index-operator – too honest for this site Feb 06 '17 at 13:28
  • 2
    @Olaf *"It does not decay for 3 specific operators."* - You are most certainly correct, but having to drag that qualification into *every* mention of arrays decaying into pointers is quite cumbersome, even when trying to be precise. My answer purposefully focused on passing buffers into functions, and my comment about indexing, since the decay certainly happens there. – StoryTeller - Unslander Monica Feb 06 '17 at 13:31
  • 2
    @StoryTeller: Nobody had stack overflow in mind when arrays and pointers were designed in the C language. That does not justify giving incomplete or missleading answers. Especially if you consider how many questions result from errors when getting the `sizeof` an "array"-parameter inside a function. Just as I was writing this, a new one popped up: http://stackoverflow.com/questions/42069055/chararray-size-and-length-are-not-the-same – too honest for this site Feb 06 '17 at 13:48
  • 3
    @Olaf - That's quite patronizing. Nowhere was I misleading. I didn't conflate pointers with array-pointers at any point, and constrained by answer to what I deemed important in the question, so I do not feel obligated to drag the entirety of the standards many mentions of arrays and pointers into this. If you disagree, your critique has been noted, and you are free to post your own answer. – StoryTeller - Unslander Monica Feb 06 '17 at 13:56
  • 2
    @StoryTeller: If your answer was seriously missleading, I had downvoted it, which I did not. Yet only the first option indeed **is** true. Feel free to downvote the other, correct answers for "patronizing". – too honest for this site Feb 06 '17 at 14:02
  • 2
    @Olaf - I'll chalk it up to assuming English not being a first language for either of us, and the difficulty of discerning intent over online written communication, but the *that* I referred to is *"Nobody had stack overflow in mind when arrays and pointers were designed in the C language."*, and not the information you presented. Your delivery is patronizing, not the other answers. – StoryTeller - Unslander Monica Feb 06 '17 at 14:08
  • 3
    @StoryTeller: Ok then. I took it for the whole comment. Not as a retoure, but your initial comment read as if you think some minor incorrectnesses would be acceptable. From the new question I linked you can see they are not. Compilers **are** the worst nit-pickers, so it is right to be most exact here, too. – too honest for this site Feb 06 '17 at 14:13
  • Typo here: `int a[3][10]; int *a[3] = { a[0], a[1], a[2] };` right? – alk Feb 06 '17 at 17:22
  • @alk Arrgh I knew I made a typo, but was too coffee deprived to see it. Thank you! – StoryTeller - Unslander Monica Feb 06 '17 at 18:20
  • NP! Thanks for adjusting. I thought about correcting it myself ... - you would have minded this? – alk Feb 06 '17 at 19:44
  • @alk Depends on the extent. I always welcome typo and minor corrections. Anything more major and I usually prefer a comment first. – StoryTeller - Unslander Monica Feb 06 '17 at 19:47
27

The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...


Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:

cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]

In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring

void func(int (*a)[10]);

one could use

void func(int a[][10])

to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.

  • 3
    Pointers to arrays are not obscure. They are the only way to pass multidimensional arrays. – too honest for this site Feb 06 '17 at 13:01
  • @Olaf well ok then, but perhaps pointers to arrays to pointers are obscure :D – Antti Haapala -- Слава Україні Feb 06 '17 at 13:27
  • @AnttiHaapala: Indeed. For the vast majority of code, such complicated constructs signal a bad interface design. One reason is exactly that the pointers fon't have length-information. Passing it for each dimension always along the call-tree is problematic at best, thus one would use `struct`s in-between. For "pointers to arrays of pointers", one either would use a 2D array (equal lengths for all "inner" arrays) or pointer to array of `struct { length, pointer to data} or pointer to `struct` of the latter. – too honest for this site Feb 06 '17 at 13:33
9

How can I know if :

  • arr is a pointer to a pointer of an integer

It is always a pointer to pointer to integer.

  • arr is a pointer to an array of pointers to integers
  • arr is a pointer to an array of pointers to arrays of integers

It can never be that. A pointer to an array of pointers to integers would be declared like this:

int* (*arr)[n]

It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and ( with detailed explanation about array pointers) here.

EDIT

Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Why?Is it wrote to write that line,and later use malloc ,and refer it as a pointer to an array of pointers?this is how they taught us.. – ChikChak Feb 06 '17 at 11:20
  • 4
    "It can never be that" and "it is incorrect practice" are very different things. If you are *writing* code, they are nearly equivalent; if you are *reading* code, you need to be aware that *the person who wrote the code may have done it wrong*. – IMSoP Feb 06 '17 at 11:32
  • 2
    btw: wouldn't the declaration declare arr as pointer to pointer to array of n integers instead of pointer to array of pointers to integers... – Antti Haapala -- Слава Україні Feb 06 '17 at 11:40
  • 3
    pointer to an array[n] of pointers to integers would be `int *(*arr)[n]` – Antti Haapala -- Слава Україні Feb 06 '17 at 11:42
  • @AnttiHaapala It is a pointer to an array pointer. Given the function `void func (int (**arr)[5])` and the array pointer `int (*arr)[5];` in the caller, you can call the function as `func(&arr);`. – Lundin Feb 06 '17 at 12:50
  • 2
    @MooingDuck No, it is a pointer to a pointer. Namely a pointer to the first element of an array of pointers. The only reason your example works is because of array decay. `int ** arr = &t;` will give you a compiler error. – Lundin Feb 06 '17 at 12:52
  • @Lundin I think what Antti meant is that a pointer to an array **of** pointers is different from a pointer to an array pointer. Perhaps a typo? – Ilja Everilä Feb 06 '17 at 12:52
  • @TakaTiki They taught you wrong. I am sorry. It is not my fault. Read the 3 links provided for further info. – Lundin Feb 06 '17 at 12:52
  • @IMSoP I pointer to a pointer can never be a pointer to an array. These two terms are clearly defined by ISO C and they are not compatible types. The fact that you can abuse the incorrect practice of using pointer-to-pointers to emulate something that looks like a 2D array but isn't, doesn't change the C concepts of compatible types. – Lundin Feb 06 '17 at 12:55
  • @IljaEverilä Yes, I was a bit confused. Reading the OP:s text again and fixing it. – Lundin Feb 06 '17 at 12:56
  • @Lundin Fine, I just think the answer would be better if it discussed the source of that confusion, and what to look out for if *other people* have abused pointers in that way. Currently, it has good information about *writing* correct code, but the question was more about *reading* code. Something like "However, you may see code that uses such a pointer to perform array-like access ... This is not the same as an array pointer, and is inferior because ..." – IMSoP Feb 06 '17 at 13:03
  • 1
    I've meant to write a FAQ in the form of a community wiki for this for a while. Work in progress. – Lundin Feb 06 '17 at 15:56
  • @Lundin: I never meant to imply that arrays and pointers were synonymous, my point was that `int*` can point to 1 element, or a series of sequential elements (colloquially called 'an array'), or even zero elements. It is not incorrect to say that a `int*` _can_ point to an array. It very much could be pointing to elements in an array. (array as in sequential memory, possibly dynamic. not as in `int[3]`) – Mooing Duck Feb 06 '17 at 20:02
  • Ok so I finally finished writing down a detailed FAQ for this. [Correctly allocating multi-dimensional arrays](http://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays). – Lundin Feb 07 '17 at 16:03
8

Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.

Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:

int i1=1,i2=2,i3=3,i4=4;

int *p2i = &i1;
int **p2p2i_v1 = &p2i;  // pointer to a pointer to a single int

int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int

int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints

// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0];  // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0];  // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0];  // correct; yields 5

// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1];  // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault


// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
7

How can I know if :

arr is a pointer to a pointer of an integer

arr is a pointer to an array of pointers to integers

arr is a pointer to an array of pointers to arrays of integers

You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.

So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.

Magisch
  • 7,312
  • 9
  • 36
  • 52
6

Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.

Consider these declarations

int a;
int a1[1];
int a2[10];

int *p;

p = &a;
//...
p = a1;
//...
p = a2;

In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • I like the single pointer approach in your explanation, because it captures the essence of the question. – Klas Lindbäck Feb 06 '17 at 11:38
  • 1
    A pointer allways points to a single element. You mean how it appears to be if one e.g. passes an array to a function, which **seems to "loose" the size information during passing. But this is actually not true, because the array is implicitly converted to a pointer to the first element, which results in my comment's first sentence. – too honest for this site Feb 06 '17 at 13:15
6

The type of

int ** arr;

only have one valid interpretation. It is:

arr is a pointer to a pointer to an integer

If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.

Assuming proper initialization, the only guaranteed valid way to use it is:

**arr = 42;
int a = **arr;

However, C allows you to use it in multiple ways.

• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)

int a = **arr;

• arr can be used as a pointer to a pointer to an an array of integer

int a = (*arr)[4];

• arr can be used as a pointer to an array of pointers to integers

int a = *(arr[4]);

• arr can be used as a pointer to an array of pointers to arrays of integers

int a = arr[4][4];

In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.

To know which is valid for the program at hand, you need to look at the code initializing arr.

Update

For the updated part of the question:

If you have:

void foo(char** x) { .... };

the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).

If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • This is not even true. "Properly initialized" includes a (one-past-the-end) pointer value, and such a pointer value does not point to anything. The only thing that is true is that it has *type* pointer to pointer to integer. But a valid pointer value of this type can point to a location in memory with zero usable elements. – Ben Voigt Feb 06 '17 at 21:41
3

C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.

In this case arr is a pointer to a pointer to integer.

There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.

One can also create a two dimensional array using it,like this

 int **arr=(int**)malloc(row*(sizeof(int*)));  
 for(i=0;i<row;i++) {
 *(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
  arr[i]=(int*)malloc(sizeof(int)*col); }
minigeek
  • 2,766
  • 1
  • 25
  • 35
  • look out! `arr` is a pointer to a pointer to _zero or more_ integers. The plural cannot be determined from the declaration – Paul Ogilvie Feb 06 '17 at 10:25
  • @Paul Ogilvie I din't get what u want to say ! Can u elaborate a little plz – minigeek Feb 06 '17 at 10:32
  • 1
    "*You could also call it a pointer to a one dimensional array of pointers*" strictly speaking this is not true. A pointer a an array of `int` would look like this: `int (*p)[42]`. This is a pointer to an `int[42]` array. Here: `int * p` is and stays a pointer to an `int`, nothing more and nothing less. Whether `p` points to the 1st element of an array of `int` depends on the context, but still won't make `p` point to the array but to its 1st element only. – alk Feb 06 '17 at 10:35
  • I guess @PaulOgilvie meant that if the pointer is `NULL`, then it does not point to anything, hence it 'points to zero integers'. – underscore_d Feb 07 '17 at 10:04
  • 1
    @underscore_d, that is partly what I mean. However, `malloc` will satisfy a request for zero bytes of memory by returning a valid pointer, but that pointer will point to zero integers. – Paul Ogilvie Feb 07 '17 at 11:32
3

There is one trick when using pointers, read it from right hand side to the left hand side:

int** arr = NULL;

What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.

And int **arr; is the same as int** arr;.

Aleksandar Makragić
  • 1,957
  • 17
  • 32
  • `int s[2] = {}; int* t[3] = {s. s. s}; int ** arr = t;` well look at that! `arr` is _a pointer to an array of pointers to arrays of integers_! – Mooing Duck Feb 06 '17 at 10:59
  • @MooingDuck No, `arr` is s pointer to a pointer to an int. The expression "`t`" decays from array of pointer to int to pointer to pointer to int, and such a value that points to the first element of `t` is assigned to `arr`. You are *defining* "pointer to array" as "pointer to the first element of an array". But "pointer to array" *already* has a meaning as a C type (for which there are no values) and it's *not that*. – philipxy Mar 23 '17 at 02:34
2
int ** arr = NULL;

It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.

msc
  • 33,420
  • 29
  • 119
  • 214
-1

There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/

Visit the site, paste your declaration and it will translate it to English.

For int ** arr;, it says declare arr as pointer to pointer to int.

The site also shows examples. Test yourself on them, then hover your cursor to see the answer.

(double (^)(int , long long ))foo

cast foo into block(int, long long) returning double

int (*(*foo)(void ))[3]

declare foo as pointer to function (void) returning pointer to array 3 of int

It will also translate English into C declarations, which is prety neat - if you get the description correct.

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551