Whenever you declare a type pointer-to-pointer-to type
you require two allocations before you can make use of any of the pointer-to type
referenced through the pointer-to-pointer-to type
(or at minimum one allocation of pointers and then an assignment of an existing object to each of the allocated pointers).
Take for example your declaration of:
sp_tuples_node **tuplepointer;
(presuming std_tuples_node
is not some typedeffed pointer)
What you need to do is:
- first allocate some number of pointers. Why? You have a pointer-to-pointer. That is a single-pointer holding the address of a pointer-to
type
. If you want reference 50
of the type object referred to, you must allocate 50
pointers so that tuplepointer
points to a block of memory that contains 50
pointers to type sp_tuples_node
.
For example:
tuplepointer = malloc (50 * sizeof *tuplepointer); /* allocate 50 pointers */
if (!tuplepointer) { /* validate allocation */
perror ("malloc-tuplepointer");
exit (EXIT_FAILURE);
}
- second, you can allocate storage for each
sp_tuples_node
and assign the starting address for each block allocated to one of the 50
pointers in the block of memory you have allocated and assigned to tuplepointer
above.
For example:
for (size_t i = 0; i < 50; i++) {
tuplepointer[i] = malloc (sizeof *tuplepointer[i]);
if (!tuplepointer[i]) {
perror ("malloc-tuplepointer[i]");
exit (EXIT_FAILURE);
}
}
(note: if you always use the dereferenced pointer to set the typesize for the type you are allocating -- you will never get your typesize wrong)
Now you have allocated storage for 50
pointers and assigned the starting address to tuplepointer
. You have also allocates storage for 50 - sp_tuples_node
and you have assigned the starting address for each to one of the 50
pointers in the block assigned to tuplepointer
. You can reference each sp_tuples_node
using array-index notation as tuplepointer[i]
.
If sp_tuples_node
contains yet another pointer to some type as a member of the struct you can now allocate a block of storage and assign the starting address to that pointer. Say you have char *str;
as a member of sp_tuples_node
. You can then allocate:
size_t len = strlen(somestring);
tuplepointer[i]->str = malloc (len + 1); /* allocate storage for str, assign to ptr */
/* validate allocation ... */
memcpy (typlepointer[i]->str, somestring, len + 1);
And so on and so forth... You can do this as many times as needed. The only thing you need to keep straight is whether you are allocating pointers, or allocating storage for an object. Obviously with a pointer-to-pointer-to type
you are allocating pointers, when you derefernce once and need to allocate for pointer-to type
you are allocating storage for an object.
How do you keep it straight?
Think of it this way. When you derefernce the type you are allocating for -- what do you have?
- with a pointer-to-pointer-to
type
, when dereferenced you have pointer-to type
(you are allocating pointers)
- with a pointer-to
type
, when dereferenced you have type
(you are allocating for an object)
Lastly, you mention linked-list in your question and you mention addNode(**head, etc)
. That is different. You likely have in that case in the caller (say main()
)
node *head;
and you are then calling:
addNode (&head, etc);
There the parameter type is pointer-to-pointer-to head
because you are passing the address of the original pointer back in main()
. head
itself already has a valid address, so you do not allocate for head
itself.
You pass &head
so the function addNode
receives the address of the original pointer instead of a copy-of the pointer. That way if you need to allocate storage for the node referenced through head
you can allocate *head = malloc (sizeof **head);
and upon function return head
will point to the new block of memory allocated in addNode()
without having to return and assign the starting address for the newly allocated block of memory.
Let me know if that helps clear it up. If not, I'm happy to try again.