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.
Related
I'm working with pointers for the first time in C. I tried to declare, initialize, and assign a memory address to 3 pointers, then print the addresses and values of each pointer and variable, then assign a value to the pointer so that the value of the data which has the memory address is changed. Here is the code:
int i = 5;
float f = 7.77;
char c = 'a';
int iNumber = 2;
float fNumber = 5.55;
char cCharacter = 'c';
int *iPtr;
float *fPtr;
char *cPtr;
iPtr = &i;
fPtr = &f;
cPtr = &c;
printf("\nThe current values are: ");
printf("%d %f %c", i, f, c);
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
iNumber = *iPtr;
fNumber = *fPtr;
cCharacter = *cPtr;
printf("\nThe modified values are: ");
printf("%d %f %c", i, f, c);
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
return 0;
is when I change the values of i, f, and c.
However, when I run the program the memory addresses for the int variables are not in hexadecimal format, they're in random numbers that change every time I run the program. The addresses for the char ones don't appear. Also, when I modifiy the values in the pointers the variables they're pointing to don't change. I thought this was how you referenced by value, i'm really confused.
This (second) call of printf
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
is wrong. You are trying to output pointers as objects of the type int, float and char that does not make sense.
If you want to output stored addresses in the pointers you need to write
printf("\nThe addresses of each pointer are: ");
printf("%p %p %p\n", ( void * )iPtr, ( void * )fPtr, ( void * )cPtr);
(do not forgot to place the new line character '\n' in the format string)
Also in this call of printf
printf("\nThe modified values are: ");
printf("%d %f %c", i, f, c);
you are not outputting modified values. The values of the variables i, f, and c were not changed. It seems you mean instead
*iPtr = iNumber;
*fPtr = fNumber;
*cPtr cCharacter;
printf("\nThe modified values are: ");
printf("%d %f %c\n", i, f, c);
Changing the value using Pointer
I think ultimately you want to change the value of i from 5 to the value of the variable iNumber, which is 2 using pointer.
Your code :
iNumber = *iPtr;
fNumber = *fPtr;
cCharacter = *cPtr;
What you've done here is, assigned the value of each pointer variable to the iNumber, fNumber, cCharacter variables.
So now if you print those variables you could see that the values of iNumber, fNumber, cCharacter is changed to 5, 7.77, a accordingly. Because, those pointer variables are pointing to the address of the first 3 variables, that are &i, &f and &c as you've might guessed.
Solution :
*iPtr = iNumber;
*fPtr = fNumber;
*cPtr = cCharacter;
As you can see in the above snippet, you need to assign the new values/variable to the pointer variable instead of doing the opposite.
Printing the Address of a Variable
Your code :
printf("\nThe addresses of each pointer are: ");
printf("%d %f %c", iPtr, fPtr, cPtr);
To print the memory addresses of variables in C, you need to use the %p format specifier in printf() instead of %d or %f. The %p format specifier is specifically used for printing memory addresses in hexadecimal format.
Also, when you're printing the memory address of a variable, you have to use the address-of operator (&), which is used to get the address of a variable.
Solution :
printf("\nThe addresses of each pointer are: ");
printf("%p %p %p", &iPtr, &fPtr, &cPtr); // hexadecimal
// not the standard way to represent memory addresses
printf("%u %u %u", &iPtr, &fPtr, &cPtr); // decimal
Tip : You can print the address in Decimal instead of Hexadecimal
for ease of mind, just by replacing %p to %u. (the adreess-of operator remains intact while printing memory addresses)
Why do the memory addresses change on each run?
When you run your C program, the computer assigns a memory address to each variable in your program. The memory address is typically represented as a large number, usually in hexadecimal format. The memory address is important because it allows the program to access and manipulate the value of the variable stored at that location in memory.
However, the memory address of a variable can change from one program run to another, for a number of reasons, such as randomization of the memory space, allocation of memory on the heap or stack, or optimization of the program code by the compiler or linker.
But as a beginner, you don't have to worry about it.
#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.
If a pointer "p" holds the address of a variable "a". if a=12 ( just taking an integer ) . If the address of "a" is 1024 (just an assumption for asking my doubt). That means the value in "p" is 1024. This 1024 is address but it is basically a number . Then why it doesn't work when we declare the integer pointer variable "p" as integer variable "p". like:
int p, a=12;
p=&a;
printf("value of a is : %d", *p );
The example could be properly written (with some additional output) as:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
intptr_t p;
int a = 12;
p = (intptr_t)(void *)&a;
printf("value of a at %" PRIdPTR " is : %d\n", p, *(int *)(void *)p);
return 0;
}
That relies on the following facts:
A pointer to any object can be converted to void * and back to a pointer to the original object type and it will compare equal to the original pointer to the object (so it will still point to it).
A pointer to void can be converted to a intptr_t or a uintptr_t value (by a cast operator) and back again and it will compare equal to the original pointer.
The PRIdPTR macro defined by #include <inttypes.h> expands to a string literal containing a printf conversion specifier (possibly preceded by a length modifier) suitable for printing the value of a parameter of type intptr_t as a signed decimal number. It is being included in the printf format string by string literal concatenation.
A void * pointer value is usually printed using the %p printf format, for example:
printf("value of a at %p is : %d\n", (void *)p, *(int *)(void *)p);
or:
printf("value of a at %p is : %d\n", (void *)&a, a);
To declare p as a pointer to int do it the following way:
int *p; /* p is a pointer to int */
so, with initializers:
int a = 12, /* a is an integer var and it's initialized to 12 */
*p = &a; /* p is an integer pointer and it's initialized to the addreess of a */
or as assignments:
a = 12; /* a is assigned the value 12 */
p = &a; /* p is assigned the address of a */
works, and *p will have the same value as a.
printf("value of a is : *p==%d (or what should be the same: a==%d)", *p, a);
*p means the to take data from the place which p stores.
The * operator when applied to an operand p basically means "read what's on address stored in p and interpret it as the type indicated by the pointer type p is declared as"
You're missing the last part. In your case, p is not a pointer, so the dereference operator does not make sense to use.
#include <stdio.h>
int main()
{
int i;
int buf[10];
char *p ;
p = 4;
printf("%d",p);
return 0;
}
Output:
4
How come it is 4? I was expecting some address value. Can you please help me understand it?
This is undefined behavior, because %d expects an integer.
The reason why you see this output is that pointers have enough capacity to store small integer numbers, such as 4. If by coincidence the pointer size on your system matches the size of an integer, printf would find a representation that it expects at the location where it expects it, so it would print the numeric value of your pointer.
The proper way to print your pointer would be with the %p format specifier, and a cast:
printf("%p", (void*)p);
I was expecting some address value.
You would get an address value if you had assigned p some address. For example, if you did this
char buf[10];
char *p = &buf[3];
printf("%p", (void*)p);
you would see the address of buf's element at index 3.
Demo.
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).