I know that If i define an array like
int a [10];
I can use a pointer notation, to access it's address using a+<corresponding_item_in_array>
and it's value using, *(a+<corresponding_item_in_array>) .
Now I wanted to reverse things, I used malloc to allocate a memory to a integer pointer, and tried to represent the pointer in subscript notation but it didn't work
int *output_array;
output_array = (int *) (malloc(2*2*2*sizeof(int))); //i.e, space for 3d array
output_array[0][0][1] = 25;
// ^ produces error: subscripted value is neither array nor pointer
I may have used an pointer expression using Storage Mapping, but ain't the simpler method available? and Why?
The int* type is not an equivalent of the 3D array type; it is an equivalent of a 1D array type:
int *output_array;
output_array = (int *) (malloc(8*sizeof(int))); //i.e, space for array of 8 ints
output_array[5] = 25; // This will work
The problem with arrays of higher ranks is that in order to index into a 2D, 3D, etc. array the compiler must know the size of each dimension except the first one in order to calculate the offsets from the indexes correctly. To deal with 3D arrays, define a 2D element, like this:
typedef int element2d[2][2];
Now you can do this:
element2d *output_array;
output_array = (element2d*) (malloc(2*sizeof(element2d)));
output_array[0][0][1] = 25; // This will work now
Demo on ideone.
What's the type of output_array? int *.
What's the type of *(output_array+n) or output[n]? int.
Is subscript permitted on int? Both subscripts (eg. *(output_array+n) and output[n]) are pointer operations, and int is not a pointer. This explains the error you recieved.
You can declare a pointer to int[x][y] like this: int (*array)[x][y];
You can allocate storage that's a suitable alternative to a 3D array to array using: array = malloc(42 * x * y);. This would be the equivalent to int array[42][x][y];, except that arrays aren't modifiable lvalues, the alignof, sizeof and address-of operators work differently and the storage duration is different.
Because compiler doesn't have any idea about the size of each dimension, so it's not able to find out where output_array[0][0][1] should be.
You could try this
typedef int (* array3d)[2][2];
array3d output_array;
output_array = (array3d) malloc(2 * 2 * 2 * sizeof(int));
output_array[0][0][1] = 25;
printf("%d\n", output_array[0][0][1]);
Related
I understand that double * price[5]; is an array of pointers. What does double (* data)[5] mean? Where is it used for?
It's a pointer to an array of 5 doubles. Rarely used.
cdecl.org is useful to answer these kinds of questions for yourself:
declare data as pointer to array 5 of double
It's a pointer to array or array pointer. Think of it as a pointer that can point at the array as whole rather than just at the first item of the array.
These are mainly there to keep the language type system consistent. If you have an array double price[5], then &price gives the address of that array, which needs a corresponding pointer type double (*) [5]. This type can only be used to point at an array of 5 double, unlike a double* which can be used to point at the first item of any array of double. So it is less generic but more type safe.
One of the main uses for array pointers is dynamic allocation of multi-dimensional arrays. These should be allocated with a single statement like this:
int (*array) [x][y][z] = malloc( sizeof(int[x][y][z]) );
or equivalent
int (*array) [x][y][z] = malloc( sizeof *array );
That way we get a true "3D array" with all memory allocated adjacently, no heap fragmentation etc. The problem is however that array pointers are cumbersome: to use the pointer in the example above, we would have to de-reference it (like any pointer): (*array)[i][j][k] = ....
To avoid that burdensome syntax, we can instead create an pointer to the first element, which is an array of type int [y][z]:
int (*array)[y][z] = malloc( sizeof(int[x][y][z]) );
...
array[i][j][k] = ... ;
where the array[i] is pointer arithmetic referring to array number i of type int[y][z], [j] refers to an array of type int [z] and [k] refers to an int.
Other uses of array pointers is increasing type safety of arrays passed to functions, or returning a pointer to an array from a function.
I wrote the code -
int arr2d[2][2] = {{1, 2}, {3, 4}};
int * arr = (int*)arr2d;
int i = 0;
for(i = 0; i < 4; i++)
{
printf("%d ", arr[i]);
}
The output was as if I printed every element in the arrays in arr2d, nothing out of the ordinary.
Why is that so?
Why can I cast from int** (as a 2 dimension array) to int*?
You have a misunderstanding. Arrays are not pointers. They do decay to pointers in most contexts, but that's a question of evaluation, not nature. Accordingly, 2D arrays are arrays of arrays, not arrays of pointers. Thus, they do not decay to pointers to pointers, but rather pointers to arrays. There is no int** involved anywhere in your code.
Given this declaration:
int arr2d[2][2] = {{1, 2}, {3, 4}};
The relevant pointer assignment you can perform without a cast is
int (*arr2d_ptr)[2];
arr2d_ptr = arr2d; // arr2d is not a pointer, but it does decay to one in this expression
arr2d_ptr is a pointer to a two-element array of int. The assignment makes it point to the first element of arr2d. If you convert that to type int *, then the result points to the first int in the array to which arr2d_ptr points. For example,
int *ip = (int *) arr2d_ptr;
That's natural, because that int is exactly the first part of the array. You can access it by index as ip[0] or *ip. And you can access the second int in that array as ip[1].
I guess the other facet of the question is about the expressions ip[2] and ip[3]. Arrays are contiguous sequences of elements. Arrays of arrays are not special in this regard: they are contiguous sequences of (smaller) arrays. Thus, the layout of your arr2d is like this:
array..|array..|
. If you overlay the layout of each of the member arrays then you get this:
int|int|int|int|
, which is exactly the same as the layout of a one-dimensional array of four int. This is why you can access all four ints by indexing ip (or arr in your example code).
Fun fact: because expressions of array type decay to pointers, you don't need a cast here. You could instead dereference arr2d_ptr to form an expression designating the first element of the 2D array, which is a 1D array, and let that decay to a pointer:
int *ip2 = *arr2d_ptr;
or, equivalently,
int *ip3 = *arr2d;
The values are stored in memory as if it was a linear array. That's why you can access them like that.
It doesn't work when the 2 dimensional array is composed out of pointers, and I have to understand why.
If you are working with an array of pointers you'll have to use a pointer to pointer, aka, double pointer.
It seems logic that if you want a pointer to access elements in an array of pointers you'll need a pointer to pointer.
//...
int *arr2d[2][2];
int **arr = (int**)arr2d;
//...
If you want to use it as a 2D array, which is what you would want in most cases, you can use:
Live sample
#include <stdio.h>
#include <string.h>
int main()
{
int arr2d[2][2] = {{1, 2}, {3, 4}};
int(*arr)[2] = arr2d; //pointer to 2d array with 2 columns
for (int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
printf("%d ", arr[i][j]); //use it as if it were a 2d array
}
putchar('\n');
}
}
A double pointer is not to be confused with a 2D array, these are different things, this thread has a nice explanation of what each of these mean.
In memory, the array char a[4] = {1, 2, 3, 4} looks likes this:
[(1)(2)(3)(4)]
with () representing a byte of memory and [] hinting you where the array begins/ends.
The array char a[2][2] = {{1, 2}, {3, 4}} looks like this in memory:
[[(1)(2)][(3)(4)]]
See, there is no difference, as [] don't really exist in memory, they are just hints I used in my reply. Effectively, if you don't know anything about the arrays and just look at the content of the raw bytes in memory, you'll see:
(1)(2)(3)(4)
in both cases.
Thus instead of creating an array a[Xmax][Ymax] and accessing the elements using a[x][y], you can as well create the array as b[Xmax * Ymax] and access the elements using b[x * Xmax + y], as that's in fact what happens behind the scenes anyway.
And in C, you can always turn an array reference into a pointer, as an array reference is a reference to a memory location where an array is located and a pointer is a reference to a memory location (regardless if an array is located there or not). So
int a[5] = { ... };
int * b = a;
works as a is a reference to an int array, which are just several int values stored in memory, and b is a pointer to a memory location where an int value is stored. Well, at the address where the array a starts, an int value is stored, so this assignment is perfectly correct.
And m[3] just means "increase the memory address m references three times by the size of the value type m references and fetch the value from that address". And that works and returns the expected value, no matter if m is a pointer or an array reference. So while this syntax is actually intended for array access, it also works with pointers.
The syntax for a pointer would actually be *(m + 3), which means "increase the pointer address three times by the size of the value type it points to and then fetch the value from that address". Yet, just in the first case, this syntax would work with an array reference as well, since an array reference can always become a pointer when required.
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?
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.
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.
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.
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;
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.
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.
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;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
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.
I have a question about how C / C++ internally stores multidimensional arrays declared using the notation foo[m][n]. I am not questioning pure pointers to pointers etc... I am asking because of speed reasons...
Correct me if I am wrong, but syntactically foo is an array of pointers, which themselves point to an array
int foo[5][4]
*(foo + i) // returns a memory address
*( *(foo + i) + j) // returns an int
I have heard from many places that the C/C++ compiler converts foo[m][n] to a one dimensional array behind the scenes (calculating the required one dimension index with i * width + j). However if this was true then the following would hold
*(foo + 1) // should return element foo[0][1]
Thus my question:
Is it true that foo[m][n] is (always?) stored in memory as a flat one dimensional array?? If so, why does the above code work as shown.
A two-dimensional array:
int foo[5][4];
is nothing more or less than an array of arrays:
typedef int row[4]; /* type "row" is an array of 4 ints */
row foo[5]; /* the object "foo" is an array of 5 rows */
There are no pointer objects here, either explicit or implicit.
Arrays are not pointers. Pointers are not arrays.
What often causes confusion is that an array expression is, in most contexts, implicitly converted to a pointer to its first element. (And a separate rule says that what looks like an array parameter declaration is really a pointer declaration, but that doesn't apply in this example.) An array object is an array object; declaring such an object does not create any pointer objects. Referring to an array object can create a pointer value (the address of the array's first element), but there is no pointer object stored in memory.
The array object foo is stored in memory as 5 contiguous elements, where each element is itself an array of 4 contiguous int elements; the whole thing is therefore stored as 20 contiguous int objects.
The indexing operator is defined in terms of pointer arithmetic; x[y] is equivalent to *(x + y). Typically the left operand is going to be either a pointer expression or an array expression; if it's an array expression, the array is implicitly converted to a pointer.
So foo[x][y] is equivalent to *(foo[x] + y), which in turn is equivalent to *(*(foo + x) + y). (Note that no casts are necessary.) Fortunately, you don't have to write it that way, and foo[x][y] is a lot easier to understand.
Note that you can create a data structure that can be accessed with the same foo[x][y] syntax, but where foo really is a pointer to pointer to int. (In that case, the prefix of each [] operator is already a pointer expression, and doesn't need to be converted.) But to do that, you'd have to declare foo as a pointer-to-pointer-to-int:
int **foo;
and then allocate and initialize all the necessary memory. This is more flexible than int foo[5][4], since you can determine the number of rows and the size (or even existence) of each row dynamically.
Section 6 of the comp.lang.c FAQ explains this very well.
EDIT:
In response to Arrakis's comment, it's important to keep in mind the distinction between type and representation.
For example, these two types:
struct pair { int x; int y;};
typedef int arr2[2];
very likely have the same representation in memory (two consecutive int objects), but the syntax to access the elements is quite different.
Similarly, the types int[5][4] and int[20] have the same memory layout (20 consecutive int objects), but the syntax to access the elements is different.
You can access foo[2][2] as ((int*)foo)[10] (treating the 2-dimensional array as if it were a 1-dimensional array). And sometimes it's useful to do so, but strictly speaking the behavior is undefined. You can likely get away with it because most C implementations don't do array bounds-checking. On the other hand, optimizing compilers can assume that your code's behavior is defined, and generate arbitrary code if it isn't.
Yes, C/C++ stores a multi-dimensional (rectangular) array as a contiguous memory area. But, your syntax is incorrect. To modify element foo[0][1], the following code will work:
*((int *)foo+1)=5;
The explicit cast is necessary, because foo+1, is the same as &foo[1] which is not at all the same thing as foo[0][1]. *(foo+1) is a pointer to the fifth element in the flat memory area. In other words, *(foo+1) is basically foo[1] and **(foo+1) is foo[1][0]. Here is how the memory is laid out for some of your two dimensional array:
C arrays - even multi-dimensional ones - are contiguous, ie an array of type int [4][5] is structurally equivalent to an array of type int [20].
However, these types are still incompatible according to C language semantics. In particular, the following code is in violation of the C standard:
int foo[4][5] = { { 0 } };
int *p = &foo[0][0];
int x = p[12]; // undefined behaviour - can't treat foo as int [20]
The reason for this is that the C standard is (probably intentionally) worded in a way which makes bounds-checking implementations possible: As p is derived from foo[0], which has type int [5], valid indices must be in range 0..5 (resp. 0..4 if you actually access the element).
Many other programming languages (Java, Perl, Python, JavaScript, ...) use jagged arrays to implement multi-dimensional arrays. This is also possible in C by using an array of pointers:
int *bar[4] = { NULL };
bar[0] = (int [3]){ 0 };
bar[1] = (int [5]){ 1, 2, 3, 4 };
int y = bar[1][2]; // y == 3
However, jagged arrays are not contiguous, and the pointed-to arrays need not be of uniform size.
Because of implicit conversion of array expressions into pointer expressions, indexing jagged and non-jagged arrays looks identical, but the actual address calculations will be quite different:
&foo[1] == (int (*)[5])((char *)&foo + 1 * sizeof (int [5]))
&bar[1] == (int **)((char *)&bar + 1 * sizeof (int *))
&foo[1][2] == (int *)((char *)&foo[1] + 2 * sizeof (int))
== (int *)((char *)&foo + 1 * sizeof (int [5]) + 2 * sizeof (int))
&bar[1][2] == (int *)((char *)bar[1] + 2 * sizeof (int)) // no & before bar!
== (int *)((char *)*(int **)((char *)&bar + 1 * sizeof (int *))
+ 2 * sizeof (int))
int foo[5][4];
foo is not an array of pointers; it's an array of arrays. Below image will help.
I have an array of int pointers int* arr[MAX]; and I want to store its address in another variable. How do I define a pointer to an array of pointers? i.e.:
int* arr[MAX];
int (what here?) val = &arr;
The correct answer is:
int* arr[MAX];
int* (*pArr)[MAX] = &arr;
Or just:
int* arr [MAX];
typedef int* arr_t[MAX];
arr_t* pArr = &arr;
The last part reads as "pArr is a pointer to array of MAX elements of type pointer to int".
In C the size of array is stored in the type, not in the value. If you want this pointer to correctly handle pointer arithmetic on the arrays (in case you'd want to make a 2-D array out of those and use this pointer to iterate over it), you - often unfortunately - need to have the array size embedded in the pointer type.
Luckily, since C99 and VLAs (maybe even earlier than C99?) MAX can be specified in run-time, not compile time.
Should just be:
int* array[SIZE];
int** val = array;
There's no need to use an address-of operator on array since arrays decay into implicit pointers on the right-hand side of the assignment operator.
IIRC, arrays are implicitly convertible to pointers, so it would be:
int ** val = arr;
According to this source http://unixwiz.net/techtips/reading-cdecl.html, by using the "go right when you can, go left when you must" rule, we get the following 2 meanings of the declarations given in the previous answers -
int **val ==> val is a pointer to pointer to int
int* (*pArr)[MAX] ==> pArr is a pointer to an array of MAX length pointers to int.
I hope the above meanings make sense and if they don't, it would probably be a good idea to peruse the above mentioned source.
Now it should be clear that the second declaration is the one which moteutsch is looking for as it declares a pointer to an array of pointers.
So why does the first one also work? Remember that
int* arr[MAX]
is an array of integer pointers. So, val is a pointer to, the pointer to the first int declared inside the int pointer array.
#define SIZE 10
int *(*yy)[SIZE];//yy is a pointer to an array of SIZE number of int pointers
and so initialize yy to array as below -
int *y[SIZE]; //y is array of SIZE number of int pointers
yy = y; // Initialize
//or yy = &y; //Initialize
I believe the answer is simply:
int **val;
val = arr;
As far as I know there is no specific type "array of integers" in c, thus it's impossible to have a specific pointer to it. The only thing you can do is to use a pointer to the int: int*, but you should take into account a size of int and your array length.