I am learning pointers and arrays in C and Here is a question that confused me for a while:
So the name of a 1D int array is a constant pointer to int, which points to the first element in that array. So when we evaluate the name of a 1D array, we should get the address of the first element in the array.
For a 2D int array, the array name is a pointer to the first array of int. So what will be the value of a 2D int array's name? I think it should be the address of the first array in this 2D array. But how is the address of an array defined in C? Is it just the address of the first element in that array?
So the name of a 1D int array is a constant pointer to int
This is wrong, and it is often taught badly. An array is an array. Here is some code for analogy:
int x = 5;
double d = x + 1.2;
In the second line x is converted to double for purposes of addition. This does not change x which is still an int, the result of conversion is "temporary" and only exists until the addition is finished. The conversion is demanded by the conditions of the + operator that both arithmetic operands must be brought to a common type (double in this case).
In the array case, say we have char *p = arrayname + 1 , then arrayname is still an array. But it is converted to a temporary pointer so that the addition can occur (the + operator requires this, it can add a pointer and an integer). The temporary pointer points to the first element of the array, but it is not correct to say that the temporary pointer is the array.
Most operators invoke this conversion of an array to a temporary pointer, but some do not. So it is not correct to say that arrayname is a pointer because it may be used with an operator that does not convert the array to a pointer, e.g. sizeof arrayname.
The result of converting an array to a pointer is a pointer to the first element of that array. This is always true even if the first element is itself an array.
But how is the address of an array defined in C? Is it just the address of the first element in that array?
No. Every variable has an address, this applies to arrays and non-arrays. If you understand the address of an int then you also understand the address of a 2x2 array of char.
Let's clear up some things:
int a = 24;
The above is many things:
a declaration: we declare a variable named a of type int.
a definition: an object of type int is created.
an initialization: this object is initialized with the value 24
So let's recap: an object of type int is created with the value 24 and the variable a names it.
Now let's apply the same to the following:
int a1[3] = {0, 1, 2};
a declaration: we declare a variable named a1 of type int[3] (aka array of 3 integers).
a definition: an object of type "array of 3 integers" is created
an initialization: the object is initialized with {0, 1, 2}
The variable a1 names that object.
So the name of a 1D int array is a constant pointer to int, which
points to the first element in that array.
Wrong. I know you might have been told or read this, but it is incorrect. An array is not a pointer!! Arrays and pointers are different types. That being said, for convenience and historical reasons, in most situations (but not all!) an array decays to a pointer to the first element:
int a1[3] = {0, 1, 2};
int* p = a1; // here a1 decays to a pointer to its first element
In the above snippet p points to the element 0 of the array a1
You can view 2D or 3D or nD array the same way:
T a2[3] = {l0, l1, l2};
Let's say T is a type. The above is an "array of 3 Ts".
if T is int then we have int a2[3] = {0, 1, 2} - an array of 3 integers. We call this an 1D int array.
but if T is int[2] then the above becomes int a2[3][2] = {{00, 01}, {10, 11}, {20, 21}} - you can see it as "an array of 3 Ts" or "an array of 3 int[2]" or "an array of 3 arrays of 2 integers".
And we can apply the same decaying rule:
int a2[3][2] = {{00, 01}, {10, 11}, {20, 21}};
int (*p2)[2] = a2; // a2 decays to a pointer to its first element.
// Its first element is an array of 2 int.
// So a2 decays to `int (*)[2]` - a pointer to an array of two elements.
In the above a2 points to the element {00, 01} of the array.
An arrays name is not a pointer. In most cases when the name of an array is used, it gets implicitly *converted* to a pointer to its first element, it is said, that the array decays into a pointer.
The name of an array does not decay to a pointer when it is the argument of the address-of operator (&), the sizeof-operator and when a string literal (which is an array of some character type) is used to initialize an array *).
That said, a two-dimensional arrays
T arr[COLS][ROWS];
first element is an array of type T[ROWS]. So arr decays to a pointer of type T(*)[ROWS] which points to the first element of arr.
*) If you might want to add that arrays also do not decay when they're the operand of the _Alignof-operator or read that somewhere else:
#EricPostpischi: Arrays cannot be operands of _Alignof. Including _Alignof in the exceptions for array conversion was an error in the C 2011 standard. _Alignof operands can only be types, not expressions.
When a 2D array decays to a pointer, you have a pointer to an array. Here's an example of what this would look like:
int arr[5][6];
int (*p)[6] = arr;
An array is not a pointer. An array's name, when used in an expression, "decays" into a pointer to the first element.
Strictly speaking, C only has one-dimensional arrays, and a 2D array is really just an array of arrays.
1D array:
The first element of int arr [x], is an int.
When arr is used in an expression, you get a pointer to that element, int*.
When doing pointer arithmetic on this pointer, each item has the size of the first element = sizeof(arr[0]).
2D array:
The first element of int arr [x][y] is an int [y].
When arr is used in an expression, you get a pointer to that element, int (*)[y].
When doing pointer arithmetic on this pointer, each item has the size of the first element = sizeof(arr[0]).
So it's the same rule. The int(*)[y] array pointer follows the same rules of pointer arithmetic as the ordinary pointer. But you can de-reference it one step further to get individual int in the array of arrays.
"So what will be the value of a 2D int array's name?"
"I actually understand that an array is not a pointer. In my question,
what I actually mean is that when the name of an array is used in an
expression, the compiler will generate the pointer constant."
You have to be careful here. As a follow-on to your comment below your question, there are nuances in how the array/pointer conversion rules apply that effect the type that results from the conversion. That will dictate whether and how you can use the array name in an expression.
"... the compiler will generate the pointer constant."
No. The compiler does not generate a pointer constant, the compiler follows C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). When the array name is used in an expression, the expression is evaluated with the address that results from the conversion of the array to a pointer (subject to the 4-exceptions stated in paragraph 3).
The rule regarding array/pointer conversion does not depend on number of dimensions, the rule is applied the same regardless. However, the type of the pointer that results from the conversion does depend on the number of array dimensions. That is critical and that will dictate whether your use of the array name is valid.
One way to help cement what is happening in the conversion is take it step-by-step. Start with a 1D array and work your way up.
6.3.2.1 - 1D Array Conversion To Pointer On Access
When you have a simple array, e.g.
int array[10];
On access to array, is converted to a pointer to the first element, e.g., the address of the element, &array[0]. (which is simply a pointer to int, or with formal type int *)
6.3.2.1 - 2D Array Conversion To Pointer On Access
With a 2D array, rule applies just the same, e.g.
int array[10][10];
Here array, a 2D array, is essentially an array of 10 - int[10] arrays (an array of 1D arrays). On access array[10][10] is converted to a pointer to the first array of 10-int in exactly the same manner, &array[0][0] (which results in a pointer to an array of int[10] or with formal type int (*)[10]) It is not a pointer-to-pointer (e.g. int**), it is very specifically a pointer to an array of int[10].
(note the important difference between int *[10] (an array of 10 pointers which on access will become a pointer-to-pointer) and int (*)[10] (a pointer to array of 10 int))
Answer
"So ... the value of a 2D int array's name when used in an expression" -- is the address of the first 1D array of integers that make up the 2D array with formal type int (*)[N] (where N is the number of elements per-row).
Nuance In How The Standard Is Applied
The type is critical for the proper use of the array name. With a 2D array, the resulting address is a pointer to an array. What results if you dereference that pointer? (Answer: an array) What happens when you access that array through the derefernced pointer? (hint: the conversion on access rules apply again). You must know what the pointer type resulting from the conversion will be in order to properly use the array name in an expression.
An Example May Help
Or it may not, but working with the pointer types that result from the array access and pointer conversion may help things sink in. Below, the example declares a simple 4x3 2D array of int. It then declares a pointer (p) of proper type to allow the array name to be used in an expression assigning the array address to the pointer. The pointer initialized with the array name is then used to further initialize an integer pointer (ip) to the first element in the first array.
The example then outputs the address for each element, and then using the pointer p outputs the address of the beginning of each row-array that makes up the 2D array. Finally the code enters a validation loop comparing the addresses of each element by (1) array index, (2) the address held by pointer p using an offset, and (3) address held by ip. The purpose being the use of each of the different pointers resulting from the expression assigning the array name to then reference each element and ensuring the addresses held by each pointer agree.
#include <stdio.h>
int main (void) {
int array[ ][3] = { {1, 2, 3}, /* 2D array values */
{3, 4, 5},
{5, 6, 7},
{7, 8, 9} },
(*p)[3] = array, /* pointer to array */
*ip = *p; /* integer poiner */
size_t size = sizeof array,
nele = size / sizeof **array,
nrow = size / sizeof *array,
ncol = sizeof *array / sizeof **array;
printf ("2D array statistics:\n\n"
" size: %zu (bytes)\n nele: %zu (ints)\n"
" nrow: %zu\n ncol: %zu\n",
size, nele, nrow, ncol);
puts ("\naddress of each array element:\n");
for (size_t i = 0; i < nrow; i++) {
for (size_t j = 0; j < ncol; j++)
printf (" %p", (void*)&array[i][j]);
putchar ('\n');
}
puts ("\naddress of each 1D array:\n");
for (size_t i = 0; i < nrow; i++)
printf (" %p\n", (void*)p[i]);
puts ("\nvalidating each array element address by index & pointer:\n");
for (size_t i = 0; i < nrow; i++) {
for (size_t j = 0; j < ncol; j++) {
if (ip != &array[i][j] || ip != *p + j) {
fprintf (stderr, "address validation failed for "
"array[%zu][%zu]\n(%p != %p || %p != %p)\n",
i, j, (void*)ip, (void*)&array[i][j],
(void*)ip, (void*)(p + j));
return 1;
}
ip++;
}
p++;
}
puts (" done!");
return 0;
}
Example Use/Output
$ ./bin/array_2d_access
2D array statistics:
size: 48 (bytes)
nele: 12 (ints)
nrow: 4
ncol: 3
address of each array element:
0x7ffe7c9a9780 0x7ffe7c9a9784 0x7ffe7c9a9788
0x7ffe7c9a978c 0x7ffe7c9a9790 0x7ffe7c9a9794
0x7ffe7c9a9798 0x7ffe7c9a979c 0x7ffe7c9a97a0
0x7ffe7c9a97a4 0x7ffe7c9a97a8 0x7ffe7c9a97ac
address of each 1D array:
0x7ffe7c9a9780
0x7ffe7c9a978c
0x7ffe7c9a9798
0x7ffe7c9a97a4
validating each array element address by index & pointer:
done!
Let me know if that helped and whether you have any further questions.
Related
I'm a Swift programmer using C code in a project and I cannot, for the life of me, figure out how the kRing function (below) works from the Uber H3 library (https://github.com/uber/h3/blob/master/examples/neighbors.c). H3Index is a 64-bit integer, that's all you need to know.
H3Index indexed = 0x8a2a1072b59ffffL;
int k = 2;
int maxNeighboring = maxKringSize(k);
H3Index* neighboring = calloc(maxNeighboring, sizeof(H3Index));
kRing(indexed, k, neighboring);
for (int i = 0; i < maxNeighboring; i++) {
if (neighboring[i] != 0) {
// whoa, neighboring is now magically an array, it was just an integer
}
}
From Uber's documentation:
void kRing(H3Index origin, int k, H3Index* out);
Output is placed in the provided array in no particular order. Elements of the output array may be left zero, as can happen when crossing a pentagon.
But the output is an in-out parameter (that's what we call them in Swift, don't know what they're called in C) that's an integer type, not an array type.
Documentation on the function: https://h3geo.org/#/documentation/api-reference/traversal
In C an int* (int pointer) is just an address that points to an int. It can be used as an array:
int array[10];
int oneInt;
void someFunc(int* ip)
{
...
}
someFunc(array);
someFunc(&oneInt);
/* are both valid calls */
In the above example the person calling someFunc needs to know whether the pointer is being treated as a single int or an array (and if an array: how many elements ?).
This seems to be handled in the API you've given:
H3Index* neighboring = calloc(maxNeighboring, sizeof(H3Index));
/* gives you a pointer to an array of maxNeighboring indexes */
kRing(indexed, k, neighboring);
/* calls kRing and passes your array. kRing can use parameter "k" to
figure out how many elements it can play with
*/
for (int i = 0; i < maxNeighboring; i++) { .. }
/* zeros each element in the array.
Kind of weird. You just called kRing to populate the array and now you're
zeroing it all out ? Seems the call to kRing was redundant in the first
place ?
*/
In the posted code, neighboring is a pointer to H3Index. With the expression neighboring[i], neighboring is not an integer type, but is still a pointer type; yet neighboring[i] does have type H3Index. The confusion seems to be around the use of array subscripting here.
Pointers and arrays are distinct types in C, but array subscripting can be used with pointers. The C Standard offers §6.5.2.1p2:
A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
That is, array subscripting is equivalent to pointer arithmetic. In the posted code, the array subscript expression neighboring[i] is equivalent to the pointer arithmetic expression *(neighboring + i).
Note that "...if E1 is an array object (equivalently, a pointer to the initial element of an array object)..." does not mean that a pointer to the initial element of an array is equivalent to that array. Arrays and pointers are distinct types, which can be seen with, e.g.:
#include <stdio.h>
int main(void) {
printf("Array of 20 ints: %zu bytes\n", sizeof (int [20]));
printf("Pointer to int: %zu bytes\n", sizeof (int *));
return 0;
}
On my machine, this outputs:
Array of 20 ints: 80 bytes
Pointer to int: 8 bytes
Here, with 4 byte ints, an array of 20 ints takes up 80 bytes, but a pointer to an int only takes up 8 bytes. These are two distinct types with two different sizes.
With an actual array (say, defined as int arr[20] = {0};), arr[i] must behave as the expression *(arr + i), where the array identifier arr has decayed to a pointer to the first element of the array arr[]. Array expressions (i.e., expressions with an array type) decay to pointers to the first element of the array in most circumstances, and they do so here as well. arr would decay to a pointer in either expression: arr + 1, or in arr[i] (in this case arr is a postfix expression followed by a postfix operator).
There are a few circumstances under which an array expression will not decay to a pointer: if the array expression is an operand to the sizeof operator, the unary & address operator, or if the array expression is a string literal used to initialize another array §6.3.2.1p3. Postfix array subscripting is not one of these cases.
This all means that array subscripting applied to an array is equivalent to array subscripting applied to a pointer to the first element of that array:
#include <stdio.h>
int main(void) {
int arr[20] = { 1, 2, 3, 4, 5 };
// Note: this will not work for `int *ptr = &arr`;
// that would have type int (*)[20],
// i.e, pointer to array of 20 `ints`.
int *ptr = &arr[0];
printf("arr[2] = %d\n", arr[2]);
printf("ptr[2] = %d\n", ptr[2]);
return 0;
}
Here, the expressions arr[2] and ptr[2] are equivalent (and both expressions have type int in this case). But by the same token, in the OP posted code, neighboring[i], where neighboring is just a pointer to H3Index, behaves as if neighboring were an array of H3Index values, yet neighboring is not such an array.
I'm just started studying C language with a book and is not getting bit confused on the part where they discuss pointers and arrays. If there is a multidimensional array(I'll just discuss this array as two-dimensional to be specific) called a[NUM_ROW][NUM_COLS], what does the a[0] mean?
The part I was studying had a part concerning "processing the rows of a multidimensional array" and it had example where
p = &a[i][0] ;
could be written as
p = a[i];
and the book said a[i] is a pointer to the first element in row i.
Then there was a part about "using the name of a multidimensional array as a pointer" where in the case of int a[NUM_ROWS][NUM_COLS], the array name a is not a pointer to a[0][0] but a pointer to a[0].
Does a[0] have same meaning as the a[i] in the first part? I am a bit confused because in the part about "using the name of a multidimensional array as a pointer" the books says array name a is a pointer to an integer array of length NUM_COLS(and a has type int (*) [NUM_COLS]
I was wondering if a[0] indicate the integer array of length NUM_COLS or a pointer to the first element in row 0. (Or is it the same thing? Maybe since I am a bit new to the concept and confused.)
P.S. the book is chapter 12.4 of C programming(KNK)
In general, the name of an array decays to a pointer to its first element. A multidimensional array is basically just an array of arrays, so when you have int a[NUM_ROW][NUM_COL], a[i] is the "name" of the i'th row.
So by the above rule, a[i] decays to a pointer to the first element of that row, which is a[i][0]. To create a pointer we put & before the expression, so that's &a[i][0].
And a decays to a pointer to the the first element of the 2-dimensional array. Each element of the main array is a row, not an individual integer, so a is equivalent to &a[0], not &a[0][0].
The memory location of a[0] and a[0][0] are the same, the difference is in the type of the expression. The type of a[0][0] is int, but the type of a[0] is int[NUM_COL], which will decay to int * in many contexts. This is easiest to see by using the typeof operator:
printf("size of a = %d, size of a[0] = %d, size of a[0][0] = %d\n", sizeof a, sizeof a[0], sizeof a[0][0]);
If NUM_ROW = 5 and NUM_COL = 10, this will probably print:
size of a = 200, size of a[0] = 40, size of a[0][0] = 4
Let's get this out of the way: Arrays and pointers are not one and the same. Array type is a different type. As an example, if you have a pointer int* ptr, ++ptr is perfectly valid (though it might not point to something valid), but if you have an array like int a[3], you may not increment it. But one constraint arrays have is, you may not pass arrays to functions and functions may not return array type. But what happens when you try? What happens is your array is implicitly converted to a pointer to its first element. That is where the confusion comes from: Arrays are converted to a pointer to their first element when you need a pointer pointing them. Therefore, ptr = a would mean ptr is now pointing to the first element of a.
Now let's assume we have this:
int arr[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
What is this exactly? It is an array of arrays. arr[i] refers to one of the answers though it usually decays to a pointer.
What is the difference between a pointer to an array and a pointer to the first element of an array? In most cases they would be same. Please specify an example when they are not the same. Thank you.
The type is different:
int x[1] = {0};
&x[0] is a pointer to the first element of x array and is of type int *.
&x is a pointer to x array and is of type int (*)[1].
But their value is the same because there is no padding in arrays:
(int *) &x == x /* in a value context the expression evaluates to 1 */
The identity of an object is given by the pair (address, type). Different objects can have the same address as long as their types are different, in which case one is a subobject of the other.
This is the case with arrays: The array is an object, and the array elements are objects, and the array elements are subobjects of the array. The first element happens to have the same address as the array itself. Something similar is true for structs and the first struct member.
So if you have an array T a[N], then the type of a is T[N] and the type of a[0] is T, and so the address of the array is
T (*array_addr)[N] = &a;
and the address of the first element is
T * elem_addr = &a[0];
Since a naked array expression decays to a pointer to the first element under certain conditions, the last line could also be written as T * elem_addr = a;, which has the exact same meaning.
The main difference is that when you obtain the reference to an array, it decays to a pointer and sizeof can't be used anymore on it to obtain the array size, eg:
int array[10];
printf("%d\n", sizeof(array)/sizeof(array[0]));
printf("%d\n", sizeof(&array)/sizeof(array[0]));
This prints on x64:
10
2
Of course you will lose any reference to the size of the array even if you convert to a pointer without any use of the & operator:
printf("%d\n", sizeof((int*)array)/sizeof(array[0])); // prints 2
you can print the a and &a, than print a++ and &a++. Through the result, you will know the answer, just try it. a means a element address, and &a means the array address. int a[] = {1, 2 };
Pointer to an array and pointer to the first element of an array is represented as q=&a and p=a. When you increment the p as p++ it will point to the next element in array but when you increment q++ it will give to the next location to the last element in that array. Thus pointer to an array represents to whole array while pointer to first element in array represents only to the first element in array.
I wrote the following code in C:
#include<stdio.h>
int main()
{
int a[10][10]={1};
//------------------------
printf("%d\n",&a);
printf("%d\n",a);
printf("%d\n",*a);
//-------------------------
printf("%d",**a);
return 0;
}
With the above 3 printf statements I got the same value. On my machine it's 2686384. But with the last statement I got 1.
Isn't it something going wrong? These statements mean:
The address of a is 2686384
The value stored in a is 2686384
the value that is stored at address of variable pointed by a (i.e. at 2686384) is 2686384.
This means a must be something like a variable pointing towards itself...
Then why is the output of *(*a) 1? Why isn't it evaluated as *(*a)=*(2686384)=2686384?
#include<stdio.h>
int main()
{
// a[row][col]
int a[2][2]={ {9, 2}, {3, 4} };
// in C, multidimensional arrays are really one dimensional, but
// syntax alows us to access it as a two dimensional (like here).
//------------------------
printf("&a = %d\n",&a);
printf("a = %d\n",a);
printf("*a = %d\n",*a);
//-------------------------
// Thing to have in mind here, that may be confusing is:
// since we can access array values through 2 dimensions,
// we need 2 stars(asterisk), right? Right.
// So as a consistency in this aproach,
// even if we are asking for first value,
// we have to use 2 dimensional (we have a 2D array)
// access syntax - 2 stars.
printf("**a = %d\n", **a ); // this says a[0][0] or *(*(a+0)+0)
printf("**(a+1) = %d\n", **(a+1) ); // a[1][0] or *(*(a+1)+0)
printf("*(*(a+1)+1) = %d\n", *(*(a+1)+1) ); // a[1][1] or *(*(a+1)+1)
// a[1] gives us the value on that position,
// since that value is pointer, &a[i] returns a pointer value
printf("&a[1] = %d\n", &a[1]);
// When we add int to a pointer (eg. a+1),
// really we are adding the lenth of a type
// to which pointer is directing - here we go to the next element in an array.
// In C, you can manipulate array variables practically like pointers.
// Example: littleFunction(int [] arr) accepts pointers to int, and it works vice versa,
// littleFunction(int* arr) accepts array of int.
int b = 8;
printf("b = %d\n", *&b);
return 0;
}
An expression consisting the the name of an array can decay to a pointer to the first element of the array. So even though a has type int[10][10], it can decay to int(*)[10].
Now, this decay happens in the expression *a. Consequently the expression has type int[10]. Repeating the same logic, this again decays to int*, and so **a is an int, which is moreover the first element of the first element of the array a, i.e. 1.
The other three print statements print out the address of, respectively, the array, the first element of the array, and the first element of the first element of the array (which are of course all the same address, just different types).
First, a word on arrays...
Except when it is the operand0 of the sizeof, _Alignof, 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 in the array.
The expression &a has type "pointer to 10-element array of 10-element array of int", or int (*)[10][10]. The expression a has type "10-element array of 10-element array of int", which by the rule above decays to "pointer to 10-element array of int", or int (*)[10]. And finally, the expression *a (which is equivalent to a[0]) has type "10-element array of int", which again by the rule above decays to "pointer to int".
All three expressions have the same value because the address of an array and the address of its first element are the same: &a[0][0] == a[0] == *a == a == &a. However, the types of the expressions are different, which matters when doing pointer arithmetic. For example, if I have the following declarations:
int (*ap0)[10][10] = &a;
int (*ap1)[10] = a;
int *ip = *a;
then ap0++ would advance ap0 to point to the next 10x10 array of int, ap1++ would advance ap1 to pointer to the next 10-element array of int (or a[1]), and ip++ would advance ip to point to the next int (&a[0][1]).
**a is equivalent to *a[0] which is equivalent to a[0][0]. which is the value of the first element of a and has type int and the value 1 (note that only a[0][0] is initialized to 1; all remaining elements are initialized to 0).
Note that you should use %p to print out pointer values:
printf("&a = %p\n", &a);
printf(" a = %p\n", a);
printf("*a = %p\n", *a);
First of all, if you want to print out pointer values, use %p - if you're on a 64 bit machine int almost certainly is smaller than a pointer.
**a is double dereferencing what's effectively a int**, so you end up with what the first element of the first sub-array is: 1.
If you define a as T a[10] (where T is some typedef), then a simple unadorned a means the address of the start of the array, the same as &a[0]. They both have type T*.
&a is also the address of the start of the array, but it has type T**.
Things become trickier in the presence of multi-dimensional arrays. To see what is happening, it is easier to break things down into smaller chunks using typedefs. So, you effectively wrote
typedef int array10[10];
array10 a[10];
[Exercise to reader: What is the type of a? (it is not int**)]
**a correctly evaluates to the first int in the array a.
From C99 Std
Consider the array object defined by the declaration
int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j] yields an int.
so,
Initial array will be x[0][0] only.
all x, &x and *x will be pointing to x[0][0].
No, there's nothing wrong with your code. Just they way you are thinking about it... The more I think about it the harder I realize this is to explain, so before I go in to this, keep these points in mind:
arrays are not pointers, don't think of them that way, they are different types.
the [] is an operator. It's a shift and deference operator, so when I write printf("%d",array[3]); I am shifting and deferencing
So an array (lets think about 1 dimension to start) is somewhere in memory:
int arr[10] = {1};
//Some where in memory---> 0x80001f23
[1][1][1][1][1][1][1][1][1][1]
So if I say:
*arr; //this gives the value 1
Why? because it's the same as arr[0] it gives us the value at the address which is the start of the array. This implies that:
arr; // this is the address of the start of the array
So what does this give us?
&arr; //this will give us the address of the array.
//which IS the address of the start of the array
//this is where arrays and pointers really show some difference
So arr == &arr;. The "job" of an array is to hold data, the array will not "point" to anything else, because it's holding its own data. Period. A pointer on the other hand has the job to point to something else:
int *z; //the pointer holds the address of someone else's values
z = arr; //the pointer holds the address of the array
z != &z; //the pointer's address is a unique value telling us where the pointer resides
//the pointer's value is the address of the array
EDIT:
One more way to think about this:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? if I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array, thus:
c == &c;
I'm messing around with multidimensional arrays and pointers. I've been looking at a program that prints out the contents of, and addresses of, a simple array. Here's my array declaration:
int zippo[4][2] = { {2,4},
{6,8},
{1,3},
{5,7} };
My current understanding is that zippo is a pointer, and it can hold the address of a couple of other pointers. By default, zippo holds the address of pointer zippo[0], and it can also hold the addresses of pointers zippo[1], zippo[2], and zippo[3].
Now, take the following statement:
printf("zippo[0] = %p\n", zippo[0]);
printf(" *zippo = %p\n", *zippo);
printf(" zippo = %p\n", zippo);
On my machine, that gives the following output:
zippo[0] = 0x7fff170e2230
*zippo = 0x7fff170e2230
zippo = 0x7fff170e2230
I perfectly understand why zippo[0] and *zippo have the same value. They're both pointers, and they both store the address (by default) of the integer 2, or zippo[0][0]. But what is up with zippo also sharing the same memory address? Shouldn't zippo be storing the address of the pointer zippo[0]? Whaaaat?
When an array expression appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the array is a string literal being used as an initializer in a declaration.
Thus, the expression zippo "decays" from type int [4][2] (4-element array of 2-element arrays of int) to int (*)[2] (pointer to 2-element array of int). Similarly, the type of zippo[0] is int [2], which is implicitly converted to int *.
Given the declaration int zippo[4][2], the following table shows the types of various array expressions involving zippo and any implicit conversions:
Expression Type Implicitly converted to Equivalent expression
---------- ---- ----------------------- ---------------------
zippo int [4][2] int (*)[2]
&zippo int (*)[4][2]
*zippo int [2] int * zippo[0]
zippo[i] int [2] int *
&zippo[i] int (*)[2]
*zippo[i] int zippo[i][0]
zippo[i][j] int
&zippo[i][j] int *
*zippo[i][j] invalid
Note that zippo, &zippo, *zippo, zippo[0], &zippo[0], and &zippo[0][0] all have the same value; they all point to the base of the array (the address of the array is the same as the address of the first element of the array). The types of the various expressions all differ, though.
When you declare a multidimensional array, the compiler treats it as a single dimensional array. Multidimensional arrays are just an abstraction to make our life easier. You have a misunderstanding: This isn't one array pointing to 4 arrays, its always just a single contigous block of memory.
In your case, doing:
int zippo[4][2]
Is really the same as doing
int zippo[8]
With the math required for the 2D addressing handled for you by the compiler.
For details, see this tutorial on Arrays in C++.
This is very different than doing:
int** zippo
or
int* zippo[4]
In this case, you're making an array of four pointers, which could be allocated to other arrays.
zippo is not a pointer. It's an array of array values. zippo, and zippo[i] for i in 0..4 can "decay" to a pointer in certain cases (particularly, in value contexts). Try printing sizeof zippo for an example of the use of zippo in a non-value context. In this case, sizeof will report the size of the array, not the size of a pointer.
The name of an array, in value contexts, decays to a pointer to its first element. So, in value context, zippo is the same as &zippo[0], and thus has the type "pointer to an array [2] of int"; *zippo, in value context is the same as &zippo[0][0], i.e., "pointer to int". They have the same value, but different types.
I recommend reading Arrays and Pointers for answering your second question. The pointers have the same "value", but point to different amounts of space. Try printing zippo+1 and *zippo+1 to see that more clearly:
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
printf("%lu\n", (unsigned long) (sizeof zippo));
printf("%p\n", (void *)(zippo+1));
printf("%p\n", (void *)(*zippo+1));
return 0;
}
For my run, it prints:
32
0xbffede7c
0xbffede78
Telling me that sizeof(int) on my machine is 4, and that the second and the third pointers are not equal in value (as expected).
Also, "%p" format specifier needs void * in *printf() functions, so you should cast your pointers to void * in your printf() calls (printf() is a variadic function, so the compiler can't do the automatic conversion for you here).
Edit: When I say an array "decays" to a pointer, I mean that the name of an array in value context is equivalent to a pointer. Thus, if I have T pt[100]; for some type T, then the name pt is of type T * in value contexts. For sizeof and unary & operators, the name pt doesn't reduce to a pointer. But you can do T *p = pt;—this is perfectly valid because in this context, pt is of type T *.
Note that this "decaying" happens only once. So, let's say we have:
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
Then, zippo in value context decays to a pointer of type: pointer to array[2] of int. In code:
int (*p1)[2] = zippo;
is valid, whereas
int **p2 = zippo;
will trigger an "incompatible pointer assignment" warning.
With zippo defined as above,
int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];
are all valid. They should print the same value when printed using printf("%p\n", (void *)name);, but the pointers are different in that they point to the whole matrix, a row, and a single integer respectively.
The important thing here is that int zippy[4][2] is not the same type of object as int **zippo.
Just like int zippi[5], zippy is the address of a block of memory. But the compiler knows that you want to address the eight memory location starting at zippy with a two dimensional syntax, but want to address the five memory location starting at zippi with a one dimensional syntax.
zippo is a different thing entirely. It holds the address of a a block of memory big enough to contain two pointer, and if you make them point at some arrays of integers, you can dereference them with the two dimensional array access syntax.
Very well explained by Reed, I shall add few more points to make it simpler, when we refer to zippo or zippo[0] or zippo[0][0], we are still referring to the same base address of the array zippo. The reason being arrays are always contiguous block of memory and multidimensional arrays are multiple single dimension arrays continuously placed.
When you have to increment by each row, you need a pointer int *p = &zippo[0][0], and doing p++ increments the pointer by every row.
In your example id its a 4 X 2 array, on doing p++ its, pointer currently points to second set of 4 elements.