Reputation: 164
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?
Upvotes: 4
Views: 178
Reputation: 36082
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*
Upvotes: 2
Reputation:
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.
Upvotes: 2
Reputation: 11638
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 sizeof(**) is the dull number we're looking for.
Upvotes: 0
Reputation: 16107
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.
Upvotes: 0