Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
533 views
in Technique[技术] by (71.8m points)

c - Why the address of structure and next is not same?

#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("
before malloc
");
    printf("
address of node is: %p",hi);
    printf("
address 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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:

  1. 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.
  2. 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.
  3. 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).
  4. 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);
  1. 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.
  2. 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.
  3. 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:

  1. hi is on the stack. The block to which it points is on the heap.
  2. The address of id is the same as the memory block (that's because it's the first element of the structure).
  3. The address of next is 8 bytes from id, when it should be only 4(after all ints are only 4 bytes long) - this is due to memory alignment.
  4. The contents of next is the same block pointed by hi.
  5. 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.
  6. Always free after a malloc. Avoid memory leaks
  7. 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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...