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: