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;
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
.
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); }
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;
.
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.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer
and assigned NULL
value.