I am a first year student in C programming so my skill/knowledge is limited. I am trying to create my own implementation on printf, but I am having trouble with retrieving and printing the address of a variable. With printf, its possible to output the address of a variable with %p, i need to replicate %p somehow.
When storing the address of a variable, the data type is int*, and I cannot figure out how to write this address to the screen(stdout).
For Example:
int i = 123;
int *address = &i;
Now how would I output address(not the value at i)? I have tried using the original printf format specifiers for testing purposes. I tried using %x, %s, %d, %lu... it all gives me an error as I am trying to output an int*(integer pointer).
Can anyone assist me in outputting the address?
You can only inspect the bits of the pointer and print those, using the type unsigned char:
unsigned char* a = ( unsigned char* )address;
for( size_t i = 0 ; i < sizeof( address ) ; i++ )
printf( "%hhu" , a[i] );
Another option, if the pointer is a pointer to an object, is to cast the pointer to types: intptr_t or uintptr_t, but the availability of those types is implementation defined.
If it's for the address of an object you could do the following:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
int a;
uintptr_t uip = (uintptr_t) ((void*) &a);
printf("address of a = 0x%"PRIXPTR, uip);
}
To print the address of a function you need to go as proposed here.
Related
#include<stdio.h>
int main(){
int a = 3;
printf("%u\n",&a);
printf("%d\n",&a);
return 0;
}
I was trying to print address of Variable, "a". Now with usage of two different format specifier, "%u" and "%d", two different memory address is printed which I find it wierd.
So My Question is what difference between two format specifier?
Using the both conversion specifiers to output an address invokes undefined behavior.
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
Instead you should use the conversion specifier p as for example
printf( "%p\n", ( void * )&a );
Another approach is to use integer types intptr_t or uintptr_t declared in the header <stdint.h> and to use specifiers PRIdPTR or PRIuPTR or, for example, PRIxPTR declared in the header <inttypes.h> to output assigned values of pointers of the type void *.
Here is a demonstration program.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main( void )
{
int a = 3;
intptr_t p1 = ( intptr_t )( void * )&a;
uintptr_t p2 = ( uintptr_t )( void * )&a;
printf( "&a = %p\n", ( void * )&a );
printf( "&a = %"PRIdPTR "\n", p1 );
printf( "&a = %"PRIuPTR "\n", p2 );
printf( "&a = %#"PRIxPTR "\n", p2 );
}
The program output is
&a = 0x7ffc220b16ec
&a = 140720879638252
&a = 140720879638252
&a = 0x7ffc220b16ec
%d is for signed integers, %u is for unsigned integers.
So, when you print the same value out with %d and with %u, you may get different values, since the bytes you're printing out are being interpreted differently. (Once as a signed integer, once as an unsigned integer.)
Final note, you should use %p ("p" for "pointer") to print out addresses.
Well of course "%u\n" has different address than "%d\n" because these are different values created one after another. Look at ASM:
RDX register will have the same value for both printf calls because of LEA instruction is putting the same address into it.
But what you probably see are the values of RCX register which contains different printf format value address for each printf call.
Now the answer:
%d is signed decimal integer.
%u is unsigned decimal integer.
The problem occurs when there is a printf call. This function changes the value of RDX register which is the memory address of a variable.
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.
I have started learning C (so, you know.. pointers).
I have this code:
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char c = 'c';
char* cptr = &c;
printf("c = %c\n", c);
printf("*cptr = %c\n", *cptr);
printf("c address = %p\n", &c);
}
My output is:
c = c
*cptr = c
c address = 0x7fff0217096f
When I convert the hexadecimal above to decimal, I get: 140720994002157
My questions:
1) Does this decimal value represent the memory address? Isn't it too big?
2) How can I print the value of the pointer (which means the address of the c variable) as a decimal?
Isn't [the address] too big?
This is a virtual address, meaning that its numerical value does not necessarily represent the sequential number of the byte in physical memory. Moreover, different processes may keep different data at the same virtual address, because each one has its individual address space.
How can I print the value of the pointer in an integer format?
Use uintptr_t to represent the pointer as an integer value, then print using PRIuPTR macro:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
char c = 'x';
char *p = &c;
uintptr_t x = (uintptr_t)p;
printf("Pointer as decimal: %"PRIuPTR"\n", x);
return 0;
}
Demo.
1). You should print the address as printf("c address = %p\n", &c);. Now you attempt to print the address where the pointer variable itself is stored, which probably doesn't make much sense.
That being said, it might still be a valid address, assuming 64 bit addresses.
2). You will have to safely convert it to an integer which is guaranteed to be large enough to contain a pointer address:
#include <inttypes.h>
printf("c address = %" PRIuPTR "\n", (uintptr_t)&c);
#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.
In this code to print the value of int and char pointer variables, why do I access them differently? For the char pointer I write sampleclient but for the int I write *intid. Why does one use * but not the other?
int main()
{
char client[] = "ABCD";
int intid = 10;
samplepass(&client, &intid);
return 0;
}
void samplepass(char *sampleclient, int *intid)
{
printf("%s %d\n", sampleclient, *intid);
}
This is because %s format specifier expects a char pointer, while %d expects an integer argument. If you want to see the value of the pointers themselves(i.e. the address they point to) use %p.
In C, you can't pass a string (character array) to a function like printf, so you do the next best thing: pass it its address in memory. The function can then treat the memory address like an array using pointer arithmetic. So the way printf reads strings is by taking in a pointer to the string. Then %s displays the dereferenced string (ABCD here), not the pointer address (which you could get by using %p instead of %s).
The integer problem is more straightforward: the * in *intid means 'get the value stored at this address'. That's why it prints out 10, not the memory address.
The 'correct' format specifier to get a memory address is %p. But you could write:
int main()
{
char client[] = "ABCD";
int intid = 10;
samplepass(&client, &intid);
return 0;
}
void samplepass(char *sampleclient, int *intid)
{
printf("%d %d\n", sampleclient, intid);
}
On my machine, the output was
-2140958000 -2140958004
(and those are the addresses in memory of client and intid). Substituting %p for %d gives nicely formatted pointers with a 0x in front and conforms to the standard, so I'd use that.
For an output that looks like:
ABCD 10
change your line
from samplepass(&client,&intid);
to samplepass(client,&intid);