So, if I have this in C,
int a[50];
and I use a, it actually points to the address of the first element of the array.
But, if I have int b[10][10] , and I use b or b[0] , to what it will point to?
Secondly, if I do,
`&a[0]`
this basically gives me the address of the first element, but if I do, &a , what does this mean actually? And also operations like, &a + 1 . Basically, are we calculating the address of the address of the first element of the array?
Or for that matter if I have a 3d array, int c[10][10][10], then what does, c means? To which element will it point to? Or, if I do, c[0]+1 , to what part of the array will this point to?
Thanks!
If you have an array such as
int a[X][Y];
Then using just a will have it decay to a pointer to the first element in the first array.
The expression &a[0] will return a pointer to the first array, hich then decays to a pointer to the first element. So both a and &a[0] (as well as plain a[0] and of course &a[0][0]) will all point to the same thing. The difference is in the types:
a is an array of arrays of integers, which decays to a pointer to an array of integers
a[0] is an array of integers, which decays to a pointer to an integer
&a[0] is a pointer to an array of integers
&a is a pointer to an array of arrays of integers
&a[0][0] is a pointer to an integer
All the expressions above, will either point to, or decay to a pointer to, the very same element: The first integer in the first array (i.e a[0][0]).
For completeness sake:
a[0][0] is an integer, the very first in the very first array.
Since &a is a pointer to an array of array of integers, adding one (i.e &a + 1) will add the size of the array of array integers, in other words the expression returns a pointer to a + sizeof(a), which is a pointer to one beyond the end of a. In more other words, it's the same as (&a)[1].
More curiosity: For a generic pointer or array p, doing p[x] is the same as doing p + x. And now for the weird part: Due to the communicative nature of addition, the expression p + x is equal to x + p, which in turn leads to p[x] is equal to x[p].
For the dereferencing:
*a decays a to a pointer to an array of arrays of integers, so *a is an array of integers (i.e. a[0])
*a[0] since the indexing operator has higher precedence than the dereference operator, you first have a[0] which is an array of integers, the dereference then decays it to a pointer to the first element of that array which it the dereferences (i.e. it's the same as a[0][0])
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize an 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 M-element array.
Given the following declaration:
T a[N][M];
the expression a has type "N-element array of M-element arrays of T"; by the rule above, it will decay to an expression of type "pointer to M-element array of T", or T (*)[M], and the value will be the address of the first element of that array.
The following table shows the types and meanings of various expressions involving a:
Expression Type Decays to Meaning
---------- ---- --------- -------
a T [N][M] T (*)[M] Points to first M-element array
&a T (*)[N][M] Points to entire NxM array
*a T [M] T * Points to first element of first array
a[i] T [M] T * Points to first element of i'th array
&a[i] T (*)[M] Points to i'th M-element array
*a[i] T Value of first element of i'th array
a[i][j] T Value of j'th element of i'th array
&a[i][j] T * Points to j'th element of i'th array
Since the address of the first element is the same as the address of the array itself, all of the expressions a, *a, &a, a[0], &a[0], and &a[0][0] yield the same value, but the types of the expressions are different.
This pattern extends to higher-dimensioned arrays. I'd draw out an example for a 3-d array, but I'm typing this on an iPad, which has already slowed me down considerably.
Related
This question already has answers here:
How come an array's address is equal to its value in C?
(6 answers)
Closed 4 years ago.
Why is these two are same things I saw one answer to this similar question but couldn't really understand.
Why *(a+i) and a+i doing the same work.
int a[1][2] = {1,2};
printf("%p or %p\n",*(a+0),a+0);
Array subscript brackets "[]" are defined in terms of pointer operations. a[i] is defined as *(a+i), assuming that a is of type array and i is an integer type. The name of an array by itself is evaluated as a pointer to its first element; integer addition to a pointer adds the integer times the sizeof the element to the pointer. (a+i) and *(a+1) are not the same - (a+i) is the address of an element in an array and *(a+i) is that element.
Thus a[0] becomes *(a+0), or *a, the first element of the array. A[1] becomes *(a+1), or *(a + (sizeof (*a) * 1), or *(address of the second element of the array), or just the second element of the array, as one would expect.
Except when it is the operand of the sizeof or 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" 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.
So given a declaration like
int a[100];
any time a appears in an expression where it isn't the operand of the sizeof or unary & operators, the compiler will treat it as a pointer expression equivalent to &a[0] (type int *).
Now, what happens if a is the operand of unary &?
The address of an array is the same as the address of the first element of the array, which should be clear from the diagram below:
+------+
a: | a[0] |
+------+
| a[1] |
+------+
...
+------+
| a[99]|
+------+
The type of the expression &a is int (*)[100] (pointer to 100-element array of int), but the value of the expression is the same as a and &a[0] (address of the first element).
Summarizing that in a table:
int a[100];
Expression Type "Decays" to
---------- ---- -----------
a int [100] int *
*a int n/a
&a int (*)[100] n/a
a[i] int n/a
&a[i] int * n/a
Again, the address of the array is the same as the address of the first element of the array, so &a, a, and &a[0] will all yield the same address value (modulo any type conversions).
Adding 1 to a pointer yields the address of the next object of the pointed to type. IOW, if p points to a 4-byte int object, the result of p + 1 will be the address of the next 4-byte int. If p points to a 100-element array of 4-byte ints, then p + 1 yields the address of the next 100-element array of int.
The subscript operation a[i] is defined as *(a + i) - given the address a, find the address of the i'th object following a and dereference the result.
This means that the value of *a is the same as a[0] - *a == *(a + 0) == a[0].
How does this apply to a 2D array, as in your example?
Given the declaration
int a[1][2];
the expression a "decays" from type "1-element array of 2-element array of int" (int [1][2]) to "pointer to 2-element array of int" (int (*)[2]). The value of the expression a is the address of the first element, but the first element has an array type itself. Thus, that value "decays" to a pointer to the first element of the subarray.
Here's a handy table to summarize:
int a[1][2];
Expression Type "Decays" to
---------- ---- -----------
a int [1][2] int (*)[2]
*a int [2] int *
&a int (*)[1][2] n/a
a[0] int [2] int *
*a[0] int n/a
&a[0] int (*)[2] n/a
a[0][0] int n/a
Again, &a, a, a[0], &a[0], and &a[0][0] will all yield the same value, since the address of a[0][0] is the same as the address of a[0] which is the same as the address of a.
C's doesn't really treat multidimensional arrays differently from single-dimensional ones.
Arrays in C are just array of arrays
char a[2][3][4][5];
is an array 2 of array 3 of array 4 of array 5 of char.
Dereferencing/subscripting works the same for any "Array A of T":
decay A to the address of the first element (or do nothing if you're defering/subscripting a pointer)
add to that the index scaled by sizeof(T)
With dereferencing/subscripting in C, when you speak of one, you speak of the other, because A[Index] or Index[A] is defined to be the same as *(A+Index) or *(Index+A).
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).
Since in char a[2][3][4][5]; a is an array 2 of ( array 3 of array 4 of array 5 of char), a[1] would give you ((char*)&a) + 1 * sizeof(char[3][4][5]) and the result would have type char[3][4][5].
Now here's where arrays are special — arrays aren't first-class objects in C. You can't have an r-value of an array type. When you attempt to obtain one, e.g., by passing the array to a function or an operator, the array immediately decays to a pointer to its first element so the char[3][4][5] type of a[1] immediately changes to char(*)[4][5].
6.5.2.1p3
Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n >= 2) with dimensions i x j x . . . x k, then E (used as other than an lvalue) is converted to a pointer to an (n - 1)-dimensional array with dimensions j x . . . x k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n - 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
This continues recursively until you've chomped off all of the dimensions (from right to left) and are left with a real type that doesn't decay. Effectively the decay of the intermediary arrays means that intermediary derefs/subscripts don't really fetch anything — they're simply additions to a base address.
Some examples with char a[2][3][4][5];:
#include <stdio.h>
char a[2][3][4][5];
#define ASSERT_TP(Expr,Tp) _Generic(Expr,Tp: (char*)(Expr))
int main()
{
printf("%zd\n", ASSERT_TP(a,char(*)[3][4][5])
- (char*)a); //0
printf("%zd\n", ASSERT_TP(a[1],char(*)[4][5])
- (char*)a); //60 == 1 * (3*4*5)
printf("%zd\n", ASSERT_TP(a[1][1],char(*)[5])
- (char*)a); //80 == 1 * (3*4*5) + 1 * (4*5)
}
Applied to your example:
int a[1][2] = {1,2}; // a decays to ptr to 1st element,
//i.e. to `int (*a)[2]`
printf("%p or %p\n",
*(a+0), // == a[0]; ((char*)&a) + 0*sizeof(int[2]);
// type is int[2], which decays to int*
a+0); // == a (after decay); (char*)&a + 0*sizeof(int[2]);
//type is still `int(*)[2]` (because no derefing)
Because the deref in *(a+0) didn't hit the real type yet, there was no fetch, just an addition to a base pointer
with type adjustement. Since the addition added 0, the value didn't change it remained the same as that of a decayed to a pointer to its first element (== a+0) or even &a (which would have the same numerical address but its type would be int (*)[1][2]).
An array can decay to pointer to its first element. In your example plain a will decay to &a[0]. And for any array or pointer a and index i, the expression a[i] is exactly equal to *(a + i).
Also, if you lay out your array how it would look like in memory, it would be
+---------+---------+
| a[0][0] | a[0][1] |
+---------+---------+
Now armed with this information, we can start transforming the expressions in your printf call.
Lets start with *(a + 0):
Because the equivalence, *(a + 0) becomes a[0].
Because a[0] is an array, it will decay to a pointer to its first element, i.e. &a[0][0].
So the first argument is equal to &a[0][0], i.e. a pointer to a[0][0].
Then lets take a + 0.
The expression a + 0 is equal to &*(a + 0).
Because the array/pointer equivalence &*(a + 0) becomes &a[0].
&a[0] is a pointer to the first element of a, which happens to begin at the same position in memory as a[0][0].
This of course means that the pointer &a[0] and &a[0][0] both are pointing to the same locations, and the output would be equal. However the types of those two pointers are very different:
The type of &a[0][0] is a pointer to an int, i.e. int *
The type of &a[0] is a pointer to an array of two int elements, i.e. int (*)[2]
For the below code snippet , what type of rvalue is returned by expression array+1 and &array+1 ?
int main()
{
int array[2][3];
printf("%p %p ", array+1, &array+1);
return 0;
}
I have already gone through below link but still my doubt is not cleared .
2D array variable pointer confusion
When array is used in an expression, it "decays" to a pointer of the first element.
The first element of a 2D array int[2][3] is a 1D array int[3].
Therefore the expression array+1 gives a pointer to such a 1D array.
The expression array+1 has type int(*)[3], an array pointer to an array of 3 integers.
When you do + 1 on any pointer, pointer arithmetic is invoked and you get "plus one pointed-at object", rather than "plus one byte/address".
Thus array+1 gives the second array of type int[3] in your 2D array.
&array is different, it gives a pointer to the address of the array itself. A pointer to a 2D array, type int(*)[2][3].
If you do &array + 1 you therefore do pointer arithmetic on objects that are 2D arrays and end up pointing "one 2D array outside the allocated array", which probably isn't meaningful.
Pointers and arrays are closely associated with each other, so, if we have a 2-D array
int a[3][4]={
1,2,3,4,
5,6,7,8,
9,10,11,12};
Both
printf("%p\n", a);
and
printf("%p\n", *a);
print the same address. What I understand is maybe a is pointing to the base address of a while *a is pointing to the first sub-array of the two-dimensional array a.
So, what is the difference between the two?
What i get is may be a is pointing to the base address of a while *a
is pointing to the first sub-array of two-dimensional array a.
That's almost it.
a on its own decays to a pointer (of type int(*)[3]) to its first subarray when you pass it to printf.
*a designates a's first subarray (of type int[3]), and decays to a pointer (of type int*) to the first element of that subarray.
In the end, they share the same value because an array has the same address as its first element, recursively.
Given the declaration
int a[3][4];
the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
a int [3][4] int (*)[4] Base address of array
&a int (*)[3][4] n/a Base address of array
*a int [4] int * Base address of first subarray
(equivalent to a[0])
a[i] int [4] int * Base address of i'th subarray
&a[i] int (*)[4] n/a Base address of i'th subarray
*a[i] int n/a Value of a[i][0]
a[i][j] int n/a Value of a[i][j]
&a[i][j] int * n/a Address of a[i][j]
The address of the first element of the array is the same as the address of the array itself, so the expressions a, &a, *a, a[0], &a[0], and &a[0][0] all yield the same value (the address of the first element of the array), but they will have different types (int (*)[3][4] vs. int (*)[4] vs. int *).
Edit
Except when it is the operand of the sizeof or unary & operators, 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.
So the expression *a is equivalent to a[0]; both expressions have type "4-element array of int". Since they're not operands of the sizeof or unary & operators, those expressions "decay" to type "pointer to int".
That's what the "Decays to" column shows.
See section 6.3.2.1 of the online C 2011 language standard.
a is a 2D array of size 3x4. That means:
sizeof(a) == 3*4*sizeof(int)
a[i] is a 1D array of size 4 (for 0<=i<3)
a[i][j] is an int ( 0<=i<3 and 0<=j<4)
when used as a pointer a decays to &a[0]
*a is a[0]: it is a 1D array of size 4. That means :
sizeof(*a) == 4*sizeof(int)
(*a)[i] is an int (0<=i<4)
when used as a pointer *a decays to &a[0][0]
So a and *a are different objects that decay to pointers to the same address which is also &a. But a decays to a pointer to int[4], whereas *a decays to a pointer to int (thanks to undur_gongor for noticing).
The difference between the pointers (that the arrays decay to) is not the address but the type.
As you have seen, both pointers point to the same address. But a points to sub-arrays whereas *a points to ints.
This makes a difference, e.g. when doing address arithmetic. a + 1 is something different than *a + 1.
It is very simple. *a is an array of integers. In your case *a in nothing but the array [1,2,3,4]. Individual elements of this array can be accessed by (*a)[i], where i is the index of the required element.
And a is pointer to this array of integers. a[0] will give you the first array (it is same as *a), a[1] will give you the second array(which is [5,6,7,8]).
For example if you want to access 5th element(which is 5), it will a[1][0].
The book that I have says that An array name is a pointer constant.
So, I tried this :
int A[3][4] = {0};
A[0][0] = 1;
A[1][0] = 2;
A[2][0] = 3;
printf("A : %x\n", A);
printf("*A : %x\n", *A);
I expected the result of first printf is the address of A and the other is 1.
because, I thought array name is a pointer constant and the result would be *(address of A).
but, the results have same value; address of A.
do you know why? please give me some advice.
First, arrays are not pointers! Your book is wrong. Arrays and pointers share some operations, and array name can be automatically converted to a pointer to its first element in some cases, but remember they are different.
Second, in your code, A is a 2-dimensional array, i.e, an array of arrays. so *A, which is the same as A[0], is its first subarray. To access A[0][0], you need **A.
Arrays are not pointers. Except when it is the operand of the sizeof or unary & operators, or is a string literal 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 of A, all of the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
A int [3][4] int (*)[4] &A[0][0]
*A int [4] int * &A[0][0]
&A int (*)[3][4] n/a &A[0][0]
A[i] int [4] int * &A[i][0]
*A[i] int n/a A[i][0]
&A[i] int (*)[4] n/a &A[i][0]
A decays to an expression of type "pointer to 4-element array of int". A[i] decays to an expression of type "pointer to int. The address of the first element of the array is the same as the address of the array itself, so the expressions
A
*A
&A
A[0]
&A[0]
&A[0][0]
all evaluate to the same value, but the types of the expressions will be different.
Array and pointers are not same.
The main difference is you cannot perform the pointer increment or decrement on the array name. You can think of array as constant pointer.
If you want to print the element of an array then try **A or *(A + i) in loop where i is the loop index
Don't confuse with array's and pointers! Both are different things! and also array is not a pointer! But array name represents base address of array!
In your code-
int A[3][4];
It is a 2D array so you need to dererence two times. If you dererence one time it will fetch the address of the array only. A, A[0], *A, &A, &A[0] all will represent the starting address of it.
Try -
printf("%d\n",**A);
or
printf("%d\n",A[0][0]);
or
printf("%d\n",*A[0]);
Can someone explain to me how C retrieves the correct memory address for a row when you only use one subscript to access a 2d array?
Example -
int array2D[2][2] = {1,2,3,4};
printf ( "starting address of row2 = %p" , array2D[1]);
I understand that when subscripting in C that what is actually going on is pointer addition so for a 1d array the array name points to element 0. In this case if I had wanted element 1 the compiler would take the starting address (say 4000) and add 4 to it (assuming a 4 bit int) so that what is returned is the item at memory address 4004.
My understanding is that when you populate a 2d array, as in my example, they are allocated sequentially so I would have
1 2
3 4
at addresses
4000 4004
4008 4012
So how does C work out that in this case array2D[1] should point to 4008 and not 4004? Does it run a sizeof() operator or have I misunderstood a fundamental here?
Thanks in advance
C knows how long each row is, so it does the multiplication to find the row.
int x[][3] = {{1,2,3},{4,5,6}};
then &x[1][0] is &x[0][0] plus 3 * sizeof(int).
That's why in a multidimensional C array declaration, all but the first dimension must be specified.
Pointer arithmetic depends on the type of the element being pointed to. Given a pointer p to type T, p + 1 points to the next element of type T, not necessarily the next byte following p. If T is char, then p + 1 points to the next char object after p, which starts at the byte immediately following p; if T is char [10], then p + 1 points to the next 10-element array of char after p, which starts at the 10th byte following p.
The type of the expression array2d in is "2-element array of 2-element array of int", which "decays" to type "pointer to 2-element array of int", or int (*)[2]1. Thus the expression array2d[1] is interpreted as *(array2d + 1). Since array2d points to an object of type int [2], array2d + 1 points to the next 2-element array of int following array2d, which is 2 * sizeof int bytes away from array2d.
1. 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 to an expression of type "pointer to T" and its value will be the address of the first element in the array.
This is going to be a bit long-winded, but bear with me still.
Array subscription is just a shorthand: (p[N]) equals (*(p + N)) in all contexts for pointer types (both are invalid expressions for void*, though).
Now, if p is an array type, it would decay to a pointer type in an expression like (*(p + N)); an int[2][2] would decay into a pointer of type (*)[2] (i.e. a pointer to an int[2]).
Pointer arithmetic takes types into account; we need to convert things to char* to visualize what the compiler does to us:
T *p;
p[N] equals *(p + N) equals *(T*)((unsigned char*)p + N * sizeof *p)
Now, if T were an int[2] (to equal the situation we described above), then sizeof *p would be sizeof(int[2]), i.e. 2 * sizeof(int).
This is how subscription works in so-called multidimensional arrays.
sizeof(array2D[1]) == 8;
if array2D address is 4000;
so array2D[1] address is 4000+sizeof(array2D[1]) == 4000+8;