How is `int (*arr1)[10]` different from `int arr2[10]`? - arrays

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;

Related

Weird pointer to array syntax

What is the logic motivating int (*arr)[5]; to declare arr as a pointer to an array of 5 elements, whereas int *arr[5] declares arr as an array of 5 pointers ? Especially given that * has low priority (unsure about this part since it isn't used as the dereferencing operator) ?
In both declarations and expressions, postfix operators like [] have higher precedence than unary operators like *, so a declaration like
T *a[N];
is parsed as
T *(a[N]);
Thus
a -- a is
a[N] -- an N-element array of
*a[N] -- pointer to
T *a[N]; -- T
If you want to declare a as a pointer to an array, then you need to explicitly group the * operator with a:
T (*a)[N];
Thus:
a -- a is
(*a) -- a pointer to
(*a)[N] -- an N-element array of
T (*a)[N]; -- T
As luck would have it, you're far more likely to be using an arrays of pointers than pointers to arrays, so it makes sense that the "simpler" form of declaration results in that type.
You've already stated the reason: * has lower precedence than [].
So
int *a[5];
is
int *(a[5]);
meaning that a is an array first, and what it's an array of is pointers.
To me, this is a fine result. I declare arrays of pointers all the time, and int a[5] is convenient syntax. Trying to type int (*a)[5] feels very strange, but that's okay, because I never declare pointers to arrays (because they're virtually never useful).
What is the logic motivating int (*arr)[5];
It depends on the context. For example if you have a two-dimensional array then you can use a pointer of such a type as an iterator.
Here is a demonstrative program
#include <stdio.h>
int main( void )
{
int a[2][5] =
{
{ 0, 1, 2, 3, 4 },
{ 5, 6, 7, 8, 9 }
};
for (int(*row)[5] = a; row != a + 2; ++row)
{
for (int *col = *row; col != *row + 5; ++col)
{
printf("%d ", *col);
}
putchar('\n');
}
return 0;
}
Or if you have a function that declares its parameter as a two-dimensional array as for example
void f( int a[][5], size_t n );
then the parameter implicitly is adjusted to pointer of the type int ( * )[5]
Take into account that if you have an array like this
int * a[5];
then a pointer to the array will look
int * ( *p )[5] = &a;
While if you have an array like this
int a[5];
then a pointer to the array will look like
int ( *p )[5] = &a;

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()

C assigning the address of a 2D array to a pointer

I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?
First, some background:
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.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.
The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes
You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.
You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.
Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same address.

Confusion with Two Dimensional Array

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

In C, what does a variable declaration with two asterisks (**) mean?

I am working with C and I'm a bit rusty. I am aware that * has three uses:
Declaring a pointer.
Dereferencing a pointer.
Multiplication
However, what does it mean when there are two asterisks (**) before a variable declaration:
char **aPointer = ...
Thanks,
Scott
It declares a pointer to a char pointer.
The usage of such a pointer would be to do such things like:
void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x
Here's another example:
char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome
Use of ** with arrays:
char** array = malloc(sizeof(*array) * 2); //2 elements
(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]
printf("%s", array[1]); //outputs There
The [] operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1] would be evaluated is as follows:
array[1] == *(array + 1);
This is one of the reasons why array indices start from 0, because:
array[0] == *(array + 0) == *(array);
C and C++ allows the use of pointers that point to pointers (say that five times fast). Take a look at the following code:
char a;
char *b;
char **c;
a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"
The variable a holds a character. The variable b points to a location in memory that contains a character. The variable c points to a location in memory that contains a pointer that points to a location in memory that contains a character.
Suppose that the variable a stores its data at address 1000 (BEWARE: example memory locations are totally made up). Suppose that the variable b stores its data at address 2000, and that the variable c stores its data at address 3000. Given all of this, we have the following memory layout:
MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
It declares aPointer as a pointer to a pointer to char.
Declarations in C are centered around the types of expressions; the common name for it is "declaration mimics use". As a simple example, suppose we have a pointer to int named p and we want to access the integer value it's currently pointing to. We would dereference the pointer with the unary * operator, like so:
x = *p;
The type of the expression *p is int, so the declaration of the pointer variable p is
int *p;
In this case, aPointer is a pointer to a pointer to char; if we want to get to the character value it's currently pointing to, we would have to dereference it twice:
c = **aPointer;
So, going by the logic above, the declaration of the pointer variable aPointer is
char **aPointer;
because the type of the expression **aPointer is char.
Why would you ever have a pointer to a pointer? It shows up in several contexts:
You want a function to modify a pointer value; one example is the strtol library function, whose prototype (as of C99) is
long strtol(const char * restrict str, char ** restrict ptr, int base);
The second argument is a pointer to a pointer to char; when you call strtol, you pass the address of a pointer to char as the second argument, and after the call it will point to the first character in the string that wasn't converted.
Remember that in most contexts, an expression of type "N-element array of T" is implicitly converted to type "pointer to T", and its value is the address of the first element of the array. If "T" is "pointer to char", then an expression of type "N-element array of pointer to char" will be converted to "pointer to pointer to char". For example:
void foo(char **arr)
{
size_t i = 0;
for (i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
void bar(void)
{
char *ptrs[N] = {"foo", "bar", "bletch", NULL};
foo(ptrs); // ptrs decays from char *[N] to char **
}
You want to dynamically allocate a multi-dimensional array:
#define ROWS ...
#define COLS ...
...
char **arr = malloc(sizeof *arr * ROWS);
if (arr)
{
size_t i;
for (i = 0; i < ROWS; i++)
{
arr[i] = malloc(sizeof *arr[i] * COLS);
if (arr[i])
{
size_t j;
for (j = 0; j < COLS; j++)
{
arr[i][j] = ...;
}
}
}
}
It means that aPointer points to a char pointer.
So
aPointer: pointer to char pointer
*aPointer :pointer to char
**aPointer: char
An example of its usage is creating a dynamic array of c strings
char **aPointer = (char**) malloc(num_strings);
aPointer gives you a char, which can be used to represent a zero-terminated string.
*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]
This is a pointer to a pointer to char.

Resources