patterncModerate
Creating nodes for linked list in a while loop in C
Viewed 0 times
nodeswhilecreatingloopforlistlinked
Problem
I am trying to create nodes for a linked list in a while loop. The code works, but it is not very pretty. How would I get the same results the proper way?
root = malloc(sizeof(struct node)); // Allocates memory for first node
pointer = root; // Set pointer to first node
char buf[MAXBUF]; // Buffer for each line
int size = 1; // Counts nodes.
/* Write to list */
while(fgets(buf, MAXBUF, f) != NULL) // Puts each line in a node through buffer
{
strncpy(pointer->data, buf, MAXBUF); // Puts line in character array in node
pointer->next = malloc(sizeof(struct node)); // Allocates memory for new node
size++; // Increments for each node. Root is 1, so first round in loop is 2
pointer = pointer->next; // Sets pointer to next node
}
size--; // Removes 1 count for last node
free(pointer); // Frees last allocated node
pointer = NULL;Solution
The technique you're trying to accomplish in building your ordered linked list is called forward-chaining. A pointer-to-pointer makes the task trivial for building a simple linked list while retaining its input order. Error checking memory allocations not-withstanding, it is done something like this:
How It Works
The parts of this that mandate further elaboration follow this general algorithm:
So on to the code:
The above line declares the root pointer, initialized to NULL (optional, but I hate indeterminate pointers anywhere in-code), and a pointer-to-pointer that holds the address of
This allocates a new node, storing its address at whatever pointer is currently being addressed by the pointer-to-pointer
Addendum: Printing the list
Per request, printing the list after this is simply:
For C99 and later,
struct node *root = NULL, **pp = &root;
char buf[MAXBUF] = {0};
size_t size = 0;
while (fgets(buf, MAXBUF, f) != NULL)
{
*pp = calloc(1, sizeof(**pp));
strncpy((*pp)->data, buf, MAXBUF-1);
pp = &(*pp)->next;
++size;
}
*pp = NULL; // terminate the last nodeHow It Works
The parts of this that mandate further elaboration follow this general algorithm:
- Utilize a pointer-to-pointer to always hold the address of the pointer that will be populated with the address of the next node to add. The initial value of this pointer-to-pointer is the address of the
rootpointer:&root.
- Acquire a new node, storing its address in
*pp, whereppis the pointer-to-pointer from (1)
- Once the node is finished being configured, change the address stored in
ppto be the address of thenextmember pointer held within the node just added. This step sets up the target location where the next node will be added if needed.
- When finished processing input, the last-node-added's
nextmember pointer has its address currently held inpp. If no nodes were added to the list, thenppstill holds the address ofroot. To terminate the list, this pointer must be set to NULL.
So on to the code:
struct node *root = NULL, **pp = &rootThe above line declares the root pointer, initialized to NULL (optional, but I hate indeterminate pointers anywhere in-code), and a pointer-to-pointer that holds the address of
root. From there...*pp = malloc(sizeof(**pp));This allocates a new node, storing its address at whatever pointer is currently being addressed by the pointer-to-pointer
pp. On the initial pass that pointer is the root pointer. On subsequent passes it will always hold the address of the next member within the last-node-added on a prior iteration. But it always holds the address of pointer that is to receive the next new node.
After the current node is finished being configured copy, then this is done:
pp = &(*pp)->next;
This stores the address of the just-added-node's next member in the pointer-to-pointer. When we loop around for the next iteration, this is where we will hang the next new node. Finally, after the loop finishes, this is done:
*pp = NULL;
This sets the pointer pointed-to by pp to NULL. Now think about what pointer that is:
- If no items were populated in the list, then
pp still holds the address of root and this will reestablish root as NULL; exactly what you want if the list is empty.
- If any nodes were read, then
pp will hold the address of the last added-node's next` pointer, which should set to NULL to terminate the linked list. Again, exactly what this code does.Addendum: Printing the list
Per request, printing the list after this is simply:
struct node *ptr = root;
while (ptr)
{
printf("data: %s\n", ptr->data);
ptr = ptr->next;
}For C99 and later,
for (struct node *ptr = root; ptr; ptr = ptr->next)
printf("data: %s\n", ptr->data);Code Snippets
struct node *root = NULL, **pp = &root;
char buf[MAXBUF] = {0};
size_t size = 0;
while (fgets(buf, MAXBUF, f) != NULL)
{
*pp = calloc(1, sizeof(**pp));
strncpy((*pp)->data, buf, MAXBUF-1);
pp = &(*pp)->next;
++size;
}
*pp = NULL; // terminate the last nodestruct node *root = NULL, **pp = &root*pp = malloc(sizeof(**pp));pp = &(*pp)->next;*pp = NULL;Context
StackExchange Code Review Q#62753, answer score: 11
Revisions (0)
No revisions yet.