#include <stdio.h>
int main() {
int arr[3] = { 1, 2, 3 };
int *p = arr;
int (*r)[3] = arr;
printf("%u %u", p, r);
printf("\n%d %d %d", p[0], p[1], p[2]);
printf("\n%d %d %d", r[0], r[1], r[2]);
printf("\n%d %d %d", *r[0], *r[1], *r[2]);
printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2]);
}
Output:
1483745184 1483745184
1 2 3
1483745184 1483745196 1483745208
1 0 -647513344
1 2 3
As you can see p and r contains same address, then
why does p[0] work but r[0] doesn't?
what goes behind p[0]?
why does (*r)[0] work but others don't?
EDIT: Other than accepted answer, this answer is also helpful https://stackoverflow.com/a/71218214/12491154
The difference between these two declarations
int *p = arr;
int (*r)[3] = arr;
is that in the second declaration there is used a wrong initializer. The array arr used as an initializer is implicitly converted to pointer to its first element of the type int *. So in the second declaration the initialized object and the initializer have different pointer types and there is no implicit conversion between the types.
To make the second declaration correct you need to write
int (*r)[3] = &arr;
Now the both pointers p and r stores the same value: the address of the extent of memory occupied by the array but have different types.
For example if you will write
printf( "sizeof( *p ) = %zu\n", sizeof( *p ) );
printf( "sizeof( *r ) = %zu\n", sizeof( *r ) );
then the first call will output the size of an object of the type int that is equal to 4 while the second call will output the size of the whole array of the type int[3] that is equal to 12.
In this your call of printf
printf("%u %u", p, r);
there are used incorrect conversion specifiers with pointers. Instead you have to write
printf("%p %p", ( void * )p, ( void * )r);
The expressions r[0], r[1], r[2] have the type int[3]. Used in this call
printf("\n%d %d %d", r[0], r[1], r[2]);
they as it was mentioned are implicitly converted to pointers to their first elements. But these arrays except the array r[0] that denotes the array arr do not exist. So there takes place an access to memory beyond the array arr,
You could write
printf( "\n%p\n", ( void * )r[0] );
and this call will be equivalent to
printf("\n%p\n", ( void * )arr );
This call of printf
printf("\n%d %d %d", *r[0], *r[1], *r[2]);
is also incorrect because arrays r[1] and r[2] of the type int[3] do not exist.
This call of printf
printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2]);
outputs elements of the array arr due to using the expression *r.
The difference between r and p is solely in the type.
The first thing to note is that the assignment int (*r)[3] = arr; is not correct; arr in assignments decays to a pointer to its first element, an int, which is a different type than r which is a pointer to an array of three ints. Now admittedly, C originally wasn't that picky, and assignments between different pointer types and between pointers and integers weren't given much thought — it's all numbers, right? But modern C tries to be more type safe, for good reason, so the proper assignment would be int (*r)[3] = &arr;: If you want the address of an array, just take the address. Your code "works" because numerically the address of the first element is the address of the array. It's the type that's wrong, not the value.
Now to your confusion: As you noted, both point to the same address; but the object p is pointing to is a simple int (which just so happens to be followed by two more ints in memory, together comprising arr), while r is pointing to the array itself.
Consequently, the type of *p is int while the type of *r is int[3], and consequently to that sizeof *r == 3 * sizeof *p holds.
As you know, C blurs that distinction in most contexts: For example, you could legitimately say p = *r;, because arrays are "adjusted" or "decay" to pointers to their first element in assignments or parameter initialization.
But for sizeof they don't. That is because indexing adds index * sizeof(element) to the numerical value of the pointer; if the pointer points to an entire array, like r (as opposed to its first element only, like p), the second element will be the next array, which isn't there — there is only one array, so your program is faulty.
#include <stdio.h>
int main() {
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*r)[3] = arr;
printf("%p %p\n", (void*)r[0], (void*)r[1]);
}
This little program illustrates this. Note how arr again decays to the address of its first element; only this time, the first element of that two-dimensional array is an array itself, of three ints, so it fits perfectly.
The types of p and r are very different:
p is a pointer to int, initialized to point to the first element of array arr,
r is a pointer to an array of 3 int: the initialization is incorrect, it should be r = &arr.
printf("%u %u", p, r) has undefined behavior: %u expects an argument with type unsigned int, p and r are pointers which should be cast as (void *) and convered with %p.
printf("\n%d %d %d", p[0], p[1], p[2]) is correct and produces 1 2 3 as expected
printf("\n%d %d %d", r[0], r[1], r[2]) has undefined behavior for multiple reasons: r[0] and r[1] decay as pointers to int, they should be cast as (void *) and printed using %p. r[2] is an invalid pointer: computing its value and passing it as an argument has undefined behavior.
postfix unary operators bind stronger than prefix operators, so *r[0] as parsed as *(r[0]), which is the same as r[0][0], the first element of the array arr. Conversely *r[1] is equivalent to r[1][0], which refers to an invalid area, beyond the end of arr, same for *r[2], so reading both of these cause undefined behavior.
conversely (*r)[0] is the same as (r[0])[0], hence r[0][0], the first element of arr, and similary (*r)[1] is the same as r[0][1] so printf("\n%d %d %d", (*r)[0], (*r)[1], (*r)[2]) outputs 1 2 3 just like printf("\n%d %d %d", p[0], p[1], p[2]).
p and r (initialized as r = &arr) indeed point to the same location, but they have different types which must be taken into consideration when writing code.
Here is a modified version:
#include <stdio.h>
int main() {
int arr[3] = { 1, 2, 3 };
int *p = arr;
int (*r)[3] = &arr;
printf("arr: address %p, sizeof(arr): %2zu bytes, sizeof(*arr): %2zu bytes\n",
(void *)arr, sizeof(arr), sizeof(*arr));
printf("p: address %p, sizeof(p): %2zu bytes, sizeof(*p): %2zu bytes\n",
(void *)p, sizeof(p), sizeof(*p));
printf("r: address %p, sizeof(r): %2zu bytes, sizeof(*r): %2zu bytes\n",
(void *)r, sizeof(r), sizeof(*r));
printf("arr: %p, arr+1: %p\n", (void *)arr, (void *)(arr + 1));
printf("p: %p, p+1: %p\n", (void *)p, (void *)(p + 1));
printf("r: %p, r+1: %p\n", (void *)r, (void *)(r + 1));
printf("%d %d %d\n", p[0], p[1], p[2]);
printf("%d %d %d\n", r[0][0], r[0][1], r[0][2]);
printf("%d %d %d\n", (*r)[0], (*r)[1], (*r)[2]);
return 0;
}
Output:
arr: address 0x7fff544137f8, sizeof(arr): 12 bytes, sizeof(*arr): 4 bytes
p: address 0x7fff544137f8, sizeof(p): 8 bytes, sizeof(*p): 4 bytes
r: address 0x7fff544137f8, sizeof(r): 8 bytes, sizeof(*r): 12 bytes
arr: 0x7fff544137f8, arr+1: 0x7fff544137fc
p: 0x7fff544137f8, p+1: 0x7fff544137fc
r: 0x7fff544137f8, r+1: 0x7fff54413804
1 2 3
1 2 3
1 2 3
*p is a pointer to an array, while (*r)[3] is an array pointer to an array.
*p will point to the values/indices of the array arr whereas (*r)[i] will point to the memory location/address of the indices.
*r will point nowhere as (*r) and *r are DIFFERENT.
Related
Below is a code snippet and the outputs:
int main()
{
int A[2][3] = {{1100, 1200, 1300}, {1400, 1500, 1600}};
int (*p)[3], (**q)[3];
p = A;
q = A;
printf("*p is : %d\n", *p);
//Output : *p is : -547221600
printf("*q is : %d", *q);//Why ?
//Output : *q is : 1100
}
p is a pointer to integer array of size 3. *p + i points to ith array in A i.e. A[i].
What would happen if instead I use double pointers (q in the above code).
I am unable to understand that why *q gives 1100 as the value.
For starters this assignment
q = A;
is incorrect because the left operand (having the type int ( ** )[3]) and the right operand (having the type int ( * )[3] after the implicit conversion of the array designator to a pointer to its first element) have different types and there is no implicit conversion between the types.
The compiler can issue an error like this
error: assignment to ‘int (**)[3]’ from incompatible pointer type ‘int (*)[3]’
You could write instead
q = &p;
In this call of printf
printf("*p is : %d\n", *p);
there is used an incorrect argument. The type of the expression *p is int[3]. So in fact you are trying to output a pointer (due to implicit conversion of the array designator to a pointer to its first element) using the conversion specifier %d that is designed to output integers.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
int A[2][3] = {{1100, 1200, 1300}, {1400, 1500, 1600}};
int (*p)[3], (**q)[3];
p = A;
q = &p;
printf( "A is : %p\n", ( void * )A );
printf( "*p is : %p\n", ( void * )*p );
printf( "*q is : %p\n", ( void * )*q);
return 0;
}
Its output might look like
A is : 0x7ffdb1c214e0
*p is : 0x7ffdb1c214e0
*q is : 0x7ffdb1c214e0
That is the first call of printf output the initial address of the first element A[0] (of the type int[3]) of the two-dimensional array.
The second call of printf outputs the address of the first element of the first "row" of the two-dimensional array that is &A[0][0].
The third call of printf outputs the value stored in the pointer p that is the address of the first "row" of the two-dimensional array A.
If you want to output the first elements of the array A using the pointers then the program can look the following way.
#include <stdio.h>
int main(void)
{
int A[2][3] = {{1100, 1200, 1300}, {1400, 1500, 1600}};
int (*p)[3], (**q)[3];
p = A;
q = &p;
printf( "**p is : %d\n", **p );
printf( "***q is : %d\n", ***q);
return 0;
}
Now the program output is
**p is : 1100
***q is : 1100
p is a pointer to integer array of size 3.
Correct.
*p + i points to ith array in A i.e. A[i].
Incorrect. p + i would be a pointer to an array.
When you indirect through the pointer to array, the result is an array, and when you add an integer to an array, the array decays to pointer to element of that array and since *p is an array of integers, the decayed pointer points to an integer element of the array. Thus, the result of *p + i is a pointer to an integer (i'th sibling of the first element of the first array).
What would happen if instead I use double pointers (q in the above code).
I assume that by substituted above code, you mean *q + i.
If you have a pointer to a pointer to an array, then indirecting through the pointer results in a pointer to an array. Adding an integer to pointer to an array gives you pointer to an array that is a sibling.
q = A;
This assignment is ill-formed in C++. An array of arrays of integers is not convertible to a pointer to pointer to an array.
printf("*p is : %d\n", *p);
printf("*q is : %d", *q);//Why ?
%d is an invalid format specifier for int* as well as for a int (*)[3]. By using invalid format specifier, the behaviour of this program is undefined. That explains all of the behaviour.
#include<stdio.h>
#define my_sizeof(type) (&type+1) - (&type)
int main()
{
int y;
printf("size_of int: %ld\n", sizeof(y));
printf("address of y = %x \n",&y);
printf("address of y +1 = %x \n", &y+1);
printf("The sizeof = %d\n", my_sizeof(y));
getchar();
return 0;
}
Output:
size_of int: 4
address of y = 26f890
address of y +1 = 26f894
The sizeof = 1
I am expecting the my_sizeof output as "4" (i.e., 26f894 - 26f890) but it is printing as "1".
Suppose if I typecast it as char* (i.e., (char*) (&type+1) - (char*)(&type)) the output is "4".
Can anyone tell me the need for (char*) typecasting.?
In this expression
(&type+1) - (&type)
there is used the pointer arithmetic. The difference between two pointers that point to elements of the same array or one past the last element of the array is equal to the number of elements between two pointers.
And an object of the type int in your system occupies 4 bytes then casting the pointers to the type char * yields 4.
From the C Standard (6.5.6 Additive operators)
9 When two pointers are subtracted, both shall point to elements of
the same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the two
array elements....
For the pointer arithmetic a single object is considered as an array having one element.
I have corrected plenty UBs in the printfs
#include<stdio.h>
#define my_sizeof(type) ((char *)(&type+1) - (char *)(&type))
int main()
{
int y;
printf("size_of int: %zu\n", sizeof(y));
printf("address of y = %p \n",(void *)&y);
printf("address of y +1 = %p \n", (void *)(&y+1));
printf("The sizeof = %zu\n", my_sizeof(y));
getchar();
return 0;
}
I know there are many similar questions, but I can't find an answer.
When passing the two-dimensional [3] [4] array to the function in my code below, how does the compiler know how far to increment the pointer, in the case of the last printf() where we are incrementing 3 x 4 memory locations, if the number 3 is missing in the function argument?
I mean, why is only arr [] [4] sufficient and not [3] [4]? Thanks
#include <stdio.h>
#include <stdlib.h>
int Fun(int arr[][4])
{
printf("%p\n", arr); // address of first element
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
}
int main()
{
int arr[3][4] =
{
1,2,3,4,
5,6,7,8,
9,10,11,12
};
printf("%p\n", arr);
printf("%p\n", arr[0] + 1);
printf("%p\n", arr + 1);
printf("Passing to function\n");
Fun(arr);
return 0;
}
First, Fun should be defined with:
int Fun(int arr[][4])
rather than what you have, int Fun(int* arr[][4]);.
Next, when Fun(arr) is evaluated, arr is automatically converted from an array of 3 arrays of 4 int to a pointer to an array of 4 int. Similarly, in the declaration of Fun, int arr[][4] is automatically adjusted to be a pointer to an array of 4 int. So the argument type and the parameter type will match if you declare Fun correctly.
You could also declare Fun as:
int Fun(int (*arr)[4])
This is the same thing as above, due to the automatic adjustment that would be applied to the declaration above. Note that the asterisk here is grouped with the arr by the parentheses. This makes it a pointer to an array of int, rather than an array of pointers to int.
Now, as to what will be printed, in main:
printf("%p\n", arr);
In this statement, arr will be automatically converted to a pointer to its first element, so it becomes a pointer to an array of 4 int. Then the value of this pointer is printed. Note: When printing pointers, technically you should convert them to const void * or void *, as with printf("%p\n", (const void *) arr);. However, omitting this likely does not cause a problem at the moment.
printf("%p\n", arr[0] + 1);
In this statement, arr[0] is the first element of arr. That first element is an array of 4 int, and it is automatically converted to be a pointer to its first element. So arr[0] becomes a pointer to the first int. Then adding 1 advances the pointer to the next int. The result is likely an address four bytes beyond arr, depending on your C implementation. (It could be a different number of bytes, but four is the most common today.)
printf("%p\n", arr + 1);
In this statement, arr is converted to a pointer to its first element, an array of 4 int. Adding 1 advances to pointer to the next element, which is the next array of 4 int. So this likely adds 16 bytes to the address.
Then, in Fun:
printf("%p\n", arr); // address of first element
Here arr is a pointer to an array of 4 int. Its value is printed, yielding the same address as for the corresponding printf in main.
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
Here arr[0] is the object pointed to by arr, which is an array of 4 int. Since it is an array, it is automatically converted to a pointer to its first element, which is an int. So this points to the first int. Then adding 1 advances to the next int, and this again yields the same address as the corresponding printf in main.
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
In this case, arr is a pointer to an array of 4 int, and adding 1 advances it to the next array of 4 int, so the result is likely 16 bytes beyond the value of arr, and this again yields the same address as the corresponding printf in main.
If you saw different values for the printf statements in Fun and main, this was likely because of the incorrect declaration with int* and because int * is eight bytes in your C implementation, compared to four for int. That error would have doubled some of the increments. You should not have seen any multiple of three in the increments.
Regarding the first dimension, Fun does not need to know the first dimension because it never advances any pointers by units of the first dimension. It receives only a pointer to an array of 4 int, and it does not need to know that there are 3 such arrays there.
The detailed answer by Eric Postpischil clearly shows all the issues in OP's code.
I'd like to note that passing a pointer to the correct type would let the compiler doing the right pointer arithmetic:
#include <stdio.h>
#include <stdlib.h>
void Fun(int (*arr)[3][4])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
void Fun_vla(size_t rows, size_t cols, int (*arr)[rows][cols])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
int main()
{
int arr[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
Fun(&arr);
puts("");
Fun_vla(3, 4, &arr);
return 0;
}
I've written a few lines of code predominantly from a book that gets you to declare an integer array, then subtract and pass two addresses from the array to another integer, in order to pass into a printf statement. I'm not sure why, but my actual pointers: aPointer and bPointer seem to be 8 bytes, which poses a problem when I try and pass the subtracted addresses to an integer.
I then changed the latter to a long. The errors are not present in Xcode now, but I cannot print the address of pointerSubtraction properly using the %p specifier which does indeed expect an int and not a long.
int arrayOfInts[10];
for (int i = 0; i < 10; i++) {
arrayOfInts[i] = i;
printf("%d", arrayOfInts[i]);
// prints out 0123456789
}
printf("\n");
int *aPointer = &arrayOfInts[1]; // get address of index 1
int *bPointer = &arrayOfInts[7]; // get address of index 7
long pointerSubtraction = bPointer - aPointer; // subtract index 7 with 1
printf("The size of aPointer is %zu bytes \n", sizeof(aPointer));
printf("The size of aPointer is %zu bytes \n", sizeof(bPointer));
printf("The address of aPointer is %p \n", aPointer);
printf("The address of bPointer is %p \n", bPointer);
printf("The address of final is %p \n", pointerSubtraction);
printf("The value of pointerSubtraction is %ld \n \n", pointerSubtraction);
You might like to use a variable typed ptrdiff_t to store the difference of two pointer values, two addresses.
To printf() out a ptrdiff_t use the length modifier "t". As ptrdiff_t is a signed integer use the conversion specifier "d".
#include <stddef.h>
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0, * pa = &a;
ptrdiff_t ptr_diff = pa - &b;
printf("pd = %td\n", ptr_diff);
return 0;
}
Also the conversion specifier "p" is only defined for pointers to void. So the printf() calls shall look like:
printf("The address of aPointer is %p \n", (void *) aPointer);
printf("The address of bPointer is %p \n", (void *) bPointer);
Also^2 : The result of adding or substrating a value v from a pointer p is only a valid address if the result pv of the operation still refers to (an element/member of) the object the original pointer p pointed to.
In your code aPointer is the value pointed by *aPointer. Same thing for bPointer.
As the comment says pointerSubtraction is the value obtained by the subtraction, not the address.
I'm trying to understand the difference between int a and int *a, my first step was to see the value I could get by printi %p of an int a. Of course the compiler shows warnings, but does complete the job for the following code.
#include <stdio.h>
int main() {
int a;
printf("a - declared");
printf("int a = [%d]\n", a); // example - 1745899614
printf("int a pointer = [%p]\n", a); // example - 0x6810505e
a = 10;
printf("a - initialized to value of 10\n");
printf("int a = [%d]\n", a); // exmaple - 10
printf("int a pointer = [%p]\n", a); // example - 0xa
return 0;
}
And as I've mentioned in the source code, I do get a somewhat satisfactory result of 0xa which is equal to 10 in hexadecimal for the value of %p of an int a. But is it actually the case that int points to to that address, or is this just the compiler trying to make sense of %p in such a case?
Where is the memory allocated for ints? How do I test for that?
To print the address of an object named a, use:
printf("The address of a is %p.\n", (void *) &a);
Merely using %p does not tell printf to print the address of the object you use as the argument. You must use the “address of” operator, &, to take the address. Otherwise, you are passing the value of a to printf, not the address of a.
Additionally, it is proper to convert the address to void *, as shown above, because the %p specifier expects a pointer to void. Other types of pointers often work (or appear to work) in many C implementations, but the technical requirement is that a pointer to void be passed.
I imagine the formater ( in printf ), is just interpreting the memory as it is told to. So yeah, "%p" is for pointer, but you gave it an int. You wanted to give it the address of a:
printf( "%p", &a );
for the whole shabang:
int a = 10;
int *b = &a;
printf("value of a: %d\n", a );
printf("location of a: %p\n", &a );
printf("value of b: %p\n", b );
printf("location of b: %p\n", &b );
printf("dereference b: %d\n", *b );
But is it actually the case that int points to to that address, or is
this just the compiler trying to make sense of %p in such a case?
It's the latter. Compiler tries to interpret the integer as a pointer. When you print the value of a using %p compiler finds that the type of a is int and warns you that it's not a pointer.
To print the address of a use:
printf("int a pointer = [%p]\n", (void*)&a);
If a is a pointer (e..g int *a;) then you need to initialize it with a valid address and then you can print:
printf("int a pointer = [%p]\n", (void*)a);
%p is merely a way to tell printf to print your value as an address memory. You're passing the value of 10to it (the value of a) and you get printed this value in the hexadecimal notation 0xa. There is no special interpretation, it is just a formatting option.
If you want the value of the a's address memory printed you can simply do printf("%p", &a);. &a is the address of a.
Or if you want to use a pointer:
int* p;
p = &a;
printf("%p", p); //Prints the p value, that is the a address. Equivalent to printf("%p", &a).