简体   繁体   中英

C memory allocation for struct with malloc

I am trying to understand the memory allocation in C for struct but I am stuck on it.

struct Person {
    char *name;
    int age;
    int height;
    int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->age = age;
    who->height = height;
    who->weight = weight;
    who->name = strdup(name);

    return who;
}
int main(int argc, char *argv[])
{
    struct Person *joe = Person_create("ABC", 10, 170, 60);
    printf("Size of joe: %d\n", sizeof(*joe));
    printf("1. Address of joe \t= %x\n", joe);
    printf("2. Address of Age \t= %x\n", &joe->age);
    printf("3. Address of Height \t= %x\n", &joe->height);
    printf("4. Address of Weight \t= %x\n", &joe->weight);
    printf("5. Address of name \t= %x\n", joe->name);
...

What I don't understand is the memory allocation for this struct. On my printout I see this:

Size of joe: 24
1. Address of joe   = 602010
2. Address of Age   = 602018
3. Address of Height    = 60201c
4. Address of Weight    = 602020
5. Address of name  = 602030

Questions:

  • Why there is a gap between the 1 and 2?
  • Why there is a gap between the 4 and 5?
  • How is the size of *name being calculated as the name points only to first char?

There is no gap between the address of the object joe and the address of data member age . This extent is occupied by data member name .

struct Person {
    char *name;
    int age;
    //...

According to the output

1. Address of joe   = 602010
2. Address of Age   = 602018

it occupies 8 bytes that is sizeof( char * ) in your platform is equal to 8. And its address coincides with the address of the object joe itself.

In this statement

printf("5. Address of name \t= %x\n", joe->name);

you did not output the address of name itself. You printed the value stored in this pointer and this value is the address of the first character of a copy of the string literal "ABC" that was gotten by using strdup .

So there is a gap between values in the outputs 4 and 5 because they are different extents of memory. Data member weight belongs to object joe while the copy of the string literal "ABC" is stored outside the object. The object just has data member name that points to the first character of the copy of the literal.

As name is a pointer then its size is calculated like

sizeof( char * )

or

sizeof( joe->name )

and equal to 8 as I explained in the beginning of the post.

If you want to determine the length of the string literal you should use standard function strlen declared in header <string.h> . For example

printf( "%zu\n", strlen( joe->name ) );

Why there is a gap between the 1 and 2?

A struct's start address is always equal to the address of it's first member. From the C standard:

6.7.2.1-13. A pointer to a structure object, suitably converted, points to its initial member

The first member is not age , but name . So the following two lines should print the same address:

printf("1. Address of joe \t= %x\n", joe);
printf("1. Address of name-pointer \t= %x\n", &joe->name);

In your code,

printf("5. Address of name \t= %x\n", joe->name);

does not print the address of the pointer, but the address of the data the pointer points to.

How the size of *name is being calculated as the name points only to first char?

name is a pointer, which occupies 8 bytes of memory regardless of the size of data it points to (that may be a string as in your case, a single char, an int or whatever).

Why there is a gap between the 4 and 5?

The memory for storing the actual name string is not within the struct - strdup allocates memory somewhere to duplicate the string into. This happens to be 16 bytes after the last member of your struct. This memory location is then pointed to by your name pointer.

Note that padding and memory alignment are a factor only for the size of the struct (they do not matter for your explicitly stated questions). Since the struct contains one pointer (8 bytes on your machine) and 3 integers (4 bytes each), one would assume that the total size is 20 bytes. On most platforms, memory is 8 byte aligned - which is why the size of your struct is rounded up to 24 bytes. This way, if you declare an array of Person s, each array element starts at an address that is 8 byte aligned, ie, the address value can be divided evenly by 8.

The only things the c standard guarantees is that the address of the first member is the same as the address of the structure, and that the addresses of subsequent members increases with their position in the structure.

Compilers are allowed to insert spaces between members; this is called padding. Regard it as the compiler optimising the structure for a particular platform.

Arrays must always be contiguous in memory though.

It is due to something called Data alignment . To quote from this website

Every data type in C/C++ will have alignment requirement (in fact it is mandated by processor architecture, not by language).

And then extending this requirement for structures:

Because of the alignment requirements of various data types, every member of structure should be naturally aligned.

You can go through this article for a detailed read..

The memory layout of the struct is machine dependent, so you should not bother with that unless you are trying to implement a DBMS or a device driver or something like that.

sizeof(*name) would equal to sizeof(char) , I do not get what confused you here, can you give further explanation?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM