how to differentiate integer pointer and integer array pointer - c

I was trying to differentiate integer pointer and integer array pointer and here's the code that I am using as an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ZLEN 5
typedef int zipdig[ZLEN] ;
#define UCOUNT 3
typedef int (*row5_pt)[ZLEN];
int main(int argc, char *argv[]) {
zipdig cmu = {8, 5, 2, 1, 3};
zipdig mit = {0, 2, 1, 3, 9};
zipdig ucb = {9, 4, 7, 2, 0};
int *univ[UCOUNT] = {mit, cmu, ucb};
int result1 = *univ[1];
row5_pt pt[UCOUNT] = {&mit, &cmu, &ucb};
int result2 = (*pt[1])[1];
printf("\nresult is %d \n", result1);
printf("\nthe size of dereferenced univ is %lu bytes \n", sizeof(*univ[1]));
printf("\nresult is %d \n", result2);
printf("\nthe size of dereferenced pt is %lu bytes \n", sizeof(*pt[1]));
return 0;
}
At first I am confused at the following two assignment:
int *univ[UCOUNT] = {mit, cmu, ucb};
row5_pt pt[UCOUNT] = {&mit, &cmu, &ucb};
here univ is an array of 3 integer pointers, and pt is an array of pointers that point to a 5-element int array. And my confusion is that in the first assignment, mit, cmu and ucb, these array identifiers are regarded as pointers, but when it comes to second assignment, why mit, cmu and ucb are regarded as array, not pointers?
Later I realized that this is due to the different pointer type that I use: the first assignment, the element of univ is an integer pointer, and mit, cmu, ucb are exactly regarded as integer pointer, but for second assignment, the element of pt is a pointer pointing to array, not integers, thus we could not directly use mit, cmu or ucb but have to use their address instead.
Is my understanding correct?

Yes, your understanding is correct.
The reason is the type of the the pointers involved. &mit is a pointer to the array whereas mit (in an expression) is gets converted into a pointer to the array's first element.
int a[10];
int *p = a; // 'a' decays into a pointer to its first element i.e. &a[0]
int *q = &a[0]; // Equivalent to the above
int (*x)[10] = &a; // &a is of type int(*)[10] i.e. a pointer to an array of 10 ints
Also see: What is array decaying?

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.

Array of pointers to an array of fixed size

