int arr[10]={1,2,3,4,5,6,7,8,9,10};
printf("%p,%p\n", arr, &arr);
printf("%p,%p\n", arr+1, &arr+1);
return 0;
For this code, GCC compiler return
0xbfe41348,0xbfe41348
0xbfe4134c,0xbfe41370
The first line is clear, no problem. But the second line makes me confused. The first address moves to the next int, so it is 4 bytes after arr, clear. However, for &arr+1 I thought it will point to the end of the whole array arr[10], so it should add 4*10 to the address. Do I misunderstand something?
What you think is right and it is done that way only.
Since &arr => 0xbfe41348 and
0xbfe41348 + 0x28(4*10 in decimal) = 0xbfe41370
I think you got confused due to addition of decimal to a hexadecimal number.
The type of &arr is 'pointer to array of 10 int'. Therefore, when you add one to it (&arr+1), it moves to the start of the next array of 10 int, which is 40 bytes beyond the start of &arr.
&arr+1 does, in fact, add 40 to the base address of the array arr but it's not obvious since the addresses are in hexadecimal or base 16, not decimal.
Now, for what it's worth, I'll add some explanation of each statement to make things clear.
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
The above statement defines arr to be of type int[10], i.e., an array of 10 integers. It then initializes arr with an array initializer list.
printf("%p,%p\n", arr, &arr);
In the above statement arr decays (evaluates or implicitly converted) to a pointer to its first element. Therefore its type is int *. &arr evaluates to a pointer to arr. Type of arr is int[10]. Therefore, type of &arr is int (*)[10], i.e., a pointer to an array of 10 integers. Parentheses are used because array subscript operator [] has higher precedence than * operator. So without parentheses int *[10] means an array of 10 pointers to integers. This is one of the cases where an array does not decay into a pointer to its first element.
Please note that both arr and &arr evaluate to the same value, i.e., the base address of the array in the above printf statement but their types are different and they have different pointer arithmetic. This shows up in the following statement -
printf("%p,%p\n", arr+1, &arr+1);
arr+1 points to the next element. Here element type is int. Therefore arr+1 evaluates to
arr + (1 * sizeof(int))
&arr + 1 also points to the next element but here the element type is int[10] - an array of 10 integers. Therefore &arr + 1 evaluates to
arr + (1 * sizeof(int[10]))
arr+1
Here arr is base pointer to integer array so results in incremented by sizeof(int)
&arr+1
Here &arr results in address of array so result is incremented by array size.
Related
I was asked what the output of the following code is:
int a[5] = { 1, 3, 5, 7, 9 };
int *p = (int *)(&a + 1);
printf("%d, %d", *(a + 1), *(p - 1));
3, 9
Error
3, 1
2, 1
The answer is NO.1
It is easy to get *(a+1) is 3.
But how about int *p = (int *)(&a + 1); and *(p - 1) ?
The answer to this could be either "1) 3,9" or "2) Error" (or more specifically undefined behavior) depending on how you read the C standard.
First, let's take this:
&a + 1
The & operator takes the address of the array a giving us an expression of type int(*)[5] i.e. a pointer to an array of int of size 5. Adding 1 to this treats the pointer as pointing to the first element of an array of int [5], with the resulting pointer pointing to just after a.
Also, even though &a points to a singular object (in this case an array of type int [5]) we can still add 1 to this address. This is valid because 1) a pointer to a singular object can be treated as a pointer to the first element of an array of size 1, and 2) a pointer may point to one element past the end of an array.
Section 6.5.6p7 of the C standard states the following regarding treating a pointer to an object as a pointer to the first element of an array of size 1:
For the purposes of these operators, a pointer to an object
that is not an element of an array behaves the same as a pointer
to the first element of an array of length one with the type of the
object as its element type.
And section 6.5.6p8 says the following regarding allowing a pointer to point to just past the end of an array:
When an expression that has integer type is added to or
subtracted from a pointer, the result has the type of the pointer
operand. If the pointer operand points to an element of an array
object, and the array is large enough, the result points to an element
offset from the original element such that the difference of the
subscripts of the resulting and original array elements equals the
integer expression. In other words, if the expression P points to the
i-th element of an array object, the expressions (P)+N
(equivalently, N+(P)) and (P)-N (where N has the value n) point to,
respectively, the i+n-th and i−n-th elements of the array object,
provided they exist. Moreover, if the expression P points to the
last element of an array object, the expression (P)+1 points one past
the last element of the array object, and if the expression Q
points one past the last element of an array object, the
expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to
elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an
overflow; otherwise, the behavior is undefined. If the result points
one past the last element of the array object, it shall not be used as
the operand of a unary * operator that is evaluated.
Now comes the questionable part, which is the cast:
(int *)(&a + 1)
This converts the pointer of type int(*)[5] to type int *. The intent here is to change the pointer which points to the end of the 1-element array of int [5] to the end of the 5-element array of int.
However the C standard isn't clear on whether this conversion and the subsequent operation on the result is allowed. It does allow conversion from one object type to another and back, assuming the pointer is properly aligned. While the alignment shouldn't be an issue, using this pointer is iffy.
So this pointer is assigned to p:
int *p = (int *)(&a + 1)
Which is then used as follows:
*(p - 1)
If we assume that p validly points to one element past the end of the array a, subtracting 1 from it results in a pointer to the last element of the array. The * operator then dereferences this pointer to the last element, yielding the value 9.
So if we assume that (int *)(&a + 1) results in a valid pointer, then the answer is 1) 3,9 otherwise the answer is 2) Error.
In the line
int *p = (int *)(&a + 1);
note that &a is being written, not a. This is important.
If simply a had been written, then the array would have decayed to a pointer to the first element, i.e. to &a[0]. However, since the expression &a was used instead, the result of this expression has the same value as if a or &a[0] had been used, but the type is different: The type is a pointer to an array of 5 int elements, instead of a pointer to a single int element.
According to the rules on pointer arithmetic, incrementing a pointer by 1 will increase the memory address by the size of the object that it is pointing to. Since the pointer is not pointing to a single element, but to an array of 5 elements, the memory address will be incremented by 5 * sizeof(int). Therefore, after incrementing the pointer, the value of (but not type of) the pointer will be equivalent to &a[5], i.e. one past the end of the array.
After casting this pointer to int * and assigning the result to p, the expression p is fully equivalent to &a[5] (both in value and in type).
Therefore, the expression *(p - 1) is equivalent to *(&a[5] - 1), which is equivalent to *(&a[4]), or simply a[4].
This:
&a + 1;
is taking the address of a, an array, and adding 1, which adds the size of one a, i.e. 5 integers. Then the indexing "backs down", one integer, ending up in the final element of a.
Normally whenever arrays are used in expressions, they "decay" into a pointer to the first element. There are a few exceptions to this rule and one such exception is the & operator.
&a therefore yields a pointer to the array of type int (*)[5]. Then &a + 1 is pointer arithmetic on such a type, meaning the pointer address is increased by the size of one int [5]. We end up pointing just beyond the array, but C actually allows us to do that as long as we don't de-reference that location.
Then the pointer is forced a type conversion to (int *) which we can do too - C allows pretty much any manner of wild pointer conversions as long as we don't de-reference or cause misalignment etc.
p - 1 does pointer arithmetic on type int and the actual type of data in the array is also int, so we are allowed to de-reference that location. We end up at the last item of the 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.
I am studying how to display elements of 2D array with the help of pointers. Here is the code I tried:
#include<stdio.h>
int main(){
int arr[3][2] = {
{7, 8},
{6,3},
{3,4}
};
printf("%u\n", (arr + 2));
printf("%u\n", *(arr + 2));
}
Output:
6487616
6487616
I am expecting output of *(arr + 2) to be 3. How is it the same as (arr + 2)?
A 2D array is really an array of arrays.
The expression arr + 2 has type int (*)[2], while *(arr + 2) has type int [2]. When printing the former, you have a pointer so that value of the pointer is printed. In the latter case, you have an array which decays to a pointer to the first element. So *(arr + 2) decays into arr + 2, which is the same as the first expression.
Going into more detail on arr + 2, arr has type int [3][2]. When you add an integer value to it, it decays to a pointer to the first member, so arr decays to type int (*)[2], and arr + 2 also has that type, and points to the subarray containing { 3, 4 }.
Also note that pointers should be printed with the %p format specifier, and that the pointer must be casted to void *, otherwise you invoke undefined behavior. In this case you were "lucky" that they happened to print the same thing.
To get the output of 3 you were expecting, you need to dereference one more time:
*(*(arr + 2))
arr is an array of arrays of int. On almost any use an array is converted to a pointer to its first element. So arr gets converted to a pointer to an array of int.
OK, arr gets converted to a pointer to an array of int, so (arr+2) is of the same type, that is, a pointer to an array of int.
Now *(arr+2) is the thing (arr+2) points to. That is, an array of int.
Now since it's an array of int, it gets converted to a pointer to its first element. So *(arr+2) gets converted to a pointer to int. Note it is not an int and is unlikely to be equal to 3.
Now how come (arr+2) and *(arr+2) dosplay the same? They are a pointer to an array and a pointer to its first element. Although these pointets are of different types, they represent the same address, because the address of any array is the same as the address of its first element.
arr is the pointer to the first array of the type int[2].(arr + 2) is the pointer to the third such array.
Whereas *(arr + 2) is the pointer to the first element of the (arr +2) array.
Both of these will hence have the same address since they are pointing to the same position.The only difference being in their type.(arr+2) is of the type int(*)[2] whereas *(arr + 2) is of the type int *.
I come across a program in C and see the pointer comparison program. What I didn't understand is these two statements.
j=&arr[4];
k=(arr+4);
the first statement is holding the address of the fifth element and the second statement syntax is what I saw first time. Can anybody explain me the second statement. and also
after executing program j and k are equal. so they are pointing to the same location.
k=(arr+4);
means k will point to 4 elements ahead of arr location after it is decayed into a pointer to index 0.
array name decays to a pointer to it's zero index. by adding 4 means it'll point to 5th element.
It's the infamous pointer arithmetic! The statement simply assigns the address of the element at the address pointed to by arr and an offset of 4 elements to the right. arr + 4 is pointing to the address of arr[4].
This is simply pointer arithmetic, mixed with C's indexing<->pointer defererence equivalence.
The former means that the expression arr + 4 causes arr (the name of an array) to decay into simply a pointer to the array's first argument. In other words, arr == &arr[0] is true.
The latter is this equivalency, for any pointer a and integer i:
a[i] === *(a + i)
This means that the first expression, the assignment to j, can be read as j = &(*(a + 4)), which makes it (pretty) clear that it's just taking the address of the element with index 4, just as the k line is doing.
This code uses a simple case of pointer arithmetics. It assigns the adress of the array ( +4 adresses, so it is the 5th element) to the pointer k.
Every arr[4] statement is expending to (arr+4); statement by the compiler itself.
These two are equivalent and can be use interchangeably.
Both are ways of getting a pointer value.
First arr[x] returns (x+1) array contents and you can get its address with & operator.
Second is known as pointer arithmetic and returns the address of the arr pointer plus x positions, so the x+1 address.
It's basic pointer arithmetic. k is a pointer, arr is a pointer to the first element of the array (a pointer to arr[0]). So by adding 4 to k, you move the pointer on 4 elements. Therefore k=(arr+4) means k points to arr[4], which would be the fifth element, and the same as j.
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;