问题
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
struct node
{
int id;
struct node *next;
};
typedef struct node NODE;
int main()
{
NODE *hi;
printf("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
return 0;
}
The output is:
before malloc
address of node is: 0x7ffd37e99e90 address of next is: 0x7ffd37e9a470
Why both are not same?
回答1:
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 calledi
and assign the value10
to it. Here, the computer allocates memory for this variable on the stack. Say, at address0x1000
. So now, address0x1000
has content10
. - Then you declare a pointer called
ip
, having typeint
. 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 variablei
to variableip
. Now the value of variableip
(your pointer) is the address ofi
.ip
doesn't hold the value10
-i
does. Think of this assignment asip = 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 ofi
, which is10
. 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("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
- Declare a pointer to
NODE
calledhi
. Lets imagine this variablehi
has address0x1000
, 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 yourprintf
you're printing the contents of that address0x1000
... 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 variablenext
. 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\n", &hi);
printf(" hi: %p\n", 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\n", &hi);
printf("Contents of hi : %p\n", hi);
printf("Address of next(&next): %p\n", &(hi->next));
printf("Contents of next : %p\n", hi->next);
printf("Address of id : %p\n", &(hi->id));
printf("Contents of id : %d\n", 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 fromid
, when it should be only 4(after allint
s are only 4 bytes long) - this is due to memory alignment. - The contents of
next
is the same block pointed byhi
. - The amount of memory "alloced" for the
hi
pointer itself is 8 bytes, as I'm working on a64bit
. That's all the room it has and needs. - Always
free
after amalloc
. 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
- SO: How Undefined is Undefined Behavior
- SO: Do I cast the result of malloc
- SO: What and where are the stack and heap?
- Pointer Basics
- Pointer Arithmetic
- C - Memory Management
- Memory: Stack vs Heap
- Memory Management
- The Lost Art of C Strucutre Packing will tell you about structures, alignment, packing, etc...
回答2:
You have no malloc here. hi pointer points to something undefined. hi->next the same.
About the question. Why they should be?
I think you do not understand pointers.
回答3:
because next is a pointer type and it is pointing to 0x7ffd37e9a470. if you print the address if next &(hi->next), you can see both hi and hi->next has a difference of 2 (because of int id is the first element).
来源:https://stackoverflow.com/questions/32780459/why-the-address-of-structure-and-next-is-not-same