I tried to assign two fixed-size arrays to an array of pointers to them, but the compiler warns me and I don't understand why.
int A[5][5];
int B[5][5];
int*** C = {&A, &B};
This code compiles with the following warning:
warning: initialization from incompatible pointer type [enabled by default]
If I run the code, it will raise a segmentation fault. However, if I dynamically allocate A and B, it works just fine. Why is this?
If you want a declaration of C that fits the existing declarations of A and B you need to do it like this:
int A[5][5];
int B[5][5];
int (*C[])[5][5] = {&A, &B};
The type of C is read as "C is an array of pointers to int [5][5] arrays". Since you can't assign an entire array, you need to assign a pointer to the array.
With this declaration, (*C[0])[1][2] is accessing the same memory location as A[1][2].
If you want cleaner syntax like C[0][1][2], then you would need to do what others have stated and allocate the memory dynamically:
int **A;
int **B;
// allocate memory for A and each A[i]
// allocate memory for B and each B[i]
int **C[] = {A, B};
You could also do this using the syntax suggested by Vlad from Moscow:
int A[5][5];
int B[5][5];
int (*C[])[5] = {A, B};
This declaration of C is read as "C is an array of pointers to int [5] arrays". In this case, each array element of C is of type int (*)[5], and array of type int [5][5] can decay to this type.
Now, you can use C[0][1][2] to access the same memory location as A[1][2].
This logic can be expanded to higher dimensions as well:
int A[5][5][3];
int B[5][5][3];
int (*C[])[5][3] = {A, B};
Unfortunately there's a lot of crappy books/tutorials/teachers out there who will teach you wrong things....
Forget about pointer-to-pointers, they have nothing to do with arrays. Period.
Also as a rule of thumb: whenever you find yourself using more than 2 levels of indirection, it most likely means that your program design is fundamentally flawed and needs to be remade from scratch.
To do this correctly, you would have to do like this:
A pointer to an array int [5][5] is called array pointer and is declared as int(*)[5][5]. Example:
int A[5][5];
int (*ptr)[5][5] = &A;
If you want an array of array pointers, it would be type int(*[])[5][5]. Example:
int A[5][5];
int B[5][5];
int (*arr[2])[5][5] = {&A, &B};
As you can tell this code looks needlessly complicated - and it is. It will be a pain to access the individual items, since you will have to type (*arr[x])[y][z]. Meaning: "in the array of array pointers take array pointer number x, take the contents that it points at - which is a 2D array - then take item of index [y][z] in that array".
Inventing such constructs is just madness and nothing I would recommend. I suppose the code can be simplified by working with a plain array pointer:
int A[5][5];
int B[5][5];
int (*arr[2])[5][5] = {&A, &B};
int (*ptr)[5][5] = arr[0];
...
ptr[x][y][z] = 0;
However, this is still somewhat complicated code. Consider a different design entirely! Examples:
Make a 3D array.
Make a struct containing a 2D array, then create an array of such structs.
There is a lot wrong with the line
int*** C = {&A, &B};
You're declaring a single pointer C, but you're telling it to point to multiple objects; that won't work. What you need to do is declare C as an array of pointers to those arrays.
The types of both &A and &B are int (*)[5][5], or "pointer to 5-element array of 5-element array of int"; thus, the type of C needs to be "array of pointer to 5-element array of 5-element array of int", or
int (*C[2])[5][5] = { &A, &B };
which reads as
C -- C is a
C[2] -- 2-element array of
*C[2] -- pointers to
(*C[2])[5] -- 5-element arrays of
(*C[2])[5][5] -- 5-element arrays of
int (*C[2])[5][5] -- int
Yuck. That's pretty damned ugly. It gets even uglier if you want to access an element of either A or B through C:
int x = (*C[0])[i][j]; // x = A[i][j]
int y = (*C[1])[i][j]; // y = B[i][j]
We have to explicitly dereference C[i] before we can index into the array it points to, and since the subscript operator [] has higher precedence than the unary * operator, we need to group *C[0] in parens.
We can clean this up a little bit. Except when it is the operand of the sizeof 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 of the array.
The expressions A and B have type int [5][5], or "5-element array of 5-element array of int". By the rule above, both expressions "decay" to expressions of type "pointer to 5-element array of int", or int (*)[5]. If we initialize the array with A and B instead of &A and &B, then we need an array of pointers to 5-element arrays of int, or
int (*C[2])[5] = { A, B };
Okay, that's still pretty eye-stabby, but that's as clean as this is going to get without typedefs.
So how do we access elements of A and B through C?
Remember that the array subscript operation a[i] is defined as *(a + i); that is, given a base address a, offset i elements (not bytes)1 from that address and dereference the result. This means that
*a == *(a + 0) == a[0]
Thus,
*C[i] == *(C[i] + 0) == C[i][0]
Putting this all together:
C[0] == A // int [5][5], decays to int (*)[5]
C[1] == B // int [5][5], decays to int (*)[5]
*C[0] == C[0][0] == A[0] // int [5], decays to int *
*C[1] == C[1][0] == B[0] // int [5], decays to int *
C[0][i] == A[i] // int [5], decays to int *
C[1][i] == B[i] // int [5], decays to int *
C[0][i][j] == A[i][j] // int
C[1][i][j] == B[i][j] // int
We can index C as though it were a 3D array of int, which is a bit cleaner than (*C[i)[j][k].
This table may also be useful:
Expression Type "Decays" to Value
---------- ---- ----------- -----
A int [5][5] int (*)[5] Address of A[0]
&A int (*)[5][5] Address of A
*A int [5] int * Value of A[0] (address of A[0][0])
A[i] int [5] int * Value of A[i] (address of A[i][0])
&A[i] int (*)[5] Address of A[i]
*A[i] int Value of A[i][0]
A[i][j] int Value of A[i][j]
Note that A, &A, A[0], &A[0], and &A[0][0] all yield the same value (the address of an array and the address of the first element of the array are always the same), but the types are different, as shown in the table above.
Pointer arithmetic takes the size of the pointed-to type into account; if p contains the address of an int object, then p+1 yields the address of the next int object, which may be 2 to 4 bytes away.
A common misconception among C beginners is that they just assume pointers and arrays are equivalent. That's completely wrong.
Confusion comes to beginners when they see the code like
int a1[] = {1,2,3,4,5};
int *p1 = a1; // Beginners intuition: If 'p1' is a pointer and 'a1' can be assigned
// to it then arrays are pointers and pointers are arrays.
p1[1] = 0; // Oh! I was right
a1[3] = 0; // Bruce Wayne is the Batman! Yeah.
Now, it is verified by the beginners that arrays are pointers and pointers are arrays so they do such experiments:
int a2[][5] = {{0}};
int **p2 = a2;
And then a warning pops up about incompatible pointer assignment then they think: "Oh my God! Why has this array become Harvey Dent?".
Some even goes to one step ahead
int a3[][5][10] = {{{0}}};
int ***p3 = a3; // "?"
and then Riddler comes to their nightmare of array-pointer equivalence.
Always remember that arrays are not pointers and vice-versa. An array is a data type and a pointer is another data type (which is not array type). This has been addressed several years ago in the C-FAQ:
Saying that arrays and pointers are "equivalent" means neither that they are identical nor even interchangeable. What it means is that array and pointer arithmetic is defined such that a pointer can be conveniently used to access an array or to simulate an array. In other words, as Wayne Throop has put it, it's "pointer arithmetic and array indexing [that] are equivalent in C, pointers and arrays are different.")
Now always remember few important rules for array to avoid this kind of confusion:
Arrays are not pointers. Pointers are not arrays.
Arrays are converted to pointer to their first element when used in an expression except when an operand of sizeof and & operator.
It's the pointer arithmetic and array indexing that are same.
Pointers and arrays are different.
Did I say "pointers are not arrays and vice-versa".
Now you have the rules, you can conclude that in
int a1[] = {1,2,3,4,5};
int *p1 = a1;
a1 is an array and in the declaration int *p1 = a1; it converted to pointer to its first element. Its elements are of type int then pointer to its first element would be of type int * which is compatible to p1.
In
int a2[][5] = {{0}};
int **p2 = a2;
a2 is an array and in int **p2 = a2; it decays to pointer to its first element. Its elements are of type int[5] (a 2D array is an array of 1D arrays), so a pointer to its first element would be of type int(*)[5] (pointer to array) which is incompatible with type int **. It should be
int (*p2)[5] = a2;
Similarly for
int a3[][5][10] = {{{0}}};
int ***p3 = a3;
elements of a3 is of type int [5][10] and pointer to its first element would be of type int (*)[5][10], but p3 is of int *** type, so to make them compatible, it should be
int (*p3)[5][10] = a3;
Now coming to your snippet
int A[5][5];
int B[5][5];
int*** C = {&A, &B};
&A and &B are of type int(*)[5][5]. C is of type int***, it's not an array. Since you want to make C to hold the address of both the arrays A and B, you need to declare C as an array of two int(*)[5][5] type elements. This should be done as
int (*C[2])[5][5] = {&A, &B};
However, if I dynamically allocate A and B it works just fine. Why is this?
In that case you must have declared A and B as int **. In this case both are pointers, not arrays. C is of type int ***, so it can hold an address of int** type data. Note that in this case the declaration int*** C = {&A, &B}; should be
int*** C = &A;
In case of int*** C = {&A, &B};, the behavior of program would be either undefined or implementation defined.
C11: 5.1.1.3 (P1):
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined
Read this post for further explanation.
Arrays are not the same thing as multi-dimensional pointers in C. The name of the array gets interpreted as the address of the buffer that contains it in most cases, regardless of how you index it. If A is declared as int A[5][5], then A will usually mean the address of the first element, i.e., it is interpreted effectively as an int * (actually int *[5]), not an int ** at all. The computation of the address just happens to require two elements: A[x][y] = A + x + 5 * y. This is a convenience for doing A[x + 5 * y], it does not promote A to multidimensional buffer.
If you want multi-dimensional pointers in C, you can do that too. The syntax would be very similar, but it requires a bit more set up. There are a couple of common ways of doing it.
With a single buffer:
int **A = malloc(5 * sizeof(int *));
A[0] = malloc(5 * 5 * sizeof(int));
int i;
for(i = 1; i < 5; i++) {
A[i] = A[0] + 5 * i;
}
With a separate buffer for each row:
int **A = malloc(5 * sizeof(int *));
int i;
for(i = 0; i < 5; i++) {
A[i] = malloc(5 * sizeof(int));
}
You are being confused by the equivalence of arrays and pointers.
When you declare an array like A[5][5], because you have declared both dimensions, C will allocate memory for 25 objects contiguously. That is, memory will be allocated like this:
A00, A01, ... A04, A10, A11, ..., A14, A20, ..., A24, ...
The resulting object, A, is a pointer to the start of this block of memory. It is of type int *, not int **.
If you want a vector of pointers to arrays, you want to declare your variables as:
int *A[5], *B[5];
That would give you:
A0, A1, A2, A3, A4
all of type int*, which you would have to fill using malloc() or whatever.
Alternatively, you could declare C as int **C.
Although arrays and pointers are closely associated, they are not at all the same thing. People are sometimes confused about this because in most contexts, array values decay to pointers, and because array notation can be used in function prototypes to declare parameters that are in fact pointers. Additionally, what many people think of as array indexing notation really performs a combination of pointer arithmetic and dereferencing, so that it works equally well for pointer values and for array values (because array values decay to pointers).
Given the declaration
int A[5][5];
Variable A designates an array of five arrays of five int. This decays, where it decays, to a pointer of type int (*)[5] -- that is, a pointer to an array of 5 int. A pointer to the whole multi-dimensional array, on the other hand, has type int (*)[5][5] (pointer to array of 5 arrays of 5 int), which is altogether different from int *** (pointer to pointer to pointer to int). If you want to declare a pointer to a multi-dimensional array such as these then you could do it like this:
int A[5][5];
int B[5][5];
int (*C)[5][5] = &A;
If you want to declare an array of such pointers then you could do this:
int (*D[2])[5][5] = { &A, &B };
Added:
These distinctions come into play in various ways, some of the more important being the contexts where array values do not decays to pointers, and contexts related to those. One of the most significant of these is when a value is the operand of the sizeof operator. Given the above declarations, all of the following relational expressions evaluate to 1 (true):
sizeof(A) == 5 * 5 * sizeof(int)
sizeof(A[0]) == 5 * sizeof(int)
sizeof(A[0][4]) == sizeof(int)
sizeof(D[1]) == sizeof(C)
sizeof(*C) == sizeof(A)
Additionally, it is likely, but not guaranteed, that these relational expressions evaluate to 1:
sizeof(C) == sizeof(void *)
sizeof(D) == 2 * sizeof(void *)
This is fundamental to how array indexing works, and essential to understand when you are allocating memory.
Either you should declare the third array like
int A[5][5];
int B[5][5];
int ( *C[] )[N][N] = { &A, &B };
that is as an array of pointers to two-dimensional arrays.
For example
#include <stdio.h>
#define N 5
void output( int ( *a )[N][N] )
{
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ ) printf( "%2d ", ( *a )[i][j] );
printf( "\n" );
}
}
int main( void )
{
int A[N][N] =
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 },
{ 16, 17, 18, 19, 20 },
{ 21, 22, 23, 24, 25 }
};
int B[N][N] =
{
{ 25, 24, 23, 22, 21 },
{ 20, 19, 18, 17, 16 },
{ 15, 14, 13, 12, 11 },
{ 10, 9, 8, 7, 6 },
{ 5, 4, 3, 2, 1 }
};
/*
typedef int ( *T )[N][N];
T C[] = { &A, &B };
*/
int ( *C[] )[N][N] = { &A, &B };
output( C[0] );
printf( "\n" );
output( C[1] );
printf( "\n" );
}
The program output is
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
25 24 23 22 21
20 19 18 17 16
15 14 13 12 11
10 9 8 7 6
5 4 3 2 1
or like
int A[5][5];
int B[5][5];
int ( *C[] )[N] = { A, B };
that is as an array of pointers to the first elements of two-dimensional arrays.
For example
#include <stdio.h>
#define N 5
void output( int ( *a )[N] )
{
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ ) printf( "%2d ", a[i][j] );
printf( "\n" );
}
}
int main( void )
{
int A[N][N] =
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 },
{ 16, 17, 18, 19, 20 },
{ 21, 22, 23, 24, 25 }
};
int B[N][N] =
{
{ 25, 24, 23, 22, 21 },
{ 20, 19, 18, 17, 16 },
{ 15, 14, 13, 12, 11 },
{ 10, 9, 8, 7, 6 },
{ 5, 4, 3, 2, 1 }
};
/*
typedef int ( *T )[N];
T C[] = { A, B };
*/
int ( *C[] )[N] = { A, B };
output( C[0] );
printf( "\n" );
output( C[1] );
printf( "\n" );
}
The program output is the same as above
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
25 24 23 22 21
20 19 18 17 16
15 14 13 12 11
10 9 8 7 6
5 4 3 2 1
depending on how you are going to use the third array.
Using typedefs (shown in the demonstrative program as commented) ssimplifies the arrays' definitions.
As for this declaration
int*** C = {&A, &B};
then in the left side there is declared a pointer of type int *** that is a scalar object while in the right side there is a list of initializers that have different type int ( * )[N][N].
So the compiler issues a message.
I am a great believer in using typedef:
#define SIZE 5
typedef int OneD[SIZE]; // OneD is a one-dimensional array of ints
typedef OneD TwoD[SIZE]; // TwoD is a one-dimensional array of OneD's
// So it's a two-dimensional array of ints!
TwoD a;
TwoD b;
TwoD *c[] = { &a, &b, 0 }; // c is a one-dimensional array of pointers to TwoD's
// That does NOT make it a three-dimensional array!
int main() {
for (int i = 0; c[i] != 0; ++i) { // Test contents of c to not go too far!
for (int j = 0; j < SIZE; ++j) {
for (int k = 0; k < SIZE; ++k) {
// c[i][j][k] = 0; // Error! This proves it's not a 3D array!
(*c[i])[j][k] = 0; // You need to dereference the entry in c first
} // for
} // for
} // for
return 0;
} // main()

