Dereferencing an array of pointers to two dimensional arrays in C? - c

I was wondering if it is possible to dereference a pointer to a two dimensional array in C:
int matrix1[2][2] = {{1,2},{3,4}};
int matrix2[2][2] = {{4,5},{6,7}};
I am trying to create an array of pointers, where the first pointer points to matrix1 and the second one to matrix2. I thought of
int *(pt[2]);
pt[0] = &matrix1
My goal would be to be able to access any element in one of the two array with something like:
pt[0][n][m];
Or for the second matrix:
pt[1][n][m]
But as far as I know this doesn't work. Is the pointer declaration wrong?

You have to declare pt as an array of pointers to array.
int (*pt[2])[2] = { matrix1, matrix2 };
Demo.

The answer provided is correct but lacks explanation. I think it is more helpful if you understand why your approach failed.
Using array indexes on pointers works by incrementing the pointer using the size of the data type.
For example if we define an array as follows:
int a[2] = {1,2};
and assume that the array was created in memory at location x
a[0]; // points at x
a[1]; //points at x + sizeof(int)
now lets take the example of two dimensional array
int a[2][2] = {{1,2},{3,4}}
again assume location x
a[0]; //points at x
a[1]; //points at x + sizeof(int [2]) because int[2] is the data type
a[0][1]; // points at x + sizeof(int)
a[1][1]; // points at x + sizeof(int[2]) + sizeof(int)
Now lets take your example
int matrix1[2][2] = {{1,2},{3,4}};
int matrix2[2][2] = {{4,5},{6,7}};
int *pt[2];
pt[0] = &matrix1; //doesn't compile
First, that won't really compile because the type of pt is pointer to int and matrix1 is a pointer to int[2]. However, you can force it by casting like this
pt[0] = (int*)&matrix1;
But it still won't work because the following is not valid either
pt[0][n][m]; //fails to compile
This is because pt is an array of pointer to int, so pt[0][n] points at an integer, not an array. As such you cannot use apply an index to it
However, if you define it as follows
int (*pt[2])[2] = {&matrix1,&matrix2}
pt is then an array of pointers to two dimensional arrays. As such, assuming matrix1 defined at x1 and matrix2 defined at x2,
pt[1][1][1]; //points to x2 + sizeof(int[2]) + sizeof(int)

Related

what is the difference between *p[5] and (*p)[5]?

While going through an example of pointers I came across a line which was *p[5] declares p as an array of 5 pointers while (*p)[5] declares p as a pointer to an array of five elements. I didn't understand the difference between them.
Could anyone explain it with an example?
1. int (*p)[5]
is called a Pointer to an Array(Array Pointer). We can declare a pointer that can point to whole array instead of only one element of the array.This pointer is useful when talking about multidimensional arrays.
In this example p is pointer that can point to an array of 5 integers.
/*Pointer to an array*/
#include<stdio.h>
int main(void)
{
int *ptr; /*can point to an integer*/
int (*p)[5];/*can point to an array of 5 integers*/
int arr[5];
ptr=arr;/*points to 0th element of arr*/
p=&arr;/*points to the whole array arr*/
printf("ptr=%p,p=%p\n",ptr,p);
ptr++;
p++;
printf("ptr=%p,p=%p\n",ptr,p);
return 0;
}
Output:
ptr=0012FEAC,p=0012FEAC
ptr=0012FEB0,P=0012FEC0
Here ptr is pointer that points to 0th element of array arr,while p is pointer that points to the whole array arr.The base type of ptr is int while base type of p is ‘an array of 5 integers’.
We know that pointer arithmetic is performed relative to the base size,so if we write p++ then the pointer will be shifted forward by 20 bytes.
2. Now coming to *p[5]:
This is called Array of Pointers(Pointer Array)
Correct syntax is datatype *arrayname[size];
We can declare an array that contains pointers as its elements.Every element of this array is a pointer variable that can hold address of any variable of appropriate type.
/*Array of pointers*/
#include<stdio.h>
int main(void)
{
int *p[5];
int i,a=5,b=10,c=15;
p[0]=&a;
p[1]=&b;
p[2]=&c;
for(i=0;i<3;i++)
{
printf("p[%d]=%p\t",i,p[i]);
printf("*p[%d]=%d\n",i,*p[i]);
}
return 0;
}
Output:
p[0]=0012FEB4 *p[0]=5
p[1]=0012FEA8 *p[1]=10
p[2]=0012FE9C *p[2]=15
I hope this explanation along with examples will clear your concepts.
Hope this is helpful :)
The order of evaluation differs. *p[3] resolves to *(p[3]) but not (*p)[3]. Also note that *p is equivalent to p[0]. Therefore, ...
*p[3] ⇔ *(p[3]) ⇔ (p[3])[0] ⇔ p[3][0]
(*p)[3] ⇔ (p[0])[3] ⇔ p[0][3]
Assuming you have an array of arrays, the difference is shown below:
A pointer is like a sticky note; you write on it where you put the actual object.
An array is a box with equal compartments. It can store objects of the same type.
You have three balls.
An array of three pointers is a box that contains three stickers. Each sticker tells where each ball is located (they might not be all in the same place).
A pointer to an array of three elements is a sticky note that tells where to find the box. The box contains all tree balls.
Let us see if this helps ,in short, assuming int
1) int *p[3]
int *p1 = &i;
int *p2 = &j;
int *p3 = &k;
Instead of the above 3 separate pointers, I can have an array of pointers as int *p[3]. Each element in the array can point to i,j, and k, all are ints
2) int (*p)[3]
int array[3];
If I want a pointer which points to this array which have 3 elements, the pointer declaration will be int (*p)[3]. This is a pointer pointing to array

How do you get the address of array elements given the address of the array itself in C?

*edited to clarify that the array is unknown
If the address of unknown integer array is 0x00006ffd29c78e70 (and an integer is 4 bytes), what is the address of element array[1]?
Many thanks in advance.
The address of the array is also the address of its first element. This is because the array itself in memory consists solely of each of its elements (starting at index 0) in turn. Therefore if A is an array, &A[0] points to the same memory as A. (Note that there is a technical difference between an array of integers type and a pointer to an integer type, though they are in many cases interchangeable as the former decays into the latter under certain circumstances which are beyond the scope of this question; this is why I described them as pointing both to the same memory).
You asked about the first element, and then referred to A[1]. Note that A[1] is the second element. A[0] is the first element.
So in your particular example, you could do:
int *A = (int *)0x00006ffd29c78e70;
int *A1 = &A[1]; // points to second element
int foo = *A1; // second element contents
or using pointer arithmetic
int *A = (int *)0x00006ffd29c78e70;
int *A1 = A+1; // points to second element
int foo = *A1; // second element contents
Note the +1 does not add one to the (byte) address, but increments the pointer by one int.
Note I have written int above - use the correct integer data type to represent your 4 byte integer.
If 0x00006ffd29c78e70 is the address of a valid array of ints then you can assign it to a pointer:
int *p = (int*)0x00006ffd29c78e70;
then p[1] will give you the next element (second) in that array.
Elements are at
unsigned char *addressofarray = whatever;
unsigned char *secondelement = addressofarray + sizeof arrayelement;
unsigned char *nthelement = addressofarray + n * sizeof arrayelement;
you just got a pointer to acess any thing in array as:
int *ptr = (int*) 0x00006ffd29c78e70;
you can acess any element as:
*(ptr+i) //i is the index

Pointer function with an array

