How to create a pointer to a multi dimensional array in C - arrays

Before anyone closes this question because there's another related one, hear me out. I've already looked at the other question and I didn't get it. I would like to create a pointer to a multi dimensional array but I don't know how. I thought I was supposed to do it like this:
int test_arr[2][4];
int *ptr_array = test_arr;
But when I do that, I get a warning saying:
incompatible pointer types initializing 'int *' with an expression of type 'int [2][4]'
I have no idea what I'm doing wrong. Can someone help me please?

In order to do pointer arithmetic the pointer has to know the size of what it is pointing to.
int test_arr[2][4]; is equivalent to 2 elements of type int[4]. So whenever you add 1 to the pointer, it will jump the size of 4 integers. If you had int* it would increment the size of a single integer only.
Like said in the comments, what you want is: int (*ptr_array)[4] = test_arr;
I know, the syntax is a little weird, but that's how you do it.

You need to understand the basics.
[Below in post, read 1D as 1 dimension and 2D as 2 dimension]
First, lets take an example of pointer to 1D array:
Take an int type and a pointer pointing to it:
int x = 1;
int *px = &x;
The type of x is int and the type of &x is int * and type of px is int * i.e. it can hold the address of an int type variable. Hence the assignment is valid.
Take a 1D int array and a pointer pointing to it:
int arr[2] = {1,2};
int *parr = arr;
Note that the type of px and parr is same i.e. int * and assigning arr to parr is completely valid although the arr is a 1D array.
This is because of the fact that, in C, an array of type converted to pointer of type that points to the initial element of the array object but there are few exceptions to this rule and one of them is when used unary & operator.
The type of arr is int [2] but in the above statment (parr declare and initialisation statement) it is converted to pointer pointing to initial element of array which is an integer i.e. arr is converted to int * type in the int *parr = arr; statement. Hence, it is valid to assign arr to parr or to any variable of type int *.
As, I have mentioned that there are few exceptions to the rule (array of type converted to pointer of type....) and one of the exception is when used unary & operator. So type of &arr will be int (*)[2]. That means you can assign &arr to any variable of type int (*)[2].
int (*parr2)[2] = &arr;
i.e. parr2 is a pointer to an array of 2 integer.
The difference between this
int *parr = arr;
and
int (*parr2)[2] = &arr;
is that parr can hold address of any int pointer but parr2 can hold the address of any array of 2 integers. Both are pointing to same address but their types are different.
If you understood the above mentioned things completely then read below otherwise read the above part again.
Now lets come to 2D array.
Take a 2D array and a pointer pointing to it:
int arr[2][2];
int (*ptr)[2] = arr;
In the above ptr declare and initialisation statement, the type of arr is int (*)[2]. Why??
Recall the rule mentioned above - array of type converted to pointer of type that points to the initial element of the array object.
arr is array of 2 1D arrays of size 2 (2 int elements). So, it's first element is array of 2 int and, by rule, it will be converted to pointer to the initial element i.e. pointer to
1D array of 2 int which is int (*)[2].
Hence, you can assign arr to a pointer variable of type int (*)[2].
The type of &arr is int (*)[2][2], so this is also perfectly fine:
int (*ptr2)[2][2] = &arr;
So, there are two ways you can have pointer to 2D arr but remember that the types of ptr and ptr2 is different. This matters, for e.g., if you add 1 to pointer ptr it will be incremented by size of int [2] but if you add 1 to ptr2 it will be incremented by size of int [2][2].
How to access the array members using pointer:
In case of 1D array:
int arr[2] = {1,2};
int *parr = arr;
int (*parr2)[2] = &arr;
// access arr members via parr pointer
printf ("%d\n", parr[0]); // this will give value of first member of array arr
// access arr members via parr2 pointer
printf ("%d\n", (*parr2)[0]); // this will give value of first member of array arr
Similarly, in case of 2D array:
int test_arr[2][4];
int (*ptr_array)[4] = test_arr;
int (*ptr_array2)[2][4] = &test_arr;
// access test_arr members via ptr_array pointer
printf ("%d\n", ptr_array[0][0]); // this will give value of first member of array test_arr
// access test_arr members via ptr_array2 pointer
printf ("%d\n", (*ptr_array2)[0][0]); // this will give value of first member of array test_arr
Based on above explanation, try yourself creating multidimensional array (> 2D array) pointers and play with them.
Hope, above explanation resolves your all confusions related to pointer to a 2D array and you understood now why compiler is giving incompatible pointer types .... warning on statement int *ptr_array = test_arr;. It's all about type compatibility during initialisation/assignment.

