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()
Related
I know that 2D array is basically pointer to array so in the following code a is pointer to 0th index that is itself an array and than *a should return address of 0th index element how a and *a both return same value
#include <stdio.h>
#include <stdio.h>
int main () {
int a[4] [5] = {{1, 2, 3, 4, 5},
{6, 7,8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17,18, 19, 20}};
printf("%d\n",a);
printf("%d\n",*a);
}
For starters to output a value of a pointer you should use the conversion specifier %p instead of %d.
printf( "%p\n", ( void * )a );
printf( "%p\n", ( void * )*a) ;
The array designator a used as an argument expression is implicitly converted to a pointer to its first element. As the array declared as a two-dimensional array like
int a[4] [5] = {{1, 2, 3, 4, 5},
{6, 7,8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17,18, 19, 20}};
then its elements have the type int [5] and the pointer (having the type int ( * )[5]) to which the array is implicitly converted will have the address of the first "row" of the array that is the initial address of the extent of memory occupied by the array.
Dereferencing the pointer you will get the first "row" that is the array a[0] of the type int [5]. Again used as an argument expression it is implicitly converted to a pointer of the type int * to its first element a[0][0]. And the address of the first element of the first "row" that is the initial address of the extent of memory occupied by the array is outputted.
That is the addresses of the array as whole, of its first "row" and of the first element of the first "row" are equal each other. But the corresponding expressions, &a, a, *a (after implicit conversion to pointers) have different types. The expression &a has the type int ( * )[4][5], the expression a (after the implicit conversion) has the type int ( * )[5] and the expression *a (also after the implicit conversion) has the type int *. But their values are equal each other.
I know that 2D array is basically pointer to array
No, it is not. Arrays when used in most expressions "decay" to a pointer to the first element, but that does not make arrays pointers.
so in the following code a is pointer to 0th index
Only in the expression printf("%d\n",a); where a decays into a pointer to its first element. The first element of a is an array of type int [5], so in this printf expression, a decayed to a pointer to such an element, a int (*)[5] type.
Using %d to print pointers is not well-defined behavior so the code is wrong, you should be using %p and cast the parameter to void*: printf("%p\n", (void*)a);
how a and *a both return same value
For any array, the array itself and it's first element naturally reside at the very same address or the concept of arrays wouldn't make any sense. The very definition of an array is a contiguous chunk of items with the same type allocated at contiguous addresses.
When you de-reference *a, you de-reference the decayed array a of type int(*)[5] and get a type int [5]. But since arrays cannot be used in most expressions, this too can be said to decay into a pointer to the first element of int [5], meaning type int*, pointing at item [0] in the first array.
There are already two valuable answers above but I think you're still confused about the situation; for I felt the same while I was a rookie (though I'm not a pro yet).
The line below does not return a pointer. Actually, it returns a memory address and the first address holds the first element of the array as data; but as it is on stack, C treats it like a pointer.
int a[4][5] = { ... };
The lines below, again, return memory addresses on stack, but they hold other memory addresses and this time, they are literally pointers; they point to different memory addresses —most probably on the heap.
int** b = malloc(4 * sizeof(int*));
int* c = malloc(5 * sizeof(int));
Do not keep your hands clean and debug the code below and inspect the output while keeping an eye on the memory dump at the same time:
#include <stdio.h>
#include <stdlib.h>
int** copyArray(int row, int col, int pSrc[row][col]) {
int** pDst = malloc(row * sizeof(int*));
for (int i = 0; i < row; i++) {
pDst[i] = malloc(col * sizeof(int));
for (int j = 0; j < col; j++) {
pDst[i][j] = pSrc[i][j];
}
}
return pDst;
}
int main() {
int a[4][5] = { { 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 },
{ 16, 17, 18, 19, 20 } };
int** b = copyArray(4, 5, a);
printf("%2d %2d %2d %2d %2d\n", a[0][0], a[0][1], a[0][2], a[0][3], a[0][4]);
printf("%p\n", &a);
printf("%p\n", a);
printf("%p\n", *a);
printf("%p\n", a[0]);
printf("%p\n", &a[0]);
printf("\n");
printf("%2d %2d %2d %2d %2d\n", b[0][0], b[0][1], b[0][2], b[0][3], b[0][4]);
printf("%p\n", &b);
printf("%p\n", b);
printf("%p\n", *b);
printf("%p\n", b[0]);
printf("%p\n", &b[0]);
for (int i = 0; i < 4; i++) {
free(b[i]);
}
free(b);
return 0;
}
I know that 2D array is basically pointer to array
No. A 2D array is an array of arrays - no pointers are involved. It would be laid out in memory as
+––––+
a: | 1 | a[0][0]
+––––+
| 2 | a[0][1]
+––––+
| 3 | a[0][2]
+––––+
| 4 | a[0][3]
+––––+
| 5 | a[0][4]
+—–––+
| 6 | a[1][0]
+––––+
| 7 | a[1][1]
+—–––+
| 8 | a[1][2]
+––—–+
| 9 | a[1][3]
+––––+
| 10 | a[1][4]
+––––+
| 11 | a[2][0]
+––––+
| 12 | a[2][1]
+–——–+
...
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize the contents of a character array in a declaration, an expression of type "N-element of T" will be converted, or "decay", to an expression of type "pointer to T".
As can be seen from the diagram above, the expressions a, a[0], and a[0][0] all have the same starting address.
The expression a has type "4-element array of 5-element array of int" - unless it is the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to 5-element array of int" (int (*)[5]) and its value is the address of a[0].
The expression *a is identical to the expression a[0] and has type "5-element array of int" - again, unless it is the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to int" and its value is the address of (*a)[0] (which is identical to the address of a[0][0]).
The expressions a, *a, &a, a[0], and &a[0][0] all yield the same address value (modulo any representational differences between types), but they have different types:
Expression Type "Decays" to Equivalent expression
---------- ---- ----------- ---------------------
a int [4][5] int (*)[5] &a[0]
*a int [5] int * &(*a)[0] or &a[0][0]
&a int (*)[4][5] n/a n/a
a[i] int [5] int * &a[i][0]
&a[i] int (*)[5] n/a n/a
a[i][j] int n/a n/a
&a[i][j] int * n/a n/a
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.
As I was going though some code examples, I encountered this way of declaration:
int (*arr1)[10]
I am aware of another way of array declaration in C:
int arr2[10]
Is int (*arr1)[10] doing the same as int arr2[10]?
The differences are as follows:
int (*arr1)[10]; // arr1 is a pointer to a 10-element array of int
int *arr2[10]; // arr2 is a 10-element array of pointer to int
This is important - despite the [10] at the end, arr1 is not an array; it only stores a single pointer value, which is the address of some 10-element array of int.
Pointers to arrays crop up in two main circumstances - when an N-dimensional array expression "decays" to a pointer expression, and when we're allocating memory for an N-dimensional array.
First, the decay rule - except when it is the operand of the sizeof or the unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted, or "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. You've probably seen this before with code like:
int arr[10];
int *p = arr; // arr "decays" to a pointer to its first element
The expression arr "decays" from type "10-element array of int" to type "pointer to int".
The exact same thing happens with 2D arrays:
int arr[5][10];
int (*p)[10] = arr;
The expression arr "decays" from type "5-element array of 10-element array of int" to type "pointer to 10-element array of int".
You can also obtain a pointer to a 1D array directly with the unary & operator:
int arr[10];
int (*p)[10] = &arr; // note presence of & operator here
but that's not very common.
Another use for pointers to arrays is when we want to dynamically allocate a contiguous 2D (or higher-dimensioned) array:
int (*p)[10] = malloc( sizeof *p * 5 ); // allocates space for a 5x10 array of int
The type of the expression *p is "10-element array of int", or int [10], so sizeof *p is equivalent to sizeof (int [10]), so the malloc call sets aside enough space for 5 10-element arrays of int. You would index into this array like any other 2D array: p[i][j] = some_value();. The rows of this array are contiguous in memory and all the same length, and it only requires a single call to free to deallocate.
You've probably seen code that dynamically allocates 2D arrays in multiple steps - first you allocate an array of pointers, then for each of those pointers you allocate an array of the target type, like so:
int **p = malloc( sizeof *p * R ); // allocates an R-element array of pointer to int
if ( p )
{
for ( size_t i = 0; i < R; i++ )
{
p[i] = malloc( sizeof *p[i] * C ); // allocates a C-element array of int
}
}
The difference here is that in the second case, the rows are not adjacent in memory - it's not a single, continuous block. Also, different rows may be different lengths (what's sometimes called a "jagged" array). You also have to free each row separately before freeing p.
The basic rules of pointer declarations are:
T *p; // p is a pointer to T
T *a[N]; // a is an array of pointer to T
T *f(); // f is a function returning pointer to T
T (*a)[N]; // a is a pointer to an N-element array of T
T (*f)(); // f is a pointer to a function returning T
T const *p; // p is a non-const pointer to const T - you can modify p to point
// to a different object, but you cannot modify the thing p points to
const T *p; // same as above
T * const p; // p is a const pointer to non-const T - you can modify what p
// p points to, but you can't modify p to point to a different object
// (which means p needs to be initialized to a valid pointer value
// when it's declared).
T const * const p; // p is a const pointer to const T - you can't update either
// p or *p
const T * const p; // same as above.
If in this specification
int (*arr1)[10]
you will remove the term in the parentheses you will get int[10]. The term in the parentheses denotes a pointer. So you have a pointer to an array of 10 elements of the type int. For example
int a[10];
int ( *arr )[10] = &a;
Dereferencing the pointer you will get the array (the object of the array type pointed to by the pointer) itself.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
enum { N = 10 };
int a[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int ( *arr )[N] = &a;
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", ( *arr )[i] );
}
putchar( '\n' );
return 0;
}
The program output is
0 1 2 3 4 5 6 7 8 9
Instead of these declarations you could use declarations based on a typedef like
enum { N = 10 };
typedef int Array[N];
Array a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Array *arr = &a;
Since there's no such thing as an array in the C language, is the following all stored in one memory location, or is each element's value stored in an "array" of memory locations?
int array[] = {11, 13, 17, 19};
Scenario 1
{11, 13, 17, 19} --> location A
Scenario 2
{
11 --> location A
13 --> location B
17 --> location C
19 --> location D
}
Which one is the valid memory layout?
C explicitly defines "array" as a type.
Quoting C11, chapter §6.2.5, Types (emphasis mine)
An array type describes a contiguously allocated nonempty set of objects with a
particular member object type, called the element type. The element type shall be
complete whenever the array type is specified. Array types are characterized by their
element type and by the number of elements in the array. An array type is said to be
derived from its element type, and if its element type is T, the array type is sometimes
called ‘‘array of T’’. The construction of an array type from an element type is called
‘‘array type derivation’’.
In a nutshell, the answer is, array elements are stored in separate but contiguous locations.
Let's suppose we have declared an array of 5 int:
int arr[5];
Then, on a platform where the size of an integer is 2 bytes (szeof(int) ==2), the array will have its elements organized like this:
On a different platform, where sizeof(int) == 4, it could be:
So the representation
{
11 --> location A
13 --> location B
17 --> location C
19 --> location D
}
is valid, considering B == A + 1, C == B + 1 and so on.
Here, please note, the pointer arithmetic regards the data type, so A+1 will not result in an address with 1 byte increment, rather the increment is by one element. In other words, the difference between the address of two consecutive element will be the same as the size of the datatype (sizeof (datatype)).
The elements would be in contiguous memory location.
Let array[0] is at location B and the size of each element of the array, i.e. sizeof(int), is S. Then we have this
array[0] at B
array[1] at B + S
array[2] at B + 2S
..
array[n] at B + n*S
C does have an array type. Just because you can access arrays via pointers doesn't mean they don't exist.
Array elements are stored in contiguous memory locations starting from the address "array" (i.e. the base address of array which is also the address of the first element of the array) and each element of the array is addressable separately.
Assuming 4 byte ints, the array int array[] = {11, 13, 17, 19}; would look like:
+-----+-----+-----+-----+
| 11 | 13 | 17 | 19 |
+-----+-----+-----+-----+
^ ^ ^ ^
0x100 0x104 0x108 0x112
You can probably understand better with a simple program:
#include <stdio.h>
int main(void)
{
int array[] = {11, 13, 17, 19};
/* all will print the same value */
printf("Base address of array: %p, %p, %p\n", (void*)array, (void*)&array[0], (void*)array);
for (size_t i = 0; i < sizeof array/sizeof array[0]; i++) {
printf("address of array[%d]: %p\n", i, (void*)&array[i]);
}
return 0;
}
One important detail is that though the addresses &array[0] and &array are the same value, their types are different. &array[0] is of type int* (pointer to an int) whereas &array is of type int(*)[4] (pointer to an array of 4 ints).
The compiler allocates the array in specific, contiguous locations.
You can also check it up with the next code:
#include <stdio.h>
void main()
{
int array[] = {11, 13, 17, 19};
for (int i = 0; i < 4; i++)
printf("0x%p ", &array[i]);
}
That gives the hexadecimal addresses
0x14fee0 0x14fee4 0x14fee8 0x14feec
with the margin of 4 bytes per element, the size of int.
Generally, you can take the pointer to one element of the array, say index m, and add it n as a number of elements, and get the pointer to the n+m index in the array.
*(array + n) == array[n]
Since there's no such thing as an array in the C language
There is totally such a thing as an array in the C language. All of your examples are C arrays.
The difference you are describing is the difference between a list and an array.
Arrays in C, as indeed in most languages, are like your Scenerio 1.
You could certainly accomplish your Scenerio 2 with an array of pointers to values. for example
int array1[] = {11, 14, 17, 19};
// vs
int* array2[] = {
&array1[0],
&array1[1],
&array1[2],
&array1[3]
};
A list however is quite different in organization.
struct list_node{
int value;
struct list_node * next;
};
struct int_list {
int length;
struct list_node * first;
};
int main(){
int i;
struct list_node nodes[4];
struct int_list list1 = {.length = 4, .first=&nodes[0]};
for (i = 0; i < 4; i++){
nodes[i].value = array1[i];
if (i != 3){
nodes[i].next = &nodes[i+1];
} else {
nodes[i].next = NULL;
}
}
// traverse the list.
struct list_node * n = list1.first;
while(n != NULL){
printf("%d\n", n->value);
n = n->next;
}
}
Sorry for asking the already answered question, I am a newbie to C and don't understand the solutions.
Here is my function
int rotateArr(int *arr) {
int D[4][4];
int i = 0, n =0;
for(i; i < M; i ++ ){
for(n; n < N; n++){
D[i][n] = arr[n][M - i + 1];
}
}
return D;
}
It throws an error
main.c|23|error: subscripted value is neither array nor
pointer nor vector|
on line
D[i][n] = arr[n][M - i + 1];
What's wrong? I am just setting the value of an array element to another array element.
The arr passed is declared as
int S[4][4] = { { 1, 4, 10, 3 }, { 0, 6, 3, 8 }, { 7, 10 ,8, 5 }, { 9, 5, 11, 2} };
C lets you use the subscript operator [] on arrays and on pointers. When you use this operator on a pointer, the resultant type is the type to which the pointer points to. For example, if you apply [] to int*, the result would be an int.
That is precisely what's going on: you are passing int*, which corresponds to a vector of integers. Using subscript on it once makes it int, so you cannot apply the second subscript to it.
It appears from your code that arr should be a 2-D array. If it is implemented as a "jagged" array (i.e. an array of pointers) then the parameter type should be int **.
Moreover, it appears that you are trying to return a local array. In order to do that legally, you need to allocate the array dynamically, and return a pointer. However, a better approach would be declaring a special struct for your 4x4 matrix, and using it to wrap your fixed-size array, like this:
// This type wraps your 4x4 matrix
typedef struct {
int arr[4][4];
} FourByFour;
// Now rotate(m) can use FourByFour as a type
FourByFour rotate(FourByFour m) {
FourByFour D;
for(int i = 0; i < 4; i ++ ){
for(int n = 0; n < 4; n++){
D.arr[i][n] = m.arr[n][3 - i];
}
}
return D;
}
// Here is a demo of your rotate(m) in action:
int main(void) {
FourByFour S = {.arr = {
{ 1, 4, 10, 3 },
{ 0, 6, 3, 8 },
{ 7, 10 ,8, 5 },
{ 9, 5, 11, 2}
} };
FourByFour r = rotate(S);
for(int i=0; i < 4; i ++ ){
for(int n=0; n < 4; n++){
printf("%d ", r.arr[i][n]);
}
printf("\n");
}
return 0;
}
This prints the following:
3 8 5 2
10 3 8 11
4 6 10 5
1 0 7 9
You are not passing your 2D array correctly. This should work for you
int rotateArr(int *arr[])
or
int rotateArr(int **arr)
or
int rotateArr(int arr[][N])
Rather than returning the array pass the target array as argument. See John Bode's answer.
Except when it is the operand of the sizeof or unary & operator, 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 the value of the expression is the address of the first element of the array.
If the declaration of the array being passed is
int S[4][4] = {...};
then when you write
rotateArr( S );
the expression S has type "4-element array of 4-element array of int"; since S is not the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 4-element array of int", or int (*)[4], and this pointer value is what actually gets passed to rotateArr. So your function prototype needs to be one of the following:
T rotateArr( int (*arr)[4] )
or
T rotateArr( int arr[][4] )
or even
T rotateArr( int arr[4][4] )
In the context of a function parameter list, declarations of the form T a[N] and T a[] are interpreted as T *a; all three declare a as a pointer to T.
You're probably wondering why I changed the return type from int to T. As written, you're trying to return a value of type "4-element array of 4-element array of int"; unfortunately, you can't do that. C functions cannot return array types, nor can you assign array types. IOW, you can't write something like:
int a[N], b[N];
...
b = a; // not allowed
a = f(); // not allowed either
Functions can return pointers to arrays, but that's not what you want here. D will cease to exist once the function returns, so any pointer you return will be invalid.
If you want to assign the results of the rotated array to a different array, then you'll have to pass the target array as a parameter to the function:
void rotateArr( int (*dst)[4], int (*src)[4] )
{
...
dst[i][n] = src[n][M - i + 1];
...
}
And call it as
int S[4][4] = {...};
int D[4][4];
rotateArr( D, S );
The problem is that arr is not (declared as) a 2D array, and you are treating it as if it were 2D.
You have "int* arr" so "arr[n]" is an int, right? Then your "[M - 1 + 1]" bit is trying to use that int as an array/pointer/vector.
the second subscript operator is invalid here.
You passed a int * pointer into function, which is a 1-d array. So only one subscript operator can be used on it.
Solution : you can pass int ** pointer into funciton