I have a problem, I have a function and I do not understand a specific thing. The function is:
int F( int* x , int n ){
int i , m=0
for (i=0;i<n; i++){
m=x[ i ] + m;
}
return m * m ;
}
I call the function with a pointer and with an integer. Later I do a "for", but I do not understand the line:
m=x[ i ] + m;
Because x is a pointer not an array.
Could you please help me.
Then x points to the memory position then to +1. For example if i call the function with
n=10
x=&n
F(x,n)
the function returns somenthing strange.
X points to the position memory to n, later to the position memory to n+1??
Since x is a pointer, when you pass the array to the function, x points to the first element of the array. Since array is a contigous allocation of memory, The pointer can be made to point to consecutive elements of the array. Thats why
m=x[i]+m
x[i] implies to the ith index from the first element of the array
main()
{
int x[10]={1,2,3,4,5,6,7,8,9,10},sum;
sum=function(x,10);
return 0;
}
This function sends the array to the function, with 10, the size of the array
Arrays are represented as contiguous memory and the array variable gets interpreted as a pointer to the base of that memory (e.g. &(x[0])). Array offset syntax gets translated into pointer arithmetic.
See this post, which clarifies the difference between pointer and arrays:
[] - indexed dereference
a[b] is equivalent to *(a + b). This means a and b must be a pointer to an array element and an integer; not necessarily respectively, because a[b] == *(a + b) == *(b + a) == b[a]. Another important equivalence is p[0] == 0[p] == *p.
The function might be equivalently declared (with more clarity perhaps):
int F(int x[], int n);
and you would call it like so:
int data[3] = {1, 2, 3};
int value = F(data, 3);

Confusion with Two Dimensional Array