Related

What is difference in int* p and (int*) p in C

I couldn't understand use of (int*) p in following program for pointer to an array
#include<stdio.h>
void main()
{
int s[4][2];
int (*p)[2];
int i,j,*pint;
for(i=0;i<=3;i++)
{
p=&s[i];
pint=(int*)p; /*here*/
printf("\n");
for(j=0;j<=1;j++)
printf("%d",*(pint+j));
}
}
can i use *p instead of (int*) p here. thanks in advance
In your code,
pint=(int*)p;
p is of type int (*)[2], i.e., pointer to an array of 2 ints, and pint is a int *. They are not compatible types, so you need the cast.
If you have an array declaration like this
int s[4][2];
then these three pointers have the same value
int ( *p1 )[4][2] = &s;
int ( *p2 )[2] = &s[0];
int *p3 = &s[0][0];
because all the pointers point to the initial address of the extent of memory allocated for the array.
However the pointers have different types because they point to objects of different types.
The first pointer points to the array in whole as a single object.
the second pointer points to an array element that in turn has the array type int[2].
And the third array point to a scalar object of the type int.
So you may not assign directly one pointer to another because they are incompatible though as it was mentioned they have the same value (address).
You need to cast one pointer type to another pointer type explicitly.
This assignment in the original program
p=&s[i];
assigns the address of each element (array of the type int[2]) to the pointer. In fact it is the address of the first element of the array that is it is equal to &s[i][0]. However the first expression and the last expression have different pointer types.
So you need to use casting in this assignment
pint=(int*)p;
Now using the pointer arithmetic in this expression
*(pint+j)
you can traverse all scalar elements of the array initially pointed to by the pointer p.
Pay attention to that this declaration of main
void main()
is nit a standard declaration.
You should declare the function main like
int main( void )

Access by pointer to multi-dimensional static arrays in C/C++

I know, that static arrays are laid out contiguously in memory.
So, for example, int T[10][10] is basically stored the same way as int T[100].
I can access element of index i, j many ways, for example:
int T[10][10];
/*filling array*/
int i=3, j=7;
int x = T[i][j];
//EDIT - old and wrong: int * ptr = T;
int * ptr = &T[0][0];
int y = *(ptr + 10* i + j);
On the other hand, when I create dynamicaly allocated 2-dimensional array by myself:
int ** T;
T = malloc(10 * sizeof(int *));
for(i = 0; i < N; i++)
T[i] = malloc(10 * sizeof(int));
My array contains pointers to
It is obvious, that I can access element of this array by:
int i=3, j=7;
int x = *(*(T+i)+j);
And now my question: why and how does it work for static arrays?
Why does
int T[10][10];
/*filling array*/
int i=3, j=7;
int x = *(*(T+i)+j);
return good value to x, when this table doesn't contain pointers to arrays? *(*(T+i)) shouldn't have sense there in my opinion, end even if, it should return T[0][i], as T points at the first element of array. How does compiler interpret this, is * something other than dereference here? Enlighten me.
For starters:
int * ptr = T;
That's not going to actually work, at least without your compiler yelling at you. Very loudly. The correct way to do this is:
int * ptr = &t[0][0];
This point is actually very relevant to your question.
As you know, when used in an expression, an array gets decayed to a pointer. For example:
char foo[10];
bar(foo);
When used in an expression, like a parameter to a function, the array decays to a pointer to the underlying type. foo gets you a char *, here.
However, and this is the key point: the array only decays one level. If the array is a two-dimensional array, the array does not get decayed to the underlying value, an int in this case. The two dimensional array reference decays to a pointer to a one-dimensional array:
int T[10][10];
/*filling array*/
int i=3, j=7;
int x = *(*(T+i)+j);
The sequence of steps that occurs here:
T decays to a pointer to an array of 10 integers, or int (*)[10]
The addition of i advances the pointer by the given value. The pointer is advanced by the size of the element being pointed to. Since the pointer points to array of 10 integers, the pointer is advanced accordingly. If i was 2, the pointer is advanced by "two arrays of 10 integers", loosely speaking.
The * operator takes a "pointer to an array of 10 integers" and gives you "an array of 10 integers" as a result. In other words: from int (*)[10] to int [10].
Since the result is used in an expression, namely the left operand of + j, and the left operand is an array type, the array type decays to a "pointer to int".
j is added to the result, and dereferenced.
Why does
int T[10][10];
/*filling array*/
int i=3, j=7;
int x = *(*(T+i)+j);
return good value to x
The magic is all in *(*(T+3)+7) (I have converted to the literal values).
T is an array (of size 10) of arrays (of size 10) of int.
When T is used in an an expression it decays into a pointer to its first element, so it decays to "pointer to arrays (of size 10) of int".
Adding an integer to that pointer will advance to the fourth element of the array.
So T+3 is a pointer to an array of 10 ints, and specifically the fourth such array in T.
*(T+3) indirects through that pointer to give an l-value of type "array of 10 ints".
Ah-ha! That is another array being used in an expression - so it decays into a pointer to it's first element! (It wouldn't decay in sizeof, so sizeof(*(T+3)) would be typically 40.)
(*(T+3) + 7) just points at the eight element in the array, and ...
*(*(T+3) + 7) is an l-value of type int!