Are arrays just the same as constant pointers or are there any another differences? [duplicate]

This question already has answers here:
C: differences between char pointer and array [duplicate]
(14 answers)
Closed 7 years ago.
I've read various articles and questions here on SO about pointers and arrays equivalency. Nearly each article explains it different. I know that arrays and pointers are strongly related and bellow are my experiments with pointers and arrays equivalency, including comments which explain given behavior (feel free to correct me if I'm wrong somewhere). My question is: are arrays are just constant pointers or is there also another differences?
#include <stdio.h>
int main ()
{
// declaring array this way in fact declares a pointer with name "a" which points to the first element in the array:
int a[] = {0,1,2,3,4};
// assigning an array to the pointer in fact assigns the address of the first array element to the pointer, those two are thus equivalents:
int *pa1 = a;
int *pa2 = &a[0];
printf("########################\n");
// REFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%p\n", (a+0)); // a+0 == 0+a
printf("%p\n", a);
printf("%p\n", &a[0]);
printf("%p\n", &0[a]); // a+0 == 0+a
printf("########################\n");
// DEREFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%d\n", *(a+0)); // a+0 == 0+a
printf("%d\n", *a);
printf("%d\n", a[0]);
printf("%d\n", 0[a]); // a+0 == 0+a
printf("########################\n");
// REFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%p\n", (a+1));
printf("%p\n", &a[1]);
// REFERENCING: pointers can use array syntax (following are equivalents)
printf("%p\n", (pa1+1));
printf("%p\n", &pa1[1]);
printf("########################\n");
// DEREFERENCING: assigning values via pointers using pointer/array syntax (following are equivalents)
*(pa1+1) = *(pa1+1) + 10;
pa2[1] = pa2[1] + 10;
// DEREFERENCING: arrays can use pointer syntax (following are equivalents)
printf("%d\n", *(a+1));
printf("%d\n", a[1]);
printf("%d\n", 1[a]);
// DEREFERENCING: assigning values via arrays using pointer/array syntax (following are equivalents)
*(a+2) = *(a+2) + 10;
a[2] = a[2] + 10;
// DEREFERENCING: pointers can use array syntax (following are equivalents)
printf("%d\n", *(pa1+2));
printf("%d\n", pa1[2]);
printf("%d\n", 2[pa1]);
printf("########################\n");
// REFERENCING: those two pointers points to the same address
printf("%p\n", pa1);
printf("%p\n", pa2);
// DEREFERENCING: those two pointers points to the same address
printf("%d\n", *pa1);
printf("%d\n", *pa2);
printf("########################\n");
// This is correct:
pa1++;
printf("%p\n", pa1);
printf("%d\n", *pa1);
printf("%p\n", pa2);
printf("%d\n", *pa2);
printf("########################\n");
return 0;
}
I would say that arrays are just constant pointers, the only thing that misleads me is that the error messages are different when I try to increment array and constant pointer, here is what I mean:
#include <stdio.h>
int main (){
int var1=0;
int * const ptr;
int a[] = {0,1,2,3,4,5};
// This gives an error:
// error: increment of read-only variable ‘ptr’
ptr++;
// This gives an error:
// error: lvalue required as increment operand
a++;
return 0;
}
If they are not the same can you please post some scenario where this difference is obvious?
Arrays and pointers are completely different animals.
Under most circumstances, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", but the array object itself is not a pointer.
This behavior has its roots in the B language, from which C was derived. In B, an array object was a pointer, and the subscript operation a[i] was interpreted as *(a + i) (offset i elements from address stored in a, dereference the result).
Ritchie kept the *(a + i) semantics, but got rid of the explicit pointer; C converts the array expression to a pointer expression instead (except when the array expression is the operand of the unary & or sizeof operators).
You may pretend, that arrays are the same as constant pointers, but in fact they are different types. One notable difference is a result of the sizeof operator. For instance:
#include <stdio.h>
int main(void)
{
int a[] = {0, 1, 2, 3, 4, 5};
int * const p = a;
printf("sizeof(a) = %zu\n", sizeof(a));
printf("sizeof(p) = %zu\n", sizeof(p));
}
For the former, you are getting total size of array. Assuming that sizeof(int) = 4, it prints 24. OTOH, for the latter, you just get the same as size of int pointer.
Also, you cannot use array initializer for pointer variable:
int * const p = {0, 1, 2, 3, 4, 5};
results into compiler's error if you set it with -pedantic-errors flag, e.g.:
error: excess elements in scalar initializer
Another important difference is that arrays are copied for each element during a struct assignment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct threeNumbers {
int t[3];
} a = {{1, 2, 3}}, b = {{4, 5, 6}};
int main(void)
{
a = b;
a.t[0] = 100;
printf("%d\n", a.t[0]); // prints 100
printf("%d\n", b.t[0]); // prints 4
}
This is not the case for pointers. Structures with const pointers cannot be assigned to each other. For non-const pointers members, only an adress is copied. If pointers were set with malloc, then this might result into memory leak.

