I came across a code whoes output I'm not able to understand.The code is-
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
int *ptr = (int*)(&a+1);
printf("%d ", *(ptr-1) );
return 0;
}
The output of above code is coming out 6, but i think that it should be 1. Please explain why it is 6.
In your question "&a" is address of the whole array a[]. If we add 1 to &a, we get “base address of a[] + sizeof(a)”. And this value is typecasted to int *. So ptr points to the memory just after 6 . ptr is typecasted to "int *" and value of *(ptr-1) is printed. Since ptr points memory after 6,so ptr – 1 points to 6.
&a is an address of array a. Adding 1 to it will increment it to one past the array (adding 24-bytes). Cast operator (int*) cast &a+1 to pointer to int type. ptr-1 will decrement ptr by 4 bytes only and therefore it is the address of last element of array a. Dereferencing ptr - 1 will give the last element which is 6.
Yes, because a is an array having a type int[6]. Therefore, &a gives you the type int (*)[6]. It is not same as pointer to int, it is a pointer to int array.
So, &a + 1 increments the pointer by one of the the array size, pointing past the last element of the array.
Then, taking the address in ptr and doing a -1, decreases the address by a sizeof(*ptr) which is sizeof(int), which gives you the address of last element on the array.
Finally, de-referencing that address, you get the value of the last element , 6. Success.
Because (int*)(&a + 1) uses the whole array as the base type and adds 1 whole size of an array to the address , i.e. adding 24 bytes.
And when you do ptr-1 since ptr type is int it will subtract only 4 bytes.
Its very important to remember the type of the pointer while doing pointer arithmetic.
Related
This question already has an answer here:
Are "array" and "&array[0]" completely interchangeable? [duplicate]
(1 answer)
Closed 2 years ago.
#include<stdio.h>
#include<conio.h>
int main()
{
int a[3][4] = {1, 2, 3, 4, 4, 3, 2, 1, 7, 8, 9, 0};
clrscr();
printf("%u \n",a);
printf("%u, %u\n", a+1, &a+1);
getch();
return 0;
}
Output:
65502
65510
65526
How does this program work if sizeof(int)=2 and base address is 65502?
When you use an array like a in an expression, it usually goes through “pointer decay” which means that you get a pointer to the first element of the array.
So, a has type int[3][4], and it decays to int (*)[4]. When you write a+1, you get the address of a[1]… which is sizeof(*a) bytes after a, which is sizeof(int)*4, which is 8 on your system.
When you use &, pointer decay does not happen. &a is not an array (it is already a pointer), so when you write &a+1, you get the address “one past the end” of a… which is sizeof(a) bytes after a, which is sizeof(int)*12, or 24 bytes on your system.
Note that, strictly speaking, the correct way to print pointers is with %p.
printf("%p\n", a);
printf("%p, %p\n", a+1, &a+1);
(Technically, you also have to cast to char * or void * but that’s hardly ever important.)
printf("%u, %u\n", a+1, &a+1);
a+1 - Here a decays into a pointer to its first element. In this case a pointer to an array of 4 int (type int (*)[4]). Have a look at What is array to pointer decay? for more information.
Thereafter you increment this pointer by one. So, now the gained address is the one of one array element of 4 int of the 2D array forward, which matches to your output as sizeof(int) == 2 * 4 = 8. The difference between 65502 and 65510 is 8.
&a+1 - &a is first evaluated. When the & operator is applied, a doesn't decay to a pointer to its first element. Rather &a gains a pointer to the whole 2D array/ a pointer to an array of 3 arrays of 4 int (type int (*)[3][4]).
Incrementing this pointer by one gets you one the size of the whole 2D array forward which also matches to your output because the difference between 65502 65526 is 24 which is correct because sizeof(int) == 2 * (3 * 4) = 24. (3 * 4) is the amount of elements in the 2D array.
Note: Printing a pointer with the %u format specifier invokes strictly seen undefined behavior. You need the %p format specifier for pointers and need to cast the pointer argument to void * to be standard-compliant.
printf("%p\n", (void*) a);
printf("%p, %p\n", (void*) a+1, (void*) &a+1);
Correct format specifier to print pointer or address?
When you increment a pointer, it gets incremented in steps of the object size that the pointer can point to.
Type of a is int (*)[4]1) i.e. pointer to an object which is an array of 4 int type. So, the a + 1 will be a pointer obtained by adding size of array of 4 integers to pointer evaluated from a in the expression.
Type of &a is int (*)[3][4]1) i.e. pointer to an object which is a 2D array of int type with dimension 3x4. So, the &a + 1 will be a pointer obtained by adding size of 2D array of integers with dimension 3x4 to pointer evaluated from &a in the expression.
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).
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.
I just saw this code snippet Q4 here and was wondering if I understood this correctly.
#include <stdio.h>
int main(void)
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int*)(&a + 1);
printf("%d %d\n", *(a + 1), *(ptr - 1));
return 0;
}
Here's my explanation:
int a[5] = { 1, 2, 3, 4, 5 }; => a points to the first element of the array. In other words: a contains the address of the first element of the array.
int *ptr = (int*)(&a + 1); => Here &a will be a double pointer and point to the whole array. I visualize it like this: int b[1][5] = {1, 2, 3, 4, 5};, here b points to a row of a 2D array. &a + 1 should point to the next array of integers in the memory (non-existent) [kind of like, b + 1 points to the second (non-existent) row of a 2D array with 1 row]. We cast it as int *, so this should probably point to the first element of the next array (non-existent) in memory.
*(a + 1) => This one's easy. It just points to the second element of the array.
*(ptr - 1) => This one's tricky, and my explanation is probably flawed for this one. As ptr is an int *, this should point to int previous to that pointed by ptr. ptr points to the non-existent second array in memory. So, ptr - 1 should probably point to the last element of the first array (a[4]).
Here &a will be a double pointer.
No. It is a pointer to an array. In this example, int (*)[5]. Refer C pointer to array/array of pointers disambiguation
so when you increment pointer to an array, it will crosses the array and points to non-existent place.
In this example, It is assigned to integer pointer. so when int pointer is decremented, it will point to previous sizeof(int) bytes. so 5 is printed.
Your statement is essentially correct, and you probably understand it better than most professionals. But since you are seeking a critique, here is the long answer. Arrays and pointers in C are different types, this is one of the most subtle details in C. I remember one of my favorite professors saying once that the people who made the language latter regretted making this so subtle and often confusing.
It is true in many cases an array of a type, and a pointer to a type can be treated the same way. They both have a value equal to their address, but they are truly different types.
When you take the address of an array &a, you have a pointer to an array. When you say (a + 1) you have a pointer to an int, when you just say a you have an array (not a pointer). a[1] is exactly the same as typing *(a + 1), in fact you could type 1[a] and it would be exactly the same as the previous two. When you pass an array to a function, you are not really passing an array, you are passing a pointer void Fn(int b[]) and void Fn(int *b) are both the exact same function signature, if you take sizeof b within the function, in both cases you will get the size of a pointer.
Pointer arithmetic is tricky, it always offsets by the size of the object it's pointing to in bytes. Whenever you use the address of operator you get a pointer to the type you applied it to.
So for what's going on in your example above:
&a is a pointer to an array, and so when you add one to it, it is offset by the sizeof that array (5 * sizeof(int)).
When you cast to int*, the cast retains the value of the pointer, but now its type is pointer to int, you then store it in ptr, a variable of type pointer to int.
a is an array, not a pointer. So when you say a + 1 you apply the addition operator to an array, not a pointer; and this yields a pointer to one-past the first element of the type stored in the array, int. Dereferencing it with * gives you the int pointed to.
ptr is a pointer to int, and it points one past the end of the array. (it is legal by the way to point one past the end of an array, it's just not legal to dereference this pointer) When you subtract 1 from it, you end up with a pointer to an int that is the last in the array, which you can dereference. (Your explain of visualizing int b[1][5] = {1, 2, 3, 4, 5}; is something I've not heard before, and while I can't honestly say if this is technically correct, I will say this is how it works and I think this is a great way to think of it; I will likely do so in the back of my mind from now on.)
Types will get very tricky in C, and also in C++. The best is yet to come.
As per your explanation you understand array pointer correctly.Using statement
int *ptr = (int*)(&a + 1);
you point to the next address of address occupied by whole array a[] so you can access the array element using ptr by decrementing address of ptr.
I am confused in the basics of pointer and array declaration in C. I want to know the difference between following two statements except that base address to array is assigned to ptr in seconed statement.
int a[2][3]= { (1,2,3),(4,5,6)};
int (*ptr)[3] = &a[0];
Please quote examples to clarify.
What effect do [3] on R side of line 2 has?
1. Bidimensional array:
int a[2][3]= { {1,2,3},{4,5,6}};
With this statement in memory you have 2x3 integers, all adjacent in memory.I suppose that you know how to access them, but in the case you don't I'll clarify it:
a[0][0] : 1
a[0][1] : 2
a[0][2] : 3
a[1][0] : 4
a[1][1] : 5
a[1][2] : 6
2. Pointer to array:
int (*ptr)[3] = &a[0];
ptr points to a int[3] block of memory.So you can assign it only to an int[3] type:
ptr= &a[0];
ptr= &a[1];
The difference is that this pointer does not have it's own memory, and you have to assign it to an int[3] variable or allocate it:
ptr= malloc (2*sizeof(int[3]);
This way you can use the memory pointed by ptr, if you initialize ptr this way:
for(int j=0; j<2; j++)
for(int i=0; i<3;i++)
ptr[j][i]=i+j*3+1;
This case you'll have the same memory representation of int a[2][3], except that this memory is in the heap and not in the stack.You can always choose to realloc/free the memory and this memory is not deleted once your function terminates.
You should know operator precedence rules in C: http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedencehttp://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
int (*ptr)[3] as opposed to int * ptr [3]
The first one is a pointer (notice * is closer to the var name) to arrays of int of size 3
The second one is equal to int (*(ptr [3])) which is an array of size 3 on int pointers.
You can also use this site: http://cdecl.org/ if you have doubts on how to interpret an expression.
a is 2-D array of row size 2 and column size 3.
whereas ptr is pointer to an array of int having size 3
But your array ainitialization is not in correct manner
Since you have used () so comma operator will be in effect and will initialize with 3and 6 and other elements of array a will be 0 to do actual initialization use {}
&a[0] is address of first element of array (means it will print same value for a also).
but this &a[0] comes into effect when you perform pointer arithmetic operation on ptr
In case of array there are 3 things to keep in mind :
---> int *ptr=&a[0][0]; Address of first element ptr++ will give you next element a[0][1]
---> &a[0] = address of first element but if you do int (*ptr)[3]=&a[0]
then by doing ptr++ pointer will be increased by the size of whole row and ptr will point to next row directly means now ptr will point to &a[1]
---> &a = address of whole array and if you keep it in int (*ptr)[2][3] =&a and do ptr++ pointer will be increased by the size of whole array.
#include<stdio.h>
int main(){
int a[5] = {0,1,2,3,4};
int * ptr;
ptr =(int *) &a;
printf("\n&a:%u,&a[0]:%u,ptr:%u\n",&a,&a[0],ptr);
ptr = (int*)(&a+1);
printf("\n&a:%u,&a[0]:%u,ptr:%u\n",&a,&a[0],ptr);
ptr = (int*)(&a);
ptr = (int*)(&a[0]+4);
printf("\n&a:%u,&a[0]:%u,ptr:%u,*ptr:%d\n",&a,&a[0],ptr,*ptr);
return 0;
}
o/p:
&a:3213284540,&a[0]:3213284540,ptr:3213284540
&a:3213284540,&a[0]:3213284540,ptr:3213284560
&a:3213284540,&a[0]:3213284540,ptr:3213284556,*ptr:4
In the above code &a and &a[0] gives the same address 3213284540. But the two cases when added with 1 gives different address.
&a[0]+1 => 3213284540 + 4 = 3213284544 [The value stored in this address is '1']
&a+1 => 3213284540 + (5*4) = 3213284560 [Goes Out of bounds of the array]
&a+1 is equivalent to sizeof(array)+1.
But how the compiler interprets this &a[0]+1 and &a+1 ?
But how the compiler interprets this &a[0]+1 and &a+1
It's pointer arithmetic, so it's always important to know the pointed types and one basic thing: adding 1 to a pointer makes it point to some "next" element.
In your example &a[0] is of type int * so adding 1 moves the
pointer to the next int. So the address should increase by 4/8
bytes or so, depending on sizeof(int)
However, &a is of type int (*)[5]. So adding 1 to it moves the
pointer to the next array. In effect, the address should increase
by sizeof(a).
Side note: use %p when printing pointer values.