简体   繁体   中英

pointer to pointer for struct

I have the following code

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    int age;
} data;

int storage (data **str) {
    *str = malloc(4 * sizeof(**str));
    (*str)[0].age = 12;
    return 0;
}

int main() {
    data *variable = NULL;
    storage(&variable);
    return 0;
}

I took it from a website source. I think I have a misunderstanding about a basic pointer to pointer concept because here in this code, we have a pointer to a struct, variable , and we are passing this to storage function, which expects pointer to pointer of struct type. After memory was malloced, I don't understand this assignment

(*str)[0].age = 12

It was assigned as if, str was of (*)[] type. I dont understand how this assignment works, like str is now a pointer to an array of structs?

It can be illustrated like this

main:
 data* variable = NULL;   //variable is a pointer
 storage(&variable)       //the address of the pointer is &variable 

the storage(data**) allows the function to take the address of the pointer variable

this allows storage to change what variable points to

In storage , the following statement changes what variable points to by dereferencing (since we did pass the address of variable ):

*str = malloc(4 * sizeof(**str) )

The malloc allocates a memory block containing four structs (which each has the size sizeof(struct data) bytes)

A struct is just a convenient way to access a part of memory, the struct describes the layout of the memory. The statement

(*str)[0].age = 12;

is the equivalent of

data* d = *str; 
d[0].age = 12;

or you can write it as a ptr with offset:

data* d = *str;
*(d + 0).age = 12;

edit: a clarification about malloc

malloc returns a block of memory allocated in bytes, the return type of malloc is void* so per definition it has no type and can be assigned to a pointer of arbitrary type:

T* ptr = malloc(n * sizeof(T));

After the assignment to ptr, the memory is treated as one or more elements of type T by using the pointer T*

First, a note about C syntax for dereferencing pointers:

a[b] is equivalent to *(a + b) , is equivalent to *(b + a) , is equivalent to b[a] .

Now, in

int main() {
    data *variable = NULL;
    storage(&variable);
    return 0;
}

variable is of type "pointer to data ", therefore its address &variable is of type "pointer to pointer to data ". This is passed to int storage(data **str) , and is the correct type for the argument str .

int storage (data **str) {
    *str = malloc(4 * sizeof(**str));
    (*str)[0].age = 12;
    return 0;
}

Here, str is dereferenced, yielding an lvalue of type data * designating the same object as main() s variable . Since it is an lvalue, it can be assigned to.

malloc() allocates memory without declared type, large enough (and sufficiently aligned) to contain four contiguous objects of type data . It returns a pointer to the beginning of the allocation.

(*str)[0] is now an lvalue designating an object of type data , and by accessing the memory malloc() allocated through this expression, the effective type of the memory becomes data . (*str)[0].age = 12; assigns the value 12 to the age -member of this object, leaving the other members of the struct (and the rest of the allocated memory) uninitialized.

Well, I think your code is simply identical to:

#include <stdlib.h>
#include <stdio.h>

typedef struct
{
    int age;
} data;

int main()
{
    data *variable = NULL;
    variable = malloc(4 * sizeof(*variable));
    *(variable + 0).age = 12;
    return 0;
}

So variable is malloced with a block of memory, which is large enough to hold 4 data s(from variable[0] to variable[3] ). That's all.

This piece of code might help illustrate what's happening, the really interesting line is

assert(sizeof(**str2) == sizeof(data));

Your numbers may vary form mine but first lets create a struct with a rather dull but hard to fake size for testing purposes.

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct {
  uint8_t  age;
  uint8_t  here_as_illustartion_only[1728];
} data;

int main() {
    data    str; 
    data *  str1 = &str;  
    data ** str2 = &str1;  
    printf("sizeof(str)    =%*zu\n", 5, sizeof(str));
    printf("sizeof(str1)   =%*zu\n", 5, sizeof(str1));
    printf("sizeof(str2)   =%*zu\n", 5, sizeof(str2));
    printf("sizeof(*str2)  =%*zu\n", 5, sizeof(*str2));
    printf("sizeof(**str2) =%*zu\n", 5, sizeof(**str2));

    assert(sizeof(**str2) == sizeof(data));
    return 0;
}

On my machine this prints the following

sizeof(str)    = 1729
sizeof(str1)   =    8
sizeof(str2)   =    8
sizeof(*str2)  =    8
sizeof(**str2) = 1729

Note the size of the pointer to pointer ie is the dull number we're looking for. 是我们正在寻找的枯燥数字。

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