What is printing out when int pointer is printed with %d? - c

This code:
#include <stdio.h>
int main() {
int num;
int *pi;
num = 0;
pi = &num;
printf("address: %p | %d\nvalue: %d\n", pi, pi, *pi);
}
produces this output:
address: 0x7fff5952f9cc | 1498610124
value: 0
I know that the left one is supposed to be the correct address, but what is printing out next to the address?

%p tells printf to treat the corresponding variable as a pointer, thus printf prints p as a pointer; that is, a hexadecimal representation (i.e. 0x7fff5952f9cc). %d on the other hand tells printf to treat the corresponding variable as numeric. Therefore, what is being printed is the actual, numeric value of p (i.e. 1498610124) which is just 0x5952f9cc in base 10.
Now, the reason why these two representations of the same variable seem to have different values is that %d only tells printf to expect a number---it doesn't specify that number's type. If you cast 0x7fff5952f9cc (a 64-bit integer) to int (a 32-bit type) you get 1498610124 (notice 0x7fff getting dropped).

You are printing the address in decimal instead of in hex but it is truncated to an int.

I guess you are executing this program on a 64bit machine.
The number printed next to the address is still the address of the pointer printed in the integer format. You can also see that the value is truncated
decimal of 0x7fff5952f9cc = 140734691998156. but it is printed as 1498610124 which is due to truncation.

you are trying to print the address of num in hex and decimal value respectively. If I am not wrong you are running your program on a 64 bit architecture and hence the address will be of 8 bytes. So your address fits in long data type. By giving %d you are value is getting truncated here. Instead of %d please use %ld. So your printf of statement should be actually as below
printf("address: %p | %ld\nvalue: %d\n", pi, pi, *pi);
Now run the program you will get your value correctly in decimal format.

It could be anything, because it's Undefined Behaviour. (C standard, § 7.21.6.1, The fprintf function):
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
You print pi (a pointer to an int) with two format specifiers, %p and %d. According to the C standard (and probably reproduced word for word in man fprintf on your system):
d,i The int argument is converted to signed decimal in the style [−]dddd
p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
So neither of those uses is correct. It's not a pointer to void and it's also not an int. So what you should write is:
printf("address: %p | %d\nvalue: %d\n", (void*)pi, (int)pi, *pi);
On your system, that probably produces the same output (Undefined Behaviour includes unexpectedly producing the incorrectly expected behaviour) but it might not. In any case, writing the line correctly makes it relatively clear what the second number printed is: it's the value of the pointer converted to an integer.
However, there is no guarantee that this will work, either. Again, from the standard (§6.3.2.3, Pointers, para. 6):
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined.
(The "previously specified" case is that a NULL pointer may reliably be converted to any integer type; it will have the value 0.)
So the idea is that a pointer is a lot like an integer, but it might be the size of a long. Or a long long. Or something else. It might even be bigger than any integer type, but if there is some integer type which is the right size and you #include <stdint.h>, that integer type will be typedef'd to intptr_t and its unsigned version (probably more useful) will be uintptr_t. Unfortunately, there is no standard printf conversions for those sizes, so if you really want to, you would need to #include <intypes.h> and write:
printf("address: %p | %" PRIuPTR "\nvalue: %d\n",
(void*)pi, (uintptr_t)pi, *pi);
Alternatively, because it is always allowed to convert any integer to any unsigned integer (with possible loss of information, but with a well-defined conversion), you could use two casts:
printf("address: %p | %u\nvalue: %d\n",
(void*)pi, (unsigned)(uintptr_t)pi, *pi);
(Because that supplies an unsigned int argument, the format specifier must be u instead of d.)

When using printf, the "p" modifier is intended to print out a memory address in hex format. The "d" modifier tells it to cast the value to a signed integer value. So it's taking 0x7fff5952f9cc and turning it into a signed int.
See this for more details on printf.

In that code who have to print the address as the %d so during compile time it displayed warning and %p display the hexadecimal but %d display the integer.

Its lower part – 4 least significant bytes – of the pointer value in decimal:
0x5952F9CC == 1498610124.

Related

But what exactly is printed when %d is used instead of %p?

As the code shows this random, seemly trash, number printed when %d is called is spaced 'sizeof(type)' numbers of the next element of a vector.
BUT if I convert the hexadecimal address of the first element, it does not match with the number.
So if it isn't the address represented in decimals, then what this printed number exactly is?
0x7ffcd6b154c0 == 140723910431936
Whereas the printed decimal was -693021504
#include <stdio.h>
void main(){
int x[] = {2, 5}, *ptr = &x;
printf("%d\n", ptr);
printf("%p\n", ptr);
printf("\n%d %d\n", ptr, (ptr + 1));
}
It's using the D6B154C0, from the 7ffcd6b154c0 which is -693021504 as a 32 bit number.
It's a dice-roll because you invoke Undefined Behavior:
C11 Standard - 7.21.6.1 The fprintf
function(p9) "If
a conversion specification is invalid, the behavior is undefined. If
any argument is not the correct type for the corresponding conversion
specification, the behavior is undefined."
More likely than not what will print is the actual pointer address on system where pointers are the same size as int (e.g. x86), otherwise, you will print 4-bytes out of the 8-byte pointer if you are lucky.
The size of a typical integer is 4 bytes(range of integers being -2,147,483,648 to 2,147,483,647) for modern compilers.
And when "%d" is used as a type specifier, it prints the address pointed by ptr as a 32-bit integer.
But
Since the size of ptr is typically 8 bytes the value of address that is in Hexadecimal can't be converted to Decimal completely,
Thus an inconsistency is introduced.
Understand it another way:
140723910431936 is nowhere between the range of integers and printing it with type specifier "%d" won't provide correct result

Why is this code printing 0?

