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 *.
Related
#include<stdio.h>
int main(){
int a[2] = {0, 1};
printf("%d\n",a);
printf("&a + 1 %d\n",&a + 1);
printf("a + 1 %d\n",a + 1);
return 0;
}
The result is as follows:
6422232
&a + 1 6422240
a + 1 6422236
Why are &a + 1 and a + 1 different?
In &a+1, &a takes the address of the array. This yields a pointer to an array, so adding one adds the size of one array. This is because each type of pointer has its own unit of measurement—adding one always adds one of the pointed-to objects.
In a+1, a is the array itself. C automatically converts an array to the address of the first element. So, a yields a pointer to an element, so adding one adds the size of one element.
(In &a+1, a was not automatically converted to a pointer to the first element. Using & with an array is an exception to the conversion. See note 1 below.)
Notes
The automatic conversion of an array to a pointer to its first element occurs in most situations. It does not occur when the array is the argument of sizeof, &, or _Alignof or when the array is a string literal used to initialize an array.
In C’s model, a pointer uses units of whatever type of object it points to. So saying “adds the size of one array” is a bit imprecise. However, if we are talking about navigating storage using valid pointers in an array of objects, moving from one object to another traverses a number of bytes equal to the size of the object.
You should not print pointers with %d. The behavior of that is not defined by the C standard. To print a pointer, convert it to void * and print with %p:
printf("%p\n", (void *) a);
printf("&a + 1 %p\n", (void *) (&a + 1));
printf("a + 1 %p\n", (void *) (a + 1));
Note that %p does not necessarily produce the actual memory address. The C standard allows an implementation to produce some other representation of the pointer. In good C implementations without complicated memory models, %p will print the memory address of the pointed-to object. However, this is a quality-of-implementation feature.
Yes though a and &a have same values. Their type is different. In pointer arithmetic type matters.
For example over here a decayed into pointer to first element(int*) in (a+1)and then it is incremented by sizeof(int).
Where as &a is a case where decaying won't happen. So &a is of type int (*)[2] (pointer to an array of 2 int elements) now when you add to it 1 it moves by the size of the array or 2*sizeof(int).
This is why they are different.
First to be very clear the name of array is a constant pointer to the array. So it constantly points to address in memory where the array 1st element is store. The answer of &a+1 and a+1 differs cause the & a+1 what does its increments the address of array in normal words in increments the size of array and a + 1 prints you the value in addition of 1st element of the array
someone please explain the output of the following code..
#include <stdio.h>
int main()
{
int arr[5];
// Assume base address of arr is 2000 and size of integer is 32 bit
printf("%u %u", arr + 1, &arr + 1);
return 0;
}
also explain the out when the "printf" statement is replaced by following
1. printf("%u %u", arr + 1, &(arr + 1));
2. printf("%u %u", arr + 1, &arr + 2);
First of all it is better to use format specifier %p that is specially designed for pointers instead of format specifier %u
In this statement
printf("%u %u", arr + 1, &arr + 1);
in expression arr + 1 array arr is converted to pointer to its first element. So it has type after conversion int * and correspondingly the element it points to has type int. Due to the pointer arithmetic expression arr + 1 will point to the next element of the array that is to the second element. So the value of pointer arr+ 1is greater than the value of pointerarrbysizeof( int )`
In this expression &arr + 1 pointer &arr has type int ( * )[5] . The element it points to (that is array arr) has type int[5] . So the value of expression &arr + 1 greater than the value of &arr by sizeof( int[5] )
As for expression &(arr + 1) then it will not compile because arr + 1 is a temporary object and you may not take the address of a temporary object.
Output of 1st printf will be(According to assumption you specified) -2032 2160
as arr+1 points to next element that is arr[1] and &arr+1 in this arr is a int(*)[5] points to int[5] thus address of arr that is base address plus size of int[5] (here in your case 5*32).
In your second printf &(arr+1) is not lvalue thus does not occupy some identifiable location in memory.Thus will give an error.
Thrid printf will give output as 2032 2320.Can be evaluated as done in 1st printf.
The output of above code is 2004 2020.
The value arr and &arr yield to same result as the array is uninitialized it will print the value of address on place of its value.
This is due of the fact bcz when u print (arr+1) ,it adds the size of arraytype i.e int (4byte) to result
But when u do ( &(arr+1)) ,it will adds the size of whole array i.e (5*4=20 bytes )to base address.
When u print &(arr+1) it will produce error bcz it will now treat & as unary& not as addressing operator
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.
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;