Why *pointer_name behaves differently in 1D and 2D array - c

Why is it that when *q is used in 1D array it gives the value in the array whereas *p in 2D array gives an address instead. Isn't *pointer_name supposed to tell what is stored, so why is output an address instead of 40 (the value in array)?
#include<stdio.h>
int main(){
int a[3][4] = {
{40, 1, 2, 3} ,
{4, 5, 6, 7} ,
{8, 9, 10, 11}
};
int (*p)[4] = a;
int b[4] = {3,4,8,5};
int *q = b;
printf("%d, %d",*q, *p);// output- 3, 10485040
return 0;
}

Because p is a pointer to an array. When you dereference p the array will decay to a pointer to the first element. Doing *p and &(*p)[0] is equivalent (and also equivalent to &a[0][0]).
If you want to print the first element then you need to dereference both pointers, i.e. **p.

2D array means an array of arrays! so each slot of first row in the 2D array should have the address of another array.
for instance if you have an array a[2][3] , the a[0] value is the address of the first slot of an array with size 4. and a[1] like so etc .

Related

Pointer variable pointing to a one dimensional array or two dimensional array?

I have the following code for a one dimensional array:
#include <stdio.h>
int main()
{
static int b[4] = {11, 12, 13, 14};
int (*p)[4];
p = b;
printf("%d \n", *(p + 1));
return 0;
}
Even though I consider "b (the array name)" as a pointer pointing to a one dimensional array, I got a compiling error as
'=': cannot convert from 'int [4]' to 'int (*)[4]'
However, if I change b array into a two dimensional array "a (the array name)", everything works fine. Does this mean that, in the usage of "int (*p)[4];", "*p" has to represent a[] as in the following:
static int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int (*p)[4];
p = a;
As a result, "int (*p)[4]" only provides the flexibility on the number of rows of a two dimensional array.
Any insights on this problem?
Arrays naturally decay to pointers to their first elements, depending on context. That is, when such a decay happen then plain b is the same as &b[0], which have the type int *. Since the types of p and b (or &b[0]) are different you get an error.
As for a it's the same thing here, it decays to a pointer to its first element, i.e. a is the same as &a[0]. But since a[0] is an array of 4 elements, then &a[0] is a pointer to an array of four elements, or int (*)[4]. Which is also the type of p in the second example.
If you have an object of some type T like
T a;
then declaration of a pointer to the object will look like
T *p = &a;
Your array b has the type int[4]. So a pointer to the array will look like
int ( *p )[4] = &b;
To output the second element of the array using the pointer you should write
printf("%d \n", *( *p + 1 ) );
Thus your compiler issued the error message
cannot convert from 'int [4]' to 'int (*)[4]
because instead of writing at least
int ( *p )[4] = &b;
you wrote
int ( *p )[4] = b;
On the other hand, an array designator used in expressions with rare exceptions is implicitly converted to pointer to its first element. For example in this declaration
int *p = b;
the array b used as an initializer is converted to pointer to its firs element. The above declaration is equivalent to
int *p = &b[0];
or that is the same
int *p = b + 0;
Using this pointer you can call the function printf like
printf("%d \n", *(p + 1));
If you have a two-dimensional array as
int a[3][4];
then used in expressions it is converted to pointer to its first element that has the type int[4]. So you may write
int ( *p )[4] = a;
If you want to declare a pointer to the whole array as a single object you can write
int ( *p )[3][4] = &a;
a pointer pointing to a one dimensional array,
No, it points directly to the first element. Likewise:
int *p = b;
is enough.
The number 4 is not really part of any type here;
static int b[] = {11, 12, 13, 14};
It can be left out in the declaration. (Because it is the first dimension unless you make it 2D)
This (from AA)
int (*p)[4] = &b;
...
printf("%d \n", *( *p + 1 ) );
is just a obfuscated and overtyped version of:
int (*p)[] = &b;
...
printf("%d \n", (*p)[1] );
This replaces b with (*p), normally not what you want.

What is the difference between these two C declarations

I declared and initialized a 2x2 array as follows:
int arr[2][2] = {1, 2, 3, 4};
Then, a pointer to integer:
int *p1;
Initialize the pointer as:
p1 = arr[0]; //p1 points to {1, 2}
Now I can print elements using p1 as *p1
Now, when I declare:
int (*ptr)[2][2];
ptr = &arr;
To print the elements, now I have to use:
printf("%d\n", *(**(ptr)+1));
What is the difference between these two declarations?
int (*ptr)[2][2]; is a pointer to a 2x2 matrix, not a pointer to an int. Since each dimension of a matrix behaves somewhat like a pointer, that is why you need extra dereferencing in the printf.

Failed to initialize a pointer array in C