how does p become a 2-D array after the call to malloc?

The following snippet declares a 2-D array of 4 X 10 using malloc function
/* Declare a pointer to an array that has 10
ints in each row. */
int (*p)[10];
register int i, j;
/* allocate memory to hold a 4 x 10 array */
p = malloc(40*sizeof(int));
But I do not understand how does p become a 2-D array. Initially p is declared to be an array of pointers that point to int. What happens after the call to malloc ? I am unable understand this.
In C, pointers and arrays are not the same, despite looking very similar. Here p is of type "pointer to array of 10 ints". You're using it as a "pointer to array of 4 arrays of 10 ints", which is a single block of memory (the only pointer is the outermost pointer). It's basically a dynamically allocated int[4][10].
The trick to reading these definitions is to realize that they're written the same way you use the item. If you have:
*x[10];
The array subscript is applied first, then the pointer dereference. So it's an array of pointers if you define int *x[10]. If you use parenthesis to override normal precedence, you can get the pointer dereference to happen first, so you have a pointer to an array.
Confusing? It gets worse. In function arguments, the outermost array of a function parameter is converted into a pointer.
int *p[10]; // array of 10 pointer to int
int (*p)[10]; // pointer to array of 10 ints
void foo(int *p[10] /* pointer to pointer to int */);
void foo(int (*p)[10] /* pointer to array of 10 ints */);
Further, arrays are converted to pointers when you use them.
int x[10]; // array of 10 int
sizeof(x); // 10 * sizeof(int)
int *y = x; // implicitly converts to a pointer to &x[0]!
sizeof(y); // sizeof(int *)
This means that you can allocate memory for an array of arrays, then let that implicitly convert to a pointer to an array, which you in turn use as if it were an array of arrays!
Anyway, this is all very confusing so please do not ever use this in production code - at least, not without a clarifying typedef:
typedef int vector[3];
vector *array_of_vectors; // actually a pointer to a vector,
// but you can use it as an aray to a vector if enough
// memory is allocated
The memory, worth 40 ints, is reserved to the pointer p. p points at his memory block. It so happens that p chooses to organize this memory as 10 equal parts, each of which happen to hold 4 ints' worth.
That's if this code is actually correct. My C is very rusty at this point.
First, some background information:
Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and its value is the address of the first element in the array. For example, given the array
int a[10];
anytime the expression a appears in the code, its type will be converted from "10-element array of int" to "pointer to int", or int *, except for cases like sizeof a, _Alignof a, and &a. If we have a 2D array of T, such as
int a[10][10];
the expression a will be converted from type "10-element array of 10-element array of int" to "pointer to 10-element array of int", or int (*)[10] (look familiar? that's the type of your pointer p).
If we want to dynamically allocate an N-element array of type T, we write something like
T *p = malloc(N * sizeof *p);
sizeof *p is equivalent to sizeof (T). In this particular case, type T is "10-element array of int", or int [10]. We want to allocate 4 such arrays, so we can write
int (*p)[10];
p = malloc(4 * sizeof *p);
This allocates space for 4 10-element arrays of int, and assigns the result to p. (sizeof *p == sizeof (int [10])).
So how does this become a 2D array?
Remember that the expression a[i] is equivalent to *(a + i); we find the address of the i'th element of type T following a and dereference the result. In this case p[i] gives us the address of the ith 10-element array of int following p. Since we dereference the pointer as part of the subscript operation, the type of the expression p[i] is "10-element array of int". Thus we can subscript this expression again and get p[i][j].

Problems with 2 D arrays

I wrote the following code in C:
#include<stdio.h>
int main()
{
int a[10][10]={1};
//------------------------
printf("%d\n",&a);
printf("%d\n",a);
printf("%d\n",*a);
//-------------------------
printf("%d",**a);
return 0;
}
With the above 3 printf statements I got the same value. On my machine it's 2686384. But with the last statement I got 1.
Isn't it something going wrong? These statements mean:
The address of a is 2686384
The value stored in a is 2686384
the value that is stored at address of variable pointed by a (i.e. at 2686384) is 2686384.
This means a must be something like a variable pointing towards itself...
Then why is the output of *(*a) 1? Why isn't it evaluated as *(*a)=*(2686384)=2686384?
#include<stdio.h>
int main()
{
// a[row][col]
int a[2][2]={ {9, 2}, {3, 4} };
// in C, multidimensional arrays are really one dimensional, but
// syntax alows us to access it as a two dimensional (like here).
//------------------------
printf("&a = %d\n",&a);
printf("a = %d\n",a);
printf("*a = %d\n",*a);
//-------------------------
// Thing to have in mind here, that may be confusing is:
// since we can access array values through 2 dimensions,
// we need 2 stars(asterisk), right? Right.
// So as a consistency in this aproach,
// even if we are asking for first value,
// we have to use 2 dimensional (we have a 2D array)
// access syntax - 2 stars.
printf("**a = %d\n", **a ); // this says a[0][0] or *(*(a+0)+0)
printf("**(a+1) = %d\n", **(a+1) ); // a[1][0] or *(*(a+1)+0)
printf("*(*(a+1)+1) = %d\n", *(*(a+1)+1) ); // a[1][1] or *(*(a+1)+1)
// a[1] gives us the value on that position,
// since that value is pointer, &a[i] returns a pointer value
printf("&a[1] = %d\n", &a[1]);
// When we add int to a pointer (eg. a+1),
// really we are adding the lenth of a type
// to which pointer is directing - here we go to the next element in an array.
// In C, you can manipulate array variables practically like pointers.
// Example: littleFunction(int [] arr) accepts pointers to int, and it works vice versa,
// littleFunction(int* arr) accepts array of int.
int b = 8;
printf("b = %d\n", *&b);
return 0;
}
An expression consisting the the name of an array can decay to a pointer to the first element of the array. So even though a has type int[10][10], it can decay to int(*)[10].
Now, this decay happens in the expression *a. Consequently the expression has type int[10]. Repeating the same logic, this again decays to int*, and so **a is an int, which is moreover the first element of the first element of the array a, i.e. 1.
The other three print statements print out the address of, respectively, the array, the first element of the array, and the first element of the first element of the array (which are of course all the same address, just different types).
First, a word on arrays...
Except when it is the operand0 of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.
The expression &a has type "pointer to 10-element array of 10-element array of int", or int (*)[10][10]. The expression a has type "10-element array of 10-element array of int", which by the rule above decays to "pointer to 10-element array of int", or int (*)[10]. And finally, the expression *a (which is equivalent to a[0]) has type "10-element array of int", which again by the rule above decays to "pointer to int".
All three expressions have the same value because the address of an array and the address of its first element are the same: &a[0][0] == a[0] == *a == a == &a. However, the types of the expressions are different, which matters when doing pointer arithmetic. For example, if I have the following declarations:
int (*ap0)[10][10] = &a;
int (*ap1)[10] = a;
int *ip = *a;
then ap0++ would advance ap0 to point to the next 10x10 array of int, ap1++ would advance ap1 to pointer to the next 10-element array of int (or a[1]), and ip++ would advance ip to point to the next int (&a[0][1]).
**a is equivalent to *a[0] which is equivalent to a[0][0]. which is the value of the first element of a and has type int and the value 1 (note that only a[0][0] is initialized to 1; all remaining elements are initialized to 0).
Note that you should use %p to print out pointer values:
printf("&a = %p\n", &a);
printf(" a = %p\n", a);
printf("*a = %p\n", *a);
First of all, if you want to print out pointer values, use %p - if you're on a 64 bit machine int almost certainly is smaller than a pointer.
**a is double dereferencing what's effectively a int**, so you end up with what the first element of the first sub-array is: 1.
If you define a as T a[10] (where T is some typedef), then a simple unadorned a means the address of the start of the array, the same as &a[0]. They both have type T*.
&a is also the address of the start of the array, but it has type T**.
Things become trickier in the presence of multi-dimensional arrays. To see what is happening, it is easier to break things down into smaller chunks using typedefs. So, you effectively wrote
typedef int array10[10];
array10 a[10];
[Exercise to reader: What is the type of a? (it is not int**)]
**a correctly evaluates to the first int in the array a.
From C99 Std
Consider the array object defined by the declaration
int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j] yields an int.
so,
Initial array will be x[0][0] only.
all x, &x and *x will be pointing to x[0][0].
No, there's nothing wrong with your code. Just they way you are thinking about it... The more I think about it the harder I realize this is to explain, so before I go in to this, keep these points in mind:
arrays are not pointers, don't think of them that way, they are different types.
the [] is an operator. It's a shift and deference operator, so when I write printf("%d",array[3]); I am shifting and deferencing
So an array (lets think about 1 dimension to start) is somewhere in memory:
int arr[10] = {1};
//Some where in memory---> 0x80001f23
[1][1][1][1][1][1][1][1][1][1]
So if I say:
*arr; //this gives the value 1
Why? because it's the same as arr[0] it gives us the value at the address which is the start of the array. This implies that:
arr; // this is the address of the start of the array
So what does this give us?
&arr; //this will give us the address of the array.
//which IS the address of the start of the array
//this is where arrays and pointers really show some difference
So arr == &arr;. The "job" of an array is to hold data, the array will not "point" to anything else, because it's holding its own data. Period. A pointer on the other hand has the job to point to something else:
int *z; //the pointer holds the address of someone else's values
z = arr; //the pointer holds the address of the array
z != &z; //the pointer's address is a unique value telling us where the pointer resides
//the pointer's value is the address of the array
EDIT:
One more way to think about this:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? if I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array, thus:
c == &c;

