malloc and pointers to pointers

Idr picture Idr · Dec 26, 2015 · Viewed 7.2k times · Source

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?

Answer

alk picture alk · Dec 26, 2015
  1. Dereferencing a pointer (*p) which had not been initialised provokes undefined behaviour in any case.

  2. 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;
}