Paul
Paul

Reputation: 275

C Confusion about pointer to pointers memory allocation?

I apologize if this might be viewed as a duplicate, but I cannot seem to find a conclusive answer that satisfies my question. So I have a struct with a self referential pointer to pointers.

struct Node {
    int id;
    int edge_count;
    struct Node **edges;
}

static struct Node s_graph[MAX_ID+1];

I then have a function that allocates some memory.

int add_edge(int tail, int head)
{
    struct Node *ptail, *phead;
    ptail = &s_graph[tail];
    phead = &s_graph[head];

    ptail->edges = realloc(ptail->edges, ++ptail->edge_count * sizeof(struct Node *));
    if (ptail->edges) {
       *(ptail->edges + ptail->edge_count - 1) = phead;
       return 0;   
   }
   return -1;
}

The above seems to work just fine. However, I keep seeing posts about pointer to pointers that lead me to wonder if I need to do something like the following in add_edge:

struct Node *phead = malloc(sizeof(struct Node *));

However, this does not seem logical. There should be enough memory for ptail->edges to store this pointer after the realloc call. I am fairly confident that I did the allocation correctly (albeit, inefficiently), but it is kind of sending me on a mind trip ... So when people declare pointer to pointers (e.g., **ptr) and then allocate memory for both ptr and *ptr, wouldn't that technically make ptr a pointer to pointers to pointers (and maybe clearer to declare as ***ptr)? Or maybe I am wrong and missing something conceptually?

Thank you in advance!

Upvotes: 0

Views: 70

Answers (1)

Jack
Jack

Reputation: 133557

It depends on the situation, there is no general answer. If you have a pointer to pointer, eg Node**, and you want to store new data into it, then you need to have two levels of allocations, otherwise one is enough.

struct Node** nodes = calloc(AMOUNT, sizeof(struct Node*));

Now you have an array of struct Node* elements, so each element is a pointer to a struct Node.

Now how do you fill this array? You could want to insert new nodes inside it. Then you wouold require to allocate them, eg

nodes[0] = calloc(1, sizeof(struct Node)); // <- mind Node, not Node*

But in your situation you just want to set the address to an element of an array of the static variable s_graph, so you don't need to allocate a second level, you directly set the value.

So:

struct Node** nodes = calloc(AMOUNT, sizeof(struct Node*));

nodes -> |   0   |   1   |   2   |   3   |

nodes[0] = calloc(1, sizeof(struct Node))

nodes -> |   0   |   1   |   2   |   3   |
             |
             |
             v
         |    NODE    |

But if you have s_graph you already have them allocated, so it's something like:

static struct Node s_graph[MAX_ID+1];
struct Node** nodes = calloc(AMOUNT, sizeof(struct Node*));

nodes -> |   0   |   1   |   2   |   3   |
s_graph -> |      N1      |      N2      |      N3      | 

nodes[0] = &s_graph[0];

nodes -> |   0   |   1   |   2   |   3   |
             |
             |----|
                  v
s_graph -> |      N1      |      N2      |      N3      | 

Upvotes: 2

Related Questions