(gcc) Multi-Dim Array or Double Pointer for Warning-free Compile

I have a function, which is called sometimes with regular, sometimes dynamic arrays.
If I define the function as
function_name(int[10][10] a)
and send int** as a parameter, I get a warning. Opposite, if I declare
function_name(int** a)
and send int[][] as a parameter (after casting) I cannot access to array elements inside function.
What is the correctest way?
When an array is passed to a function, it "decays" to a pointer to its first element. So, given:
T a[10];
f(a);
In the call f(a), a is actually &a[0], i.e., a pointer, and the type is T * (the type of &a[0]).
When you have an array of arrays, the same rule applies:
T a[10][5];
f(a);
a decays to a pointer again, equal to &a[0]. a[0] is of type "array [5] of T". So, &a[0] is of type "pointer to array [5] of T", i.e., if you were to declare a pointer p to set equal to &a[0], you would do:
T (*p)[5]; /* parentheses because [] binds tighter than * */
p = &a[0];
Given the above, and assuming your array is declared in the calling code as int a[10][10];, you should declare your function as:
function_name(int (*a)[10]);
For more, see this.
There is a syntax error in function_name(int[10][10] a)—you need to specify the array size after the "variable" name: function_name(int a[10][10]). In fact, the above is equivalent to function_name(int (*a)[10]), because of the "decaying" mentioned above.
Edit: ah, I think I understand now. You cannot declare a function that takes both a "two dimensional" array and a pointer-to-pointer, for the reasons mentioned above (the "decaying" to pointer happens only once). A pointer to pointer may not point to contiguous data, and may have different number of elements in each "row". An array of arrays doesn't cannot have those properties. They are fundamentally different.
int ** and int [][] are not the same.
The former is pointer to pointer to int whereas second one is 2-d array of int.
int[][] decays to int (*)[] when you pass it as argument to function.
void func(int arr[][10]) { //decays to `int (*arr)[10]`
printf("%d correct", arr[1][9]); //10th element of 2nd row
//printf("%d correct", (*(arr + 1))[9]); //same as above
}
int main() {
int (*arr)[10]; //pointer to array of ints
arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.
arr[1][9] = 19;
func(arr);
return 0;
}

Resources