So I was learning and practicing the concept of Pointers and addresses of variables in C language. But there is one thing that is making me curious. The code that I ran is-
#include <stdio.h>
int main()
{
int *p, n;
p = &n;
int *c = NULL;
printf("Address of variable = %p\n", p);
printf("Address of variable = %lu\n", p);
printf("Address of c variable = %lu\n", c);
return 0;
}
I am sure that this code is correct to print addresses and the output I got was-
pointer.c: In function ‘main’:
pointer.c:10:37: warning: format ‘%lu’ expects argument of type ‘long unsigned
int’, but argument 2 has type ‘int *’ [-Wformat=]
10 | printf("Address of variable = %lu\n", p);
| ~~^ ~
| | |
| | int *
| long unsigned int
| %ls
pointer.c:11:39: warning: format ‘%lu’ expects argument of type ‘long unsigned
int’, but argument 2 has type ‘int *’ [-Wformat=]
11 | printf("Address of c variable = %lu\n", c);
| ~~^ ~
| | |
| | int *
| long unsigned int
| %ls
Address of variable = 0x7fffc5a57474
Address of variable = 140736509342836
Address of c variable = 0
So, I was wondering that as to what do these compiler warnings mean, and should I be concerned about these warnings?
Also, when I used %d
instead of %p
or %lu
, I got the values of addresses as a "negative" value, so can negative addresses exist in the memory?
Also, the address values in the output are unusually large. They are even larger than the size of my 16 GB RAM, how is that possible that my variable is stored in a location which doesn't exist?
You have to be careful if you're thinking about pointers as numbers. Internally, they are usually addresses, and they are usually numeric, but they are unsigned numeric. So, no, you typically won't have "negative addresses".
You might not have learned how computers represent negative numbers. Here's a quick demonstration of the common " two's complement " representation, using only three bits. The point is that the same bit pattern can have two different interpretations, depending on whether you care about negative values or not:
bit pattern | signed int |
unsigned int |
---|---|---|
000 | 0 | 0 |
001 | 1 | 1 |
010 | 2 | 2 |
011 | 3 | 3 |
100 | -4 | 4 |
101 | -3 | 5 |
110 | -2 | 6 |
111 | -1 | 7 |
So, as you can see, if you have a large, unsigned number, but you interpret it as if it's signed (like, by printing it with %d
, you get a negative number, instead.
Two other things to remember are:
Your code is not correct.
The conversion specifier lu
expects its corresponding argument to have type unsigned long
and d
expects its corresponding argument to have type int
; p
and c
have type int *
, hence the warnings. And yes, these warnings matter - at the very least you're going to get garbled output, as you've discovered.
Pointer types are not integer types; they don't have to have the same size or representation as integer types (on x86_64, int
is 32 bits wide but pointer types are 64 bits wide). The only conversion specifier that is defined for pointer types is p
, and it expects its corresponding argument to have type void *
.
Your code should be written more like
printf( "p = %p\n", (void *) p );
printf( "c = %p\n", (void *) c );
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.