int array[2] = {1, 1};
int (*pointer_array)[2] = {NULL, NULL};
The first line can be correctly compiled but not the second one? Why?
GCC compiler will pop up a warning, excess elements in scalar initializer.
How to initialize a pointer array in C?
EDITED
I declared a pointer array in a wrong way.
It should be like this:
int *pointer_array[2] = {NULL, NULL};
It should be
int (*pointer_array)[2]=(int[]){1,2};
This is pointer to array of int .I don't know you want pointer to array of int or array of pointers.
To declare as array of pointer you need to do this -
int *pointer_array[2];
Suppose you have an array of int of length 5 e.g.
int x[5];
Then you can do a = &x;
int x[5] = {1};
int (*a)[5] = &x;
To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).
Understand what you asked in question is a compilation time error:
int (*a)[3] = {11, 2, 3, 5, 6};
It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].
Additionally,
You can do something like for one dimensional:
int *why = (int[2]) {1,2};
Similarly, for two dimensional try this(thanks #caf):
int (*a)[5] = (int [][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };

Initializing "a pointer to an array of integers"

int (*a)[5];
How can we Initialize a pointer to an array of 5 integers shown above.
Is the below expression correct ?
int (*a)[3]={11,2,3,5,6};
Suppose you have an array of int of length 5 e.g.
int x[5];
Then you can do a = &x;
int x[5] = {1};
int (*a)[5] = &x;
To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).
Understand what you asked in question is an compilation time error:
int (*a)[3] = {11, 2, 3, 5, 6};
It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].
Additionally,
You can do something like for one dimensional:
int *why = (int p[2]) {1,2};
Similarly, for two dimensional try this(thanks #caf):
int (*a)[5] = (int p[][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };
{11,2,3,5,6} is an initializer list, it is not an array, so you can't point at it. An array pointer needs to point at an array, that has a valid memory location. If the array is a named variable or just a chunk of allocated memory doesn't matter.
It all boils down to the type of array you need. There are various ways to declare arrays in C, depending on purpose:
// plain array, fixed size, can be allocated in any scope
int array[5] = {11,2,3,5,6};
int (*a)[5] = &array;
// compound literal, fixed size, can be allocated in any scope
int (*b)[5] = &(int[5]){11,2,3,5,6};
// dynamically allocated array, variable size possible
int (*c)[n] = malloc( sizeof(int[n]) );
// variable-length array, variable size
int n = 5;
int vla[n];
memcpy( vla, something, sizeof(int[n]) ); // always initialized in run-time
int (*d)[n] = &vla;
int a1[5] = {1, 2, 3, 4, 5};
int (*a)[5] = &a1;
int vals[] = {1, 2};
int (*arr)[sizeof(vals)/sizeof(vals[0])] = &vals;
and then you access the content of the array as in:
(*arr)[0] = ...

passing the array inside a function

int f(int b[][3]);
int main()
{
int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
f(a);
printf("%d\n", a[2][1]);
}
int f(int b[][3])
{
++b;
b[1][1] = 1;
}
3x3 => 9 elements contained in the 2-D array a. When it's passed, then b will contain the the base address of the a. If suppose base address is 1000 then ++b how does it to 3 locations and not 9 locations ahead? Are we doing typecasting when the variable a is passed to b[][3] as only the three elements?
How does b[1][1] correspond to the address of 8 and not 5?
We can't do incrementing or decrementing in an array as array is a const pointer, but how is that they are incrementing ++b as its an array?
The function heading
int f(int b[][3])
is a nothing more than a confusing way to write (and is exactly equivalent to)
int f(int (*b)[3])
The type of b is "pointer to three-element array of int". When you increment the b parameter you adjust it to point to the next three-element array of int -- now it points to {4,5,6}. Then b[1] indexes once more and gives you the array {7,8,9} and finally b[1][1] gives you the oneth element of that array, namely 8.
C multidimensional arrays are really linear, except that there is syntactic sugar to do the arithmetic correctly.
so with b[][3], it excepts a 1-D array and implicitly translates b[i][j] --> b[3*i+j]
++b works as follows: (++b)[i][j] = ORIGINAL_b[i+1][j]. So in your case, you are accessing ORIGINAL_b[1+1][1] = ORIGINAL_b[2*3+1] = ORIGINAL_b[7] (the 8th element)
Note: this is in stark contrast to the dynamic malloc version (in **b, b is a array of pointers)
How is b[1][1] corresponds to the address of 8 and not address of 5?
This is expected behavior:
int f(int b[][3])
{
//at this point b[0][0] is 1, b[1][1] is 5
++b;
//now b[0][0] is 4, b[1][1] is 8
b[1][1]=1;
}
The pointer has incremented to point to the next memory slot, which is the second slot of array a. Basically:
b -> a[0]
++b -> a[1]

Resources