What is the exact meaning of defining `int *p={1,2,3};`?

I am trying to learn pointers in c.
As per my understanding int *p={1,2,3}; defines a pointer to the array of integers i.e {1,2,3}. So I deduct that p[0] is the first element of this array i.e 1. But my compiler(dev c++) is not giving any value and hanging for output.
How to find other elements of this array i.e 2 and 3 in terms of p? i.e is there any way to get these value through the pointer variable p. Please guide.
Sample program:
#include<stdio.h>
#include<conio.h>
main()
{
int *p={1,2,3};
printf("%d\n",p[0]);
getch();
}
Update: What about
int (*p)[3]={1,2,3};
int *p={1,2,3};
it is invalid C code. The right of = has to be a value of pointer type, not an initializer list of int elements.
Please enable all your compiler warnings and fix them.
int p[] = {1, 2, 3};
is valid C code. It initializes an array of 3 int elements.
#include <stdio.h>
#include <conio.h>
int main(){
int a[] = {1,2,3};
//int *p={1,2,3};//invalid
int *p1=(int[]){1,2,3};//valid in C99
printf("%d\n", p1[0]);//1
p1=a;
printf("%d\n", p1[0]);//1
//int (*p)[3]={1,2,3};//invalid
int (*p2)[3]=&(int[]){1,2,3};//valid in C99
printf("%d\n", (*p2)[0]);//1
p2 = &a;
printf("%d\n", (*p2)[0]);//1
getch();
return 0;
}
Yes,int (*p)[3] means pointer to array of 3 integers(My instructer also refers it as 2-dimensional pointer), in simple words it means that it can store address of the 1st row of a 2-Dimensional array,As you go on Increment the p it will point to the next subsequent row of the 2-D array, As demonstrated in below example.
int main(void)
{
int ary[2][3]={{1,2,3},{4,5,6}};
int (*p)[3]=ary;
printf("using ary: %d %d\n",p[0],p[1]); // outputs:2686708 2686720
printf("using ptr: %d %d\n",ary[0],ary[1]); //outputs:2686708 2686720
return 0;
}
And i think you are forgetting the basic property of pointers,They are used to store the address of other variables,You can't initialize pointers as you did in example,That is applicable only for strings,I feel you are trying to initialize integers pointers in the way of strings.
char *ptr="hello"; //correct
char *ptr[]={"hi","bye" } // correct
int *pttr=123; //Not Correct
int *pttr[]={{123},{456}} //Not Correct

Resources