What is the difference between these two C declarations - c

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.

Related

Pointers problems with C

I don't understand the difference in the t and p pointers. The t pointer gives the same output when printing t and *t only when using **t I get the value.
What's the difference between them?
The code is:
int main()
{
int B [2][3] = {
{2, 3, 6},
{4, 5, 8}
};
int *p = B;
int (*t)[3] = B;
printf ("%d\n", p);
printf ("%d\n", t);
printf ("%d\n", *p);
printf ("%d\n", *t);
printf ("%d\n", **t);
return 0;
}
Output is:
6422000
6422000
2
6422000
2
Comments have addressed the importance of using the correct format specifiers, but here are a couple of other points to consider:
point 1:
The declaration: int *p = B; should generate a compile time warning. This is because int *p is a simple pointer to int, as such it should only be set to point to the address of (&) a single int. But B does not represent an int.
For illustration, it is instructive to see the variations of warnings for the following 3 incorrect ways of initializing p with B. Each starts off with the phrase:
_"warning: incompatible pointer types initializing `int *` with an..."_:
int *p = B;//...expression of type 'int [2][3]'
int *p = &B;//...expression of type 'int (*)[2][3]'
int *p = &B[0]//...expression of type 'int (*)[3]'
Note the incompatible pointer types at the end of each warning. Each of them is specific, providing the programmer hints how to address the potential problem.
The following initializes *p with the address of a single int and generates no warning
int *p = &B[0][0];//assigning address of p to the location of a single integer value.
point 2:
The following declaration/assignment:
int (*t)[3] = B;
creates t as a pointer to an array of 3 int, and points t to the first instance (row) of 3 int in B where B is defined as:
int B [2][3] = {{2, 3, 6}, {4, 5, 8}};
Because t is defined in this way it is flexible in the way it can be used in that it is pointable to any array of 3 int i.e. it does not matter how many rows B has, or to which row t is pointed. Example, given the following arrays:
int B[5][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
int A[3] = {0}; //A simple array of 3 int all set to 0
The following declarations can be made:
int (*t)[3] = NULL; //points to nothing
t = B; //points to location of 1st element of 1st row in B
t = &B[1]; //points to location of 1st element of 2nd row in B
t = &B[4]; //points to location of 1st element of 5th row in B
t = &A; //points to location of 1st element of A
Writing int *p = B; isn't a good idea but anyway, it puts the address of the very first element of B, 2 into p. So, p outputs the address(6422000) and *p outputs 2. All good till here.
What is t? It's a pointer to an array, B. What will happen when you print it, you'll get the address to B, which is always also the address of it's very first element, which happens to be 6422000. So, what will happen when you dereference t? You'll get and array, B in this case, which will then decay into a pointer and give you the memory address. And the memory address of B is 6422000. And **t will dereference the dereferenced array. The deference array is B, which will decay into the pointer, 6422000 in this case and that will be dereferenced again, giving 2.
Basically:
p: Address of the very first element of B, 2.
*p: Dereferenced p, in this case 2.
t: Address to B. Address of an array is also the address of it's very first element, equivalent to p.
*t: Dereferences into B, B will decay into it's very first element's pointer, equivalent to p.
**t: Dereferenced *t, which is 2.
Note: I know, the first element of B is {2, 3, 6}, not 2. I refer to 2 as "the very first element". That's inaccurate but for the purpose of explanation, I was forced to use the terminology.

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.

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

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 .

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] = ...

Resources