Please consider the following 2-D Array:
int array[2][2] = {
{1,2},
{3,4}
};
As per my understanding:
- 'array' represents the base address of the 2-D array (which is the same as address of the first element of the array, i.e array[0][0]).
The actual arrangement of a 2-D Array in memory is like a large 1-D Array only.
Now, I know that base address = array. Hence, I should be able to reach the Memory Block containing the element: array[0][0].
If I forget about the 2-D array thing & try to treat this array as a simple 1-D array:
array[0] = *(array+0) gives the base address of the first array & NOT the element array[0][0]. Why?
A 2-D array does not store any memory address (like an Array of Pointers).
If I know the base address, I must be able to access this memory as a linear 1- Dimensional Array.
Please help me clarify this doubt.
Thanks.
array[0] is a one-dimensional array. Its address is the same as the address of array and the same as the address of array[0][0]:
assert((void*)&array == (void*)&(array[0]));
assert((void*)&array == (void*)&(array[0][0]));
Since array[0] is an array, you can't assign it to a variable, nor pass it to a function (if you try that, you'll be passing a pointer to the first element instead). You can observe that it's an array by looking at (array[0])[0] and (array[0])[1] (the parentheses are redundant).
printf("%d %d\n", (array[0])[0], (array[0])[1]);
You can observe that its size is the size of 2 int objects.
printf("%z %z %z\n", sizeof(array), sizeof(array[0]), sizeof(array[0][0]));
Here's a diagram that represents the memory layout:
+-------------+-------------+-------------+-------------+
| 1 | 2 | 3 | 4 |
+-------------+-------------+-------------+-------------+
`array[0][0]' `array[0][1]' `array[1][0]' `array[1][1]'
`---------array[0]---------' `---------array[1]---------'
`-------------------------array-------------------------'
"Thou shalt not fear poynter arythmethyc"...
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)&array[0][0];
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", ptr[i]);
}
Why does this work? The C standard specifies that multidimensional arrays are contigous in memory. That means, how your 2D array is arranged is, with regards to the order of its elements, is something like
array[0][0]
array[0][1]
array[1][0]
array[1][1]
Of course, if you take the address of the array as a pointer-to-int (int *, let's name it ptr), then the addresses of the items are as follows:
ptr + 0 = &array[0][0]
ptr + 1 = &array[0][1]
ptr + 2 = &array[1][0]
ptr + 3 = &array[1][1]
And that's why it finally works.
The actual arrangement of a 2-D Array in memory is like a large 1-D Array only.
yes, the storage area is continuous just like 1D arrary. however the index method is a little different.
2-D[0][0] = 1-D[0]
2-D[0][1] = 1-D[1]
...
2-D[i][j] = 1-D[ i * rowsize + j]
...
If I forget about the 2-D array thing & try to treat this array as a simple 1-D array: array[0] = *(array+0) gives the base address of the first array & NOT the element array[0][0]. Why?
the *(array+0) means a pointer to a array. the first element index in such format should be *((*array+0)+0).
so finally it should be *(*array)
A 2-D array does not store any memory address (like an Array of Pointers).
of course, you can . for example ,
int * array[3][3] ={ null, };
If I know the base address, I must be able to access this memory as a linear 1- Dimensional Array.
use this formal 2-D[i][j] = 1-D[ i * rowsize + j]...
Arrays are not pointers.
In most circumstances1, 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 of the array.
The type of the expression array is "2-element array of 2-element array of int". Per the rule above, this will decay to "pointer to 2-element array of int (int (*)[2]) in most circumstances. This means that the type of the expression *array (and by extension, *(array + 0) and array[0]) is "2-element array of int", which in turn will decay to type int *.
Thus, *(array + i) gives you the i'th 2-element array of int following array (i.e., the first 2-element array of int is at array[0] (*(array + 0)), and the second 2-element array of int is at array[1] (*(array + 1)).
If you want to treat array as a 1-dimensional array of int, you'll have to do some casting gymnastics along the lines of
int *p = (int *) array;
int x = p[0];
or
int x = *((int *) array + 0);
1. The exceptions are when the array expression is an operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration.
I like H2CO3's answer. But you can also treat the pointer to the array as an incrementable variable like so:
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 4; i++)
{
printf("%d\n", *ptr);
ptr++;
}
the ++ operator works on pointers just fine. It will increment the pointer by one address of it's type, or size of int in this case.
Care must always be used with arrays in c, the following will compile just fine:
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 100; i++) //Note the 100
{
printf("%d\n", *ptr);
ptr++;
}
This will overflow the array. If you are writing to this you can corrupt other values in the program, including the i in the for loop and the address in the pointer itself.

Array Pointers and Manipulation

Suppose I have:
int (* arrPtr)[10] = NULL; // A pointer to an array of ten elements with type int.
int (*ptr)[3]= NULL;
int var[10] = {1,2,3,4,5,6,7,8,9,10};
int matrix[3][10];
Now if I do,
arrPtr = matrix; //.....This is fine...
Now can I do this:
ptr = var; //.....***This is working***
OR is it compulsory to do this:
ptr= (int (*)[10])var; //....I dont understand why this is necessary
Also,
printf("%d",(*ptr)[4]);
is working even though we declare
int (*ptr)[3]=NULL;
^^^
In some cases, Name of Array is Pointer to it's First Location.
So, when you do,
ptr = var;
You are assigning address of var[0] to ptr[0]
int var[10] declaration makes var as an int pointer
As both are int pointers, the operation is valid.
For Second Question,
When you declare a Pointer, It points to some address.
Say
int * ptr = 0x1234; //Some Random address
now when you write ptr[3], it's 0x1234 + (sizeof(int) * 3).
So Pointer works irrespective of it's declared array size.
So when ptr = NULL,
*ptr[4] will point to NULL + (sizeof(int) * 4)
i.e. A Valid Operation!
ptr and var aren't compatible pointers because ptr is a pointer to an array of 3 ints and var is an array of 10 ints, 3 ≠ 10.
(*ptr)[4] works likely because the compiler doesn't do rigorous boundary checks when indexing arrays. This probably has to do with the fact that a lot of existing C code uses variable-size structures defined something like this:
typedef struct
{
int type;
size_t size; // actual number of chars in data[]
unsigned char data[1];
} DATA_PACKET;
The code allocates more memory to a DATA_PACKET* pointer than sizeof(DATA_PACKET), here it would be sizeof(DATA_PACKET)-1+how many chars need to be in data[].
So, the compiler ignores index=4 when dereferencing (*ptr)[4] even though it's >= 3 in the declaration int (*ptr)[3].
Also, the compiler cannot always keep track of arrays and their sizes when accessing them through pointers. Code analysis is hard.
ptr is a pointer to array of 3 integers, so ptr[0] will point to the start of the first array, ptr[1] will point to the start of the second array and so on.
In your case:
printf("%d",(*ptr)[4]);
works as you print the element no 5 of the first array
and
printf("%d",(*ptr+1)[4]);
print the element no 5 of the second array ( which of course doesn't exists)
for example the following is the same as yours
printf("%d",ptr[0][4]);
but this doesn't mean that you depend on this as var is array of 10 integers, so ptr has to be decelared as
int *ptr = NULL
in this case to print the element no 5
printf("%d", ptr[4]);

Resources