void main()
{
clrscr();
float f = 3.3;
/* In printf() I intentionaly put %d format specifier to see
what type of output I may get */
printf("value of variable a is: %d", f);
getch();
}
In effect, %d tells printf to look in a certain place for an integer argument. But you passed a float argument, which is put in a different place. The C standard does not specify what happens when you do this. In this case, it may be there was a zero in the place printf looked for an integer argument, so it printed “0”. In other circumstances, something different may happen.
Using an invalid format specifier to printf invokes undefined behavior. This is specified in section 7.21.6.1p9 of the C standard:
If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
What this means is that you can't reliably predict what the output of the program will be. For example, the same code on my system prints -1554224520 as the value.
As to what's most likely happening, the %d format specifier is looking for an int as a parameter. Assuming that an int is passed on the stack and that an int is 4 bytes long, the printf function looks at the next 4 bytes on the stack for the value given. Many implementations don't pass floating point values on the stack but in registers instead, so it instead sees whatever garbage values happen to be there. Even if a float is passed on the stack, a float and an int have very different representations, so printing the bytes of a float as an int will most likely not give you the same value.
Let's look at a different example for a moment. Suppose I write
#include <string.h>
char buf[10];
float f = 3.3;
memset(buf, 'x', f);
The third argument to memset is supposed to be an integer (actually a value of type size_t) telling memset how many characters of buf to set to 'x'. But I passed a float value instead. What happens? Well, the compiler knows that the third argument is supposed to be an integer, so it automatically performs the appropriate conversion, and the code ends up setting the first three (three point zero) characters of buf to 'x'.
(Significantly, the way the compiler knew that the third argument of memset was supposed to be an integer was based on the prototype function declaration for memset which is part of the header <string.h>.)
Now, when you called
printf("value of variable f is: %d", f);
you might think the same thing happens. You passed a float, but %d expects an int, so an automatic conversion will happen, right?
Wrong. Let me say that again: Wrong.
The perhaps surprising fact is, printf is different. printf is special. The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be, because it depends on the details of the %-specifiers buried in the format string. So there are no automatic conversions to just the right type. It's your job to make sure that the types of the arguments you actually pass are exactly right for the format specifiers. If they don't match, the compiler does not automatically perform corresponding conversions. If they don't match, what happens is that you get crazy, wrong results.
(What does the prototype function declaration for printf look like? It literally looks like this: extern int printf(const char *, ...);. Those three dots ... indicate a variable-length argument list or "varargs", they tell the compiler it can't know how many more arguments there are, or what their types are supposed to be. So the compiler performs a few basic conversions -- such as upconverting types char and short int to int, and float to double -- and leaves it at that.)
I said "The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be", but these days, good compilers go the extra mile and try to figure it out anyway, if they can. They still won't perform automatic conversions (they're not really allowed to, by the rules of the language), but they can at least warn you. For example, I tried your code under two different compilers. Both said something along the lines of warning: format specifies type 'int' but the argument has type 'float'. If your compiler isn't giving you warnings like these, I encourage you to find out if those warnings can be enabled, or consider switching to a better compiler.
Try
printf("... %f",f);
That's how you print float numbers.
Maybe you only want to print x digits of f, eg.:
printf("... %.3f" f);
That will print your float number with 3 digits after the dot.
Please read through this list:
%c - Character
%d or %i - Signed decimal integer
%e - Scientific notation (mantissa/exponent) using e character
%E - Scientific notation (mantissa/exponent) using E character
%f - Decimal floating point
%g - Uses the shorter of %e or %f
%G - Uses the shorter of %E or %f
%o - Signed octal
%s - String of characters
%u - Unsigned decimal integer
%x - Unsigned hexadecimal integer
%X - Unsigned hexadecimal integer (capital letters)
%p - Pointer address
%n - Nothing printed
The code is printing a 0, because you are using the format tag %d, which represents Signed decimal integer (http://devdocs.io).
Could you please try
void main() {
clrscr();
float f=3.3;
/* In printf() I intentionaly put %d format specifier to see what type of output I may get */
printf("value of variable a is: %f",f);
getch();
}

Difference b/w getting an address of variable using %p and %d

Here is an example
#include <stdio.h>
int main()
{
int a;
printf("%d\n",&a);
printf("%p\n",&a);
return 0;
}
======Output=======
-2054871028
0x7ffd8585280c
Do these two address point to same address in RAM ?
And how can i get the value by using each one of them, especially the second one.
%d format specifier is used to output a signed decimal integer.
From C Standard#7.21.6.1p8
d,i
The int argument is converted to signed decimal in the style [-]dddd. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it is expanded with leading zeros. The default precision is 1. The result of converting a zero value with a precision of zero is no characters.
%p prints the pointer.
From C Standard#7.21.6.1p8
p
The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner. [emphasis mine]
This statement
printf("%d\n",&a);
lead to undefined behavior because %d is not valid for printing a pointer.
From C Standard#7.21.6.1p9
If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
When you take the address of the variable a by writing &a, what you're really doing is generating a pointer to a.
%p is designed for printing pointers. You should use %p to print pointers.
%d is not designed for printing pointers. It tries to print their values as signed decimal, which can be confusing (as you've seen), and it may not print the entire value, on a machine where pointers are bigger than integers. (For example, if you try to print pointers with %d in most "64 bit" environments, you can get even stranger results -- and that might be part of what happened here.)
This is an easy mistake to make. Good compilers should warn you about it. Mine says "warning: format specifies type 'int' but the argument has type 'int *'".
But yes, both 0x7ffd8585280c and -2054871028 do "point to the same address in RAM", because they're both the same number, the same address. (Well, they're trying to be the same address. See footnote below.)
I'm not sure what you mean by "And how can I get the value". Are you trying to get the value of the pointer, or the value of what the pointer points to?
You've already got the value of the pointer -- it's the address 0x7ffd8585280c. And since we know it points to the variable a, we know the value it points to, too. Things will be a bit more clear if we do it like this:
int a = 5;
int *ip = &a;
printf("value of pointer: %p\n", ip);
printf("pointed-to value: %d\n", *ip);
Without the explicit pointer variable ip, we could write
int a = 5;
printf("value of pointer: %p\n", &a);
printf("pointed-to value: %d\n", *&a);
But that's pretty silly, because the last line is equivalent to the much more straightforward
printf("pointed-to value: %d\n", a);
(Taking the address of a variable with & and then grabbing the contents of the pointer using * is a no-op: it's a lot like like writing a + 1 - 1.)
Footnote: I said that 0x7ffd8585280c and -2054871028 were the same number, but they're not, they're just trying to be. 0x7ffd8585280c is really -140748133160948, and -2054871028 is really 0x8585280c, which is the lower-order 8 digits of 0x7ffd8585280c. It looks like %p on your machine is printing pointers as 48-bit values by default. I was about to be surprised by that, but then I realized my Mac does the same thing. Somehow I'd never noticed that.

Why does %d,and %p give different values? [duplicate]

This question already has answers here:
What happens when I use the wrong format specifier?
(2 answers)
Correct format specifier to print pointer or address?
(5 answers)
Closed 4 years ago.
As you can see in the program, The first output is 6356744 and the second output is 0060FF08, why is it different? Is the %d typecasting it into an integer, if so, how?
#include<stdio.h>
int main()
{
int *a;
int b = 7;
a = &b;
printf(" The value of a = %d",a);
printf("\n The value of a= %p",a);
}
Printing a pointer with %d is formally undefined behavior, meaning anything can happen, including a program crash. Your program will for example likely break when you compile it as a 64 bit application, where int is 32 bits but a pointer is likely 64 bits. Therefore, always use %p and never anything else when printing a pointer.
There is no implicit conversion taking place - the printf family of functions doesn't have that kind of intelligence - it doesn't know the type passed. With the format specifier, you tell the function which type it is getting. And if you lie to printf and say "I'll give you an int" and then give it a pointer, you unleash bugs. This makes the printf family of functions very dangerous in general.
(The only implicit conversion that take place in printf is when you pass small integer types or float, in which case the "default argument promotions" take place and promote the parameter either to int or double. This is not the case here, however.)
In this specific case, you happened to get the decimal representation of 0x0060FF08, which is by no means guaranteed.
Pedantically, you should also cast the pointer to type (void*) since this is what %p expects.
%p prints a pointer and it's not necessarily hexadecimal, or even a number
If format specifiers do not match the datatype of the provided parameter, you yield undefined behaviour. %d expects an integral value, such that when you pass a pointer value, you get undefined behaviour (cf., for example, cppreference.com-printf):
...If any argument after default argument promotions is not the type
expected by the corresponding conversion specifier, or if there are
fewer arguments than required by format, the behavior is undefined.
The (only) correct format specifier for printing pointer values is %p, usually printing the address in hex format.
One of the undefined behaviours is that %d takes the pointer value as an 32/64 bit integral value and hence prints decimals, which - if you printed it using the correct %p-format - corresponds to the hex-value of the address (yet in decimal format).
%d prints an int, in decimal.
%p prints a pointer (strictly speaking, a void * pointer) in an implementation-defined way, typically in hexadecimal.
On a machine where ints and pointers have different sizes, trying to print a pointer using %d will typically give a meaningless result. For example, on a lot of machines these days, ints are 32 bits while pointers are 64 bits. So if you try to print a pointer using %d, what you might get is half the pointer value, in decimal.
(Strictly speaking, trying to print a pointer using %d is undefined, no matter what the relative sizes are.)
Bottom line, use the right printf specifier for the job. Use %d to print ints. Use %p to print pointers. Don't try to mix 'n' match.

How can a variable have two different addresses at same point of time? [duplicate]

This question already has answers here:
How to printf a memory address in C
(2 answers)
Closed 5 years ago.
I tried to play around a little bit with pointer for some assigned value of 'i' and what I found out in in that there are two different addresses assigned for declaration %u and %lu,%llu. How is possible that a variable can have two different addresses at the same instance of execution -
#include <stdio.h>
int main(void)
{
int i;
float f;
printf("\nEnter an integer:\t");
scanf("%d",&i);
printf("\nValue of address of i=%u",&i);
printf("\nvalue of address of i=%d",&i);
printf("\nValue of address of i=%lu",&i);
printf("\nValue of address of i=%llu",&i);
printf("\nvalue of i=%d",i);
printf("\nvalue of i=%u",i);
printf("\nvalue of i=%lu",i);
printf("\nvalue of i=%llu\n",i);
}
This is the output -
aalpanigrahi#aalpanigrahi-HP-Pavilion-g4-Notebook-PC:~/Desktop/Daily programs/pointers$ ./pointer001
Enter an integer: 12
Value of address of i=1193639268
value of address of i=1193639268
Value of address of i=140725797092708
Value of address of i=140725797092708
value of i=12
value of i=12
value of i=12
value of i=12
Here we can clearly see that for %u and %d the address is 1193639268 (Though the output of %d and %u might not be equal in all cases) and the output of %lu and %llu is 140725797092708 and what is it's physical significance.
The proper format specifier for printing a pointer is %p.
Using the wrong format specifier, such as %d, %u, %lu, or %llu invokes undefined behavior.
As the the specific behavior you're seeing, a pointer on your particular implementation is probably an 8 byte value, while an int or unsigned int is probably a 4 byte value. As a result, using %d or %u only reads the first 4 bytes of the 8 byte value passed in to the function and prints that value. When you then use %lu or %llu, all 8 bytes are read and printed as such.
Again, because you're invoking undefined behavior, you can't depend on this particular output to be consistent. For example, compiling in 32-bit mode vs 64-bit mode will likely give different results. Best to use %p, and also to cast the pointer to void *, as that is the specific pointer type expected by %p.
There is only one address. You're using integer printing codes of varying widths, so sometimes you see 32 bits of address, and sometimes you see 64 bits of address. How much is valid depends on your system; on a 32 bit system, printing 64 bits means 32 bits of the value are garbage; on a 64 bit system, printing 32 bits means you're omitting half the pointer.
There is a dedicated format code, %p that's intended for printing pointers, use that, not integer printing codes.
You're using the wrong format specifier, which results in undefined behavior. In this specific case the behavior is that 1193639268 (0x47257D64) is the lower part of 140725797092708 (0x7FFD47257D64)
The correct format specifier for addresses is %p
It doesn't. It's just that you are using incorrect format specifiers for pointer types.
The behaviour on doing that is undefined. The output you observe is a manifestation of that undefined behaviour.
Use %p for a pointer, and cast the pointer argument to a const void* type (many compilers are lax on this last point but it's good practice nonetheless).

Resources