0

I've already seen a lot of other questions, however I still can't seem to figure out how to initialize a pointer to a struct member that is also a pointer. Given my pointer to my struct (which contains a member that is a pointer) I want to initialize a pointer to that member pointer.

For example when adding a node to a linked list the parameter given in the examples which I have learned are addNode(**head, etc). I would like to know whether or not I need to allocate memory to this pointer and how to initialize it if I'm doing it wrong in the code below.

int row, col;
double val;
char nwln;

sp_tuples_node ** tuplepointer/* = malloc(sizeof(sp_tuples_node *));*/

FILE * inFile = fopen(input_file, "r");
sp_tuples * new_tuples = malloc(sizeof(sp_tuples));
tuplepointer = new_tuples->tuples_head;
fscanf(inFile, "%d %d%c", &row, &col, &nwln);

  //while not eof
  fscanf(inFile, "%d %d %d%c", &row, &col, &val, &nwln);
  addNode(tuplepointer, row, col, val);
  return new_tuples;

The line in question is separated by new lines the rest of the non completed code is there for context of calling the function and its functionality should be disregarded.

Thank you for any feedback regarding how to assign pointers to members that are pointers.

King_D1ce
  • 3
  • 1
  • What is `sp_tuples_node`? That sounds like Hungarian Notation for a `typedef` pointer-to-struct. I don't think it's a good idea to mix typedefs and multiple pointers in the same declaration (`sp_tuples_node** tuplepointer`) because it's unclear how much pointer-indirection is going on. – Dai Nov 14 '19 at 04:18
  • I'm seeing a lot of immediate use of invalid memory (`malloc` doesn't zero memory after allocation whereas, `calloc` does), for example `tuplepointer = new_tuples->tuples_head` right after `new_tuples = malloc(sizeof(sp_tuples))` - you shouldn't do that and a smart compiler will give you a warning. – Dai Nov 14 '19 at 04:20
  • I tried looking for a tag regarding a homework style format however I could not find one this is NOT the answer to the hw (just to clarify I'm not trying to get answers). I cannot change the dumb notation (I agree makes it really hard to read). Thank you for pointing out my error however I will add that to my fixes for this. For the pointer to the member in the Struct should I allocate memory for the entire separate type `(ex: tuplepointer = calloc(sizeof(tuple_node_struct)` – King_D1ce Nov 14 '19 at 04:28
  • or should I just initialize a pointer like `(tuple_node_struct ** tuplepointer;)` `tuplepointer = new_tuples->tuples_head` – King_D1ce Nov 14 '19 at 04:35
  • I can't help further without knowing your `struct` definitions.Please post your **full** code, including any header files, especially any `typedef` and `struct` statements. – Dai Nov 14 '19 at 05:16
  • 1
    Note that [`while (!feof(file))` is always wrong](https://stackoverflow.com/questions/5431941/). – Jonathan Leffler Nov 14 '19 at 05:45

1 Answers1

0

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.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Thank you very much for your detailed response, with the considerations you provided my code complied (although I may have to change the code entirely depending on if my functionality is correct). It is as you said in your last section I am trying to implement a program that interacts with some data and stores it as a linked list, I am attempting to implement my own add, rm, and find functions in order to manipulate the data easier. Not sure if it will work out this way but your explanations explained the topic to me in a very thorough way, even if I have to change it I learned a lot! – King_D1ce Nov 14 '19 at 06:56
  • Glad it helped. Good luck with your project. You may find [Singly Linked List (node only, no wrapper)](https://pastebin.com/5MPLU4wB) helpful for a plain linked-list example. Much greater insert efficiency can be obtained by keeping track of both the `head` and `tail` nodes eliminating the need to iterate to find the next point of insertion. You may find [Singly Linked List of Integers (example)](https://pastebin.com/R2AewR3A) instructive there `:)` – David C. Rankin Nov 14 '19 at 07:12