TL;DR
Your code provokes Undefined Behavior, as already mentioned in Morlacke's Answer. Other than that, it seems that you're having problems on understanding how pointers work. See references for tutorials.
First, From your comments
When you say that there's memory allocated for ip
in this case:
int i = 10;
int *ip;
ip = &i;
What happens is:
- You declare an
int
variable called i
and assign the value 10
to it. Here, the computer allocates memory for this variable on the stack. Say, at address 0x1000
. So now, address 0x1000
has content 10
.
- Then you declare a pointer called
ip
, having type int
. The computer allocates memory for the pointer. (This is important, see bellow for explanation). Your pointer is at address, say, 0x2000
.
- When you assign
ip = &i
, you're assigning the address of variable i
to variable ip
. Now the value of variable ip
(your pointer) is the address of i
. ip
doesn't hold the value 10
- i
does. Think of this assignment as ip = 0x1000
(don't actually write this code).
- To get the value
10
using your pointer you'd have to do *ip
- this is called dereferencing the pointer. When you do that, the computer will access the contents of the address held by the pointer, in this case, the computer will access the contents on the address of i
, which is 10
. Think of it as: get the contents of address 0x1000
.
Memory looks like this after that snippet of code:
VALUE : 10 | 0x1000 |
VARIABLE : i | ip |
ADDRESS : 0x1000 | 0x2000 |
Pointers
Pointers are a special type of variable in C. You can think of pointers as typed variables that hold addresses. The space your computer allocates on the stack for pointers depends on your architecture - on 32bit
machines, pointers will take 4 bytes; on 64bit
machines pointers will take 8 bytes. That's the only memory your computer allocates for your pointers (enough room to store an address).
However, pointers hold memory addresses, so you can make it point to some block of memory... Like memory blocks returned from malloc.
So, with this in mind, lets see your code:
NODE *hi;
printf("
before malloc
");
printf("
address of node is: %p",hi);
printf("
address of next is: %p",hi->next);
- Declare a pointer to
NODE
called hi
. Lets imagine this variable hi
has address 0x1000
, and the contents of that address are arbitrary - you didn't initialize it, so it can be anything from zeroes to a ThunderCat.
- Then, when you print
hi
in your printf
you're printing the contents of that address 0x1000
... But you don't know what's in there... It could be anything.
- Then you dereference the
hi
variable. You tell the computer: access the contents of the ThunderCat and print the value of variable next
. Now, I don't know if ThunderCats have variables inside of them, nor if they like to be accessed... so this is Undefined Behavior. And it's bad!
To fix that:
NODE *hi = malloc(sizeof NODE);
printf("&hi: %p
", &hi);
printf(" hi: %p
", hi);
Now you have a memory block of the size of your structure to hold some data. However, you still didn't initialize it, so accessing the contents of it is still undefined behavior.
To initialize it, you may do:
hi->id = 10;
hi->next = hi;
And now you may print anything you want. See this:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
typedef struct node NODE;
int main(void)
{
NODE *hi = malloc(sizeof(NODE));
if (!hi) return 0;
hi->id = 10;
hi->next = hi;
printf("Address of hi (&hi) : %p
", &hi);
printf("Contents of hi : %p
", hi);
printf("Address of next(&next): %p
", &(hi->next));
printf("Contents of next : %p
", hi->next);
printf("Address of id : %p
", &(hi->id));
printf("Contents of id : %d
", hi->id);
free(hi);
return 0;
}
And the output:
$ ./draft
Address of hi (&hi) : 0x7fffc463cb78
Contents of hi : 0x125b010
Address of next(&next): 0x125b018
Contents of next : 0x125b010
Address of id : 0x125b010
Contents of id : 10
The address of variable hi
is one, and the address to which it points to is another. There are several things to notice on this output:
hi
is on the stack. The block to which it points is on the heap.
- The address of
id
is the same as the memory block (that's because it's the first element of the structure).
- The address of
next
is 8 bytes from id
, when it should be only 4(after all int
s are only 4 bytes long) - this is due to memory alignment.
- The contents of
next
is the same block pointed by hi
.
- The amount of memory "alloced" for the
hi
pointer itself is 8 bytes, as I'm working on a 64bit
. That's all the room it has and needs.
- Always
free
after a malloc
. Avoid memory leaks
- Never write code like this for other purposes than learning.
Note: When I say "memory alloced for the pointer" I mean the space the computer separates for it on the stack when the declaration happens after the Stack Frame setup.
References