I'm trying to understand when I need to use malloc when using multiple levels of pointers. For example,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
typedef struct {
char first[10];
char last[10];
} Person;
Person *p;
p = malloc(sizeof(Person));
strcpy(p->first, "John");
strcpy(p->last, "Doe");
printf("First: %s Last:%s\n", p->first, p->last);
return 0;
}
In this first version I'm using Person *p
and I only use malloc
to allocation space for type Person
. In the 2nd version, I'll change Person *p
to Person **p
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
typedef struct {
char first[10];
char last[10];
} Person;
Person **p;
*p = malloc(sizeof(Person));
strcpy((*p)->first, "John");
strcpy((*p)->last, "Doe");
printf("First: %s Last:%s\n", (*p)->first, (*p)->last);
return 0;
}
I'm still using only one malloc
even though there is now another pointer.
In this third version, I'll use Person ***p
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
typedef struct {
char first[10];
char last[10];
} Person;
Person ***p;
*p = malloc(sizeof(void));
**p = malloc(sizeof(Person));
strcpy((**p)->first, "John");
strcpy((**p)->last, "Doe");
printf("First: %s Last:%s\n", (**p)->first, (**p)->last);
return 0;
}
My questions:
1) Why do I need to malloc
space for **p
in the 3rd version, but I don't need to malloc
space for *p
? They are both pointers to pointers?
2) Also, why don't I need to malloc
space for p
in either the 2nd or 3rd version?
3) In the third version, what is the right size to malloc
for *p
? On my 64 bit Mac the sizeof(void)
is 1, and the sizeof(void*)
is 8, and both seem to work but what is the right one?
Dereferencing a pointer (*p
) which had not been initialised provokes undefined behaviour in any case.
When allocating space to a pointer you mostly ever want to allocate to it memory with the size of what is it pointing to by typically using the sizeof
operator. This latter case is the one and only exception to 1. that allows coding *p
.
So the 3rd example could look like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char first[10];
char last[10];
} Person;
int main(void) {
Person ***p;
p = malloc(sizeof *p);
*p = malloc(sizeof **p);
**p = malloc(sizeof ***p);
strcpy((**p)->first, "John");
strcpy((**p)->last, "Doe");
printf("First: %s Last:%s\n", (**p)->first, (**p)->last);
free(**p);
free(*p);
free(p);
return 0;
}
I'm just going to put this here to summarize :
1) You do need to allocate space for *p
. If you run your second program with valgrind, you'll see an error for alloc size (1 instead of 8); *p
is a pointer to pointer, but **p
isn't, it's a pointer to a structure.
2) You do need to allocate space in both cases and if you turn on the warnings (which you should never turn off anyway), you'll get this warning :
warning: ‘p’ is used uninitialized in this function [-Wuninitialized] *p = malloc(sizeof(Person));
3) The right one is void*
. void*
is a pointer which means its size is enough to contain every memory address in your 64 bit computer. It could be smaller if your computer was using a 32bit system. Although it would be even better to use
malloc(sizeof(Person*));
instead of malloc(sizeof(void*));
Since you already know the type you're going to use. It doesn't change anything computer wise but makes the code clearer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With