Loop through a node list - c

I'm fairly new to coding in c and have stumbled upon a problem. The code below is what I have so far and the problem at hand is how to looping through the node job_list.
We have two nodes, the first one creates a basic job post with a reference number (an integer) and job name (a string - an array of characters) as parameters, and the second is a list that holds job posts with the job_node being one parameter and then the second one being a standard struct job_list * next parameter.

I think you mixed few things up..
singly link list (that's what i understand you are up to) is not a fixed size data structure. it even not an increasing space data structure. link list use exactly the amount of memory you want to hold in it.
link list is a list of nodes. you can create list - and it will be an empty list.
then, you can add nodes with your desired data and every node you insert - create a new node (on the heap = dynamically allocated) which will contain your data and will be linked to the list.
every data node in the list will have a node_next it will point to, and node_prev which will point at this particular node(head and tail will not have this 2 nodes. head will point at node_next but will not have node_prev which point to it, and tail only have node_prev which will point to it).
so, if you want to create list you will have to dynamically allocate the space of the list which contain 2 nodes: head and tail(or end).
this is an example of create function:
slist_t *SlistCreate(void)
{
slist_t *list = malloc(sizeof(slist_t));
slist_iter_t dummy = NULL;
if(NULL == list)
{
return (NULL);
}
dummy = malloc(sizeof(node_t));
if(NULL == dummy)
{
free(list);
return (NULL);
}
dummy->next = NULL;
dummy->data = (void *)list;
list->head = dummy;
list->tail = dummy;
return (list);
}
then you will be able to insert nodes before particular node or after - that's depend on how you will implement this:
if you want to implement insert before:
you will have to encapsulate the list struct and prevent the user from sending your head to insert before.
or you can check every time if your insert function get the head of the list and update the head of the list (you can insert after and copy the head data to the head->next node and then use the head for the data the user wanted to be at the head of the list.
if you want to implement insert after:
you will have to check if the user sent you the tail (also called dummy_node cause it point to dummy_node->next = NULL), and use the same method i mentioned before, only the opposite way..
this is an example of insert before - in this example i used slist_iter_t which is pointer to node_t - the user isn't exposed to any of this structs (not to the list struct or the nodes struct):
slist_iter_t SlistInsert(slist_iter_t iterator, const void *data)
{
slist_t *ptr = NULL;
slist_iter_t dup = (slist_iter_t)malloc(sizeof(node_t));
if(NULL == dup)
{
return(NULL);
}
assert(NULL != iterator);
dup->data = iterator->data;
dup->next = iterator->next;
iterator->data = (void *)data;
iterator->next = dup;
if(NULL == dup->next)
{
ptr = (slist_t *)dup->data;
ptr->tail = dup;
}
return (iterator);
}
so, for using this DS you will have to write create function, insert function and destroy function (you will have to free all your dynamically allocated memory).
you may add more function such as remove, search data, clear list, is empty and so on. if you choose to encapsulate this implementation and hide from the user the struct of the list and the struct of the node, you will have to add more function such as get data function, get next node, and more..
you mentioned you need to insert if this data doesn't exist in the list so you can send from insert function to find function.
your function needs to look something like this:
struct job_list {
struct job_node * front;
struct job_list * next;
};
struct job_node {
int reference_number;
char * job_name;
struct job_node *next;
};
for your first function:
struct job_node *JobListCreate(void)
{
struct job_node *list = malloc(sizeof(struct job_node));
struct node_job dummy = NULL;
if(NULL == list)
{
return (NULL);
}
dummy = malloc(sizeof(node_t));
if(NULL == dummy)
{
free(list);
return (NULL);
}
dummy->next = NULL;
dummy->data = (void *)list;
list->head = dummy;
list->tail = dummy;
return (list);
}
for your second function:
void JobListInsertInFront(struct job_node *list, int reference_number, char * job_name)
{
slist_t *ptr = NULL;
struct node_job dup = NULL;
assert(NULL != list);
dup = (struct node_job)malloc(sizeof(node_t));
if(NULL == dup)
{
printf("Allocation failed\n");
return;
}
dup->reference_number = list->head->reference_number;
dup->job_name = list->head->job_name;
dup->next = list->head->next;
list->head->reference_number = reference_number;
list->head->job_name = job_name;
list->head->next = dup;
return;
}
and for the last function:
bool JobListInsertIfNotExist(struct job_node *list, int reference_number, char * job_name)
{
slist_t *ptr = NULL;
struct node_job dup = NULL;
assert(NULL != list);
while (NULL != dup)
{
if (dup->reference_number == reference_number && dup->job_name == job_name)
{
return false;
}
dup = dup->next;
}
dup = (struct node_job)malloc(sizeof(node_t));
if(NULL == dup)
{
printf("Allocation failed\n");
return;
}
dup->reference_number = list->head->reference_number;
dup->job_name = list->head->job_name;
dup->next = list->head->next;
list->head->reference_number = reference_number;
list->head->job_name = job_name;
list->head->next = dup;
return true;
}

As Jack Lilhammers pointed out in the comments, your code is very complex and there are a lot of mistakes in it, so I wrote down some general functions that you can then modify accordingly.
This is the basic struct, that we are going to work with:
struct node {
int data;
struct node *next;
};
Create a new node
Then this is how you'd create a new node:
#include <stdio.h>
#include <stdlib.h>
struct node *new_node(int data, struct node *next)
{
struct node *new = malloc(sizeof *new);
if (!new) {
printf("Error: memory allocation failed");
exit(EXIT_FAILURE);
}
new->data = data;
new->next = next;
return new;
}
You would initially call the function like this:
struct node *head = new_node(5, NULL);
Check if a node exists
Normally you would do something like this to check if a node with specific data exists in the linked list:
#include <stdbool.h>
/* Return whether or not the node exists */
bool node_exists(struct node *head, int data)
{
struct node *cursor = head;
while (cursor != NULL) {
if (cursor->data == data)
return true;
cursor = cursor->next;
}
return false;
}
Insert new node at the end
If you want to insert a new node at the end of the linked list, this is how it works:
void insert_last(struct node *head, struct node *new)
{
struct node **cursor = &head;
while ((*cursor) != NULL)
cursor = &(*cursor)->next;
*cursor = new;
}
Insert new node if nonexistent
You can combine the last two functions to only insert a new node at the end of the linked list, if the data doesn't already exist:
#include <stdbool.h>
/*
* Return whether or not the node exists. If it exists,
* insert the new node at the end of the linked list.
*/
bool new_insert_last(struct node *head, struct node *new)
{
struct node **cursor = &head;
while ((*cursor) != NULL) {
if ((*cursor)->data == new->data)
return true;
cursor = &(*cursor)->next;
}
*cursor = new;
return false;
}
This function could be called like this:
new_insert_last(head, new_node(3, NULL));
I have created a GitLab Snippet, so you can see the functions in action.

Related

C: Function do Delete a Node on a Generic Linked List

I'm having trouble writing a function that will delete a node on a generic linked list.
I have my linked list declared as follow (this is the way my professor wants us to do):
typedef enum _STATUS {ERROR,OK} STATUS;
typedef enum _BOOLEAN {FALSE, TRUE} BOOLEAN;
#define MAX_NOME 20
typedef struct _FUNC
{
char name[MAX_NOME];
char dept[MAX_NOME];
BOOLEAN permanent;
} FUNC;
typedef struct _LIST_NODE
{
void * data;
struct _LIST_NODE * next;
} LIST_NODE;
typedef LIST_NODE * LIST;
#define DATA(node) ((node)->data)
#define NEXT(node) ((node)->next)
I've come with this function to delete all nodes with permanent == FALSE, but it is really not working.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while ((*list)->next != NULL)
{
if(((FUNC*)DATA(*list))->permament == FALSE)
{
node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
}
else
{
list = NEXT(*list);
}
}
}
Any feedback would be greatly appreciated. Thank you.
You iterate through the list with a pointer to node pointer, which is a good idea. (Typecasting away the pointer nature of LIST is not a good idea, however.) There are several errors in yur code.
To get a pointer to the last element of a list, you do:
Node **p = &head;
while (*p) {
p = &(*p)->next;
}
Your respective code, i.e. your function without the deletion stuff, looks like this:
while ((*list)->next != NULL) {
list = NEXT(*list);
}
You should iterate while (*list). The idea to check next probably stems from similar code that uses a node pointer to iterate. When you use a pointer to node pointer, dereferencing that pointer has the same effect as accessing next, because that pointer points to the head node at first and to the previous node's next member on subsequent iterations.
That's why you must assign the address of (*list)->next to list when you want to advance the pointer. (The comiler warns you that the pointer types don't match.)
So the "raw" loop should be:
while (*list != NULL) {
list = &NEXT(*list);
}
Now let's look at deletion. When you have determined that the node should be deleted, you do:
LIST *node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
Here, you do not want to advance the iterator pointer. Instead, you want to update what it points at: You want to skip the current node *list by deflecting the pointer that points to the node to the next node or to NULL, when that was the last node:
*list = NEXT(*node);
When you do that, list and node will still be the same address, only the contents have changed. (Because node == list, *node now points at the node after the node you want to delete and you accidentally free that node and its data. Make the temporary pointer a simple node pointer:
LIST node = *list;
*list = NEXT(node);
free(DATA(node));
free(node);
Putting it all together:
void DeleteFuncNotPermanent(LIST *list, int c)
{
while (*list)
{
if (((FUNC*) DATA(*list))->permament == FALSE)
{
LIST node = *list;
*list = (NEXT(*list));
free(DATA(node));
free(node);
}
else
{
list = &NEXT(*list);
}
}
}
I have tried to rewrite your delete function. Let me know if it works. The changes are basically related to pointer dereferencing.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while (list!= NULL) // change
{
if(((FUNC*)(DATA(list)))->permament == FALSE) // change
{
node = list;
list = NEXT(node); //change
free((FUNC*)(DATA(node))); // change
free(node); // change
}
else
{
list = NEXT(list); //change
}
}
}

How to add new element to double linked list

I want to make a function that can add new elements to double linked list in C, but I couldn't do it. Here is code.
New element should have name, group etc. Just explain me how to make name and rest of it I will do by myself.
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <string.h>
typedef struct inform
{
char name[20];
char group[20];
char form[20];
int day;
int month;
int year;
int srok;
} INF_BLOK;
typedef struct list_elem
{
INF_BLOK inf;
struct list_elem *next, *prev;
} APTEKA;
APTEKA *head, *tail;
int InputData(INF_BLOK* inf);
int main()
{
return 0;
}
I tried to implement a function that inserts an element based on an given index. Note, that i changed your list_item struct a bit so that it contains a pointer to your data-elements.
Here is the implementation:
/**************************************************************
* Function: insert_index
* Parameters: APTEKA* head, INF_BLOK* data, int index
* Return value: Returns NULL on failure, a pointer to the head
* on success
* Description: Inserts a APTEKA* element based on an given
* index
***************************************************************/
APTEKA* insert_index(APTEKA* head, INF_BLOK* data, int index) {
// Local variable for index
int ind = 1;
APTEKA* new_node = (APTEKA*)malloc(sizeof(APTEKA));
new_node->inf = data;
// Check if head exists, the malloc call was successfull and the index is
// in allowed range
// NOTE: Index for head starts at position 1
if(head && new_node && index) {
// If index is one, set a new head
if(index == 1) {
// The previous node is of course NULL
new_node->prev = NULL;
new_node->next = head->next;
if(head->next)
head->next->prev = new_node;
head->next = new_node;
// In a full implementation you need to free the memory for head and the data field in the
// structure. free(...)
// Return a pointer to the new head of the list
return new_node;
} else {
APTEKA* current_node = head->next;
// Loop through all positions before the desired index
for(; ind < (index - 1); ++ind)
current_node = current_node->next;
new_node->prev = current_node;
new_node->next = current_node->next;
if(current_node->next)
current_node->next->prev = new_node;
current_node->next = new_node;
}
}
else {
// Return NULL on failure
return NULL;
}
// Return an pointer to the head
return head;
}
Explanation:
First the function creates a new node named new_node and sets the pointer of the inf data field to the given parameter. Before actually inserting i basically check for that everything is right.
I then divide into two cases: first one to replace the head (index == 1) and second one is for any other index.
If the head should be replaced i change the dependecies and return a pointer to the newly created node. For any other case i iterate to the element before the index and then try to insert it.
When i tested it with this main function, it seemed to work:
int main()
{
/* Only used for testing purposes */
APTEKA* head = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* first = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* tail = (APTEKA*)malloc(sizeof(APTEKA));
head->next = first, head->prev = NULL;
first->next = tail, first->prev = head;
tail->next = NULL, tail->prev = first;
/* Information for head node */
INF_BLOK* block_head = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_head->name, "Head", 5);
/* Information for tail node */
INF_BLOK* block_tail = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_tail->name, "Tail", 5);
/* Information for first block */
INF_BLOK* block_first = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_first->name, "First", 6);
/* Information for block to add */
INF_BLOK* block_sec = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_sec->name, "Second", 7);
head->inf = block_head, first->inf = block_first, tail->inf = block_tail;
if(!insert_index(head, block_sec, 2))
fprintf(stderr, "Error inserting element\n");
APTEKA* element = head;
/* Print out name-data of nodes */
while(element) {
puts(element->inf->name);
element = element->next;
}
element = head;
// Freeing everything
while (element) {
APTEKA* next = element->next;
free(element->inf), free(element);
element = next;
}
return 0;
}
Hopefully, my answer gives you the desired insights. If i did something wrong, please correct me :)
NOTE: For this answer i only used the name attribute of your data-item structure. For storing the group, form, etc. you will need another procedure setting those values.

Alphabetical Insert in Double linked list issue

So, I am reading from a file and inserting national park names into nodesin a double linked list. Now, I want to insert alphabetically, and I thought I was doing that in the insert function, but when I go to print out the list, it is just in the order in which they are inserted in. My guess is that I have an error in the strcmp in the insert function, but I can't figure it out.
I am suppose to use sentinel nodes. So, the first node has "" in it and the last node will have 177 in the data fields. This is my first time using sentinel nodes, and my teacher wanted us to use them, so I apologize if there is errors with them.
Thanks for the help.
#define DUMMY_TRAILER '\177'
typedef struct node NODE;
struct node
{
char data[20]; //for sentinel nodes
char parkName[20];
NODE *forw;
NODE *back;
};
FILE *Open(void); // Opens file
NODE *init_list(void); //Creates the sentinel nodes
void insert(NODE *list, char *name); //Inserts nodes into list
void traverse_forw(NODE *list); // Traverse the list and prints
Main
int _tmain(int argc, _TCHAR* argv[])
{
FILE* inputFile;
NODE *list;
char tempName[31];
inputFile = Open();
list = init_list();
while(fgets(tempName, 31, inputFile) != NULL)
{
insert(list, tempName);
FLUSH;
}
traverse_forw(list);
free(list);
return 0;
}
Insert Function
void insert(NODE *list, char *data)
{
NODE *curr = list->forw;
NODE *prev = list;
NODE *pnew;
int duplicate = 1;
// search
while (strcmp(data,curr->data) > 0)
{
prev = curr;
curr = curr->forw;
}
if (strcmp(data, curr->data))
{
duplicate = 0; // not a duplicate
pnew = (NODE *) malloc(sizeof (NODE));
if (!pnew)
{
printf("Fatal memory allocation error in insert!\n");
exit(3);
}
strcpy(pnew->parkName, data);
pnew->forw = curr;
pnew->back = prev;
prev->forw = pnew;
curr->back = pnew;
}
return;
}
Traverse to print out park names
void traverse_forw(NODE *list)
{
putchar('\n');
list = list->forw; // skip the dummy node
while (list->data[0] != DUMMY_TRAILER)
{
printf("%s\n", list->parkName);
list = list->forw;
}
return;
}
You are storing file read-lines into parkName but comparison is based on the data field
First of all you should create an empty linked list which is equal to NULL, then in the insert function before search, you control if the list is empty or not (in order to not comparing an string with NULL in the first insertion).
another issue is that in this part of the insert function:
while (strcmp(data,curr->data) > 0)
{
prev = curr;
curr = curr->forw;
}
you are only controlling if the data is alphabetically after the current data, I mean you control only forward and if you insert a data which starts with "D" after a data which starts with "R" for instance, your code won't handle that. so you should also consider backward control as well.
Another issue is which pouyan mentioned above, that you are putting data into the data and not in the parkname.

doublepointed list C

I wanted to make a list using double pointer and using void as return.
#include<stdio.h>
#include<stdlib.h>
typedef struct list{
int value;
struct list *next;
}*list;
void addnode(struct list **List, int number) {
if(*List == NULL) {
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
} else {
while((*List)->next != NULL) {
(*List) = (*List)->next;
}
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
}
}
int main() {
list List1 = NULL;
addnode(&List1, 20);
printf("%d \n", List1->value);
addnode(&List1, 30);
printf("%d \n", List1->value);
printf("%d \n", List1->next->value);
return 0;
}
The first if in addnode is always executed but i want to append the list if its not empty but it seems like it never work. Ill also get segmenation fault because in the last printf it tries to take the next element in the list but its never initialized like i want.
If everthing worked as i wanted i should have printed out
printf("%d\n", List1->value)
20
printf("%d\n", List1->value)
20
printf("%d\n", List1->next->value)
30
The size you are passing to malloc is wrong.
You are allocating a struct list, not a struct list *.
If you are trying to append a new list item, remember (*List)->next will already be NULL on the second call. The malloc following that uses the pointer before the NULL list item (*List) when it should be assigned to the next list item, the one that is NULL, to make it non-NULL ((*List)->next=malloc(struct list);).
Also, your malloc should be using sizeof(struct list), without the *. If you add the *, you're allocating a struct list **. A rule you can use is use one * fewer than the destination type as the sizeof operand. Since your destination is *List, which is of type struct list *, use sizeof(struct list). Alternatively, because your destination is *List, use sizeof **List (use one more * than the destination variable has). This avoids you needing to know the type. It won't matter if List or *List is NULL because the sizeof operation is executed first; pointer dereferencing never occurs since sizeof works on the type of the variable.
Modify your program like this
int addNode(struct list **List, int number)
{
struct list *new, *tmp; // new = create new node, tmp = navigate to last
new = malloc(sizeof(struct list));
if(!new) { //always validate "malloc"
perror("malloc");
exit(1);
}
new -> value = value; // assigning values to new node
new -> next = NULL;
if(!(*list)) { //Check if list is empty or not, plz initialize *list#main() with NULL as like your program. or write seperate function to initialize
*list = new;
return 0; //no need write else condition, bcoz its the first node. and u can directly return
}
tmp = *list;
while(tmp -> next) // To navigate to last node
tmp = tmp -> next;
tmp -> next = new; //creating link to new node
return 0;
}
It's better to write print function seperatly.
int print(struct list **list)
{
struct *current; //current is your current node position
current = *list;
while(current) { //loop till current node addr == NULL
printf("%d\t", current -> value);
current = current -> next;
}
printf("\n");
return 0;
}

How to implement a linked list in C?

I am creating a linked list as in the previous question I asked. I have found that the best way to develop the linked list is to have the head and tail in another structure. My products struct will be nested inside this structure. And I should be passing the list to the function for adding and deleting. I find this concept confusing.
I have implemented the initialize, add, and clean_up. However, I am not sure that I have done that correctly.
When I add a product to the list I declare some memory using calloc. But I am thinking shouldn't I be declaring the memory for the product instead. I am really confused about this adding.
Many thanks for any suggestions,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 128
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct product_data_t *next;
}product_data_t;
typedef struct list
{
product_data_t *head;
product_data_t *tail;
}list_t;
void add(list_t *list, int code, char name[], int cost);
void initialize(list_t *list);
void clean_up(list_t *list);
int main(void)
{
list_t *list = NULL;
initialize(list);
add(list, 10, "Dell Inspiron", 1500);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
// Allocate memory for the new product
list = calloc(1, sizeof(list_t));
if(!list)
{
fprintf(stderr, "Cannot allocated memory");
exit(1);
}
if(list)
{
// First item to add to the list
list->head->product_code = code;
list->head->product_cost = cost;
strncpy(list->head->product_name, name, sizeof(list->head->product_name));
// Terminate the string
list->head->product_name[127] = '/0';
}
}
// Initialize linked list
void initialize(list_t *list)
{
// Set list node to null
list = NULL;
list = NULL;
}
// Release all resources
void clean_up(list_t *list)
{
list_t *temp = NULL;
while(list)
{
temp = list->head;
list->head = list->head->next;
free(temp);
}
list = NULL;
list = NULL;
temp = NULL;
}
============================== Edited ============================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 64
// typedef struct product_data product_data_t;
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
}product_data_t;
typedef struct list
{
struct list *head;
struct list *tail;
struct list *next;
struct list *current_node;
product_data_t *data;
}list_t;
void add(list_t *list, int code, char name[], int cost);
int main(void)
{
list_t *list = NULL;
list = initialize(list);
add(list, 1001, "Dell Inspiron 2.66", 1299);
add(list, 1002, "Macbook Pro 2.66", 1499);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
/* Allocate memory for the new product */
product_data_t *product = (product_data_t*) calloc(1, sizeof(*product));
if(!product)
{
fprintf(stderr, "Cannot allocate memory.");
exit(1);
}
/* This is the first item in the list */
product->product_code = code;
product->product_cost = cost;
strncpy(product->product_name, name, sizeof(product->product_name));
product->product_name[PRODUCT_NAME_LEN - 1] = '\0';
if(!list->head)
{
/* Assign the address of the product. */
list = (list_t*) product;
/* Set the head and tail to this product */
list->head = (list_t*) product;
list->tail = (list_t*) product;
}
else
{
/* Append to the tail of the list. */
list->tail->next = (list_t*) product;
list->tail = (list_t*) product;
}
/* Assign the address of the product to the data on the list. */
list->data = (list_t*) product;
}
If you are looking to better understand the basics of linked lists, take a look at the following document:
http://cslibrary.stanford.edu/103/LinkedListBasics.pdf
Arguably you want your list data structure to be external to the data that it stores.
Say you have:
struct Whatever
{
int x_;
}
Then your list structure would look like this:
struct Whatever_Node
{
Whatever_Node* next_
Whatever* data_
}
Ryan Oberoi commented similarly, but w/o example.
In your case the head and tail could simply point to the beginning and end of a linked-list. With a singly linked-list, only the head is really needed. At it's most basic, a linked-list can be made by using just a struct like:
typedef struct listnode
{
//some data
struct listnode *next;
}listnodeT;
listnodeT *list;
listnodeT *current_node;
list = (listnodeT*)malloc(sizeof(listnodeT));
current_node = list;
and as long as list is always pointing to the beginning of the list and the last item has next set to NULL, you're fine and can use current_node to traverse the list. But sometimes to make traversing the list easier and to store any other data about the list, a head and tail token are used, and wrapped into their own structure, like you have done. So then your add and initialize functions would be something like (minus error detection)
// Initialize linked list
void initialize(list_t *list)
{
list->head = NULL;
list->tail = NULL;
}
void add(list_t *list, int code, char name[], int cost)
{
// set up the new node
product_data_t *node = (product_data_t*)malloc(sizeof(product_data_t));
node->code = code;
node->cost = cost;
strncpy(node->product_name, name, sizeof(node->product_name));
node->next = NULL;
if(list->head == NULL){ // if this is the first node, gotta point head to it
list->head = node;
list->tail = node; // for the first node, head and tail point to the same node
}else{
tail->next = node; // append the node
tail = node; // point the tail at the end
}
}
In this case, since it's a singly linked-list, the tail is only really useful for appending items to the list. To insert an item, you'll have to traverse the list starting at the head. Where the tail really comes in handy is with a doubly-linked list, it allows you to traverse the list starting at either end. You can traverse this list like
// return a pointer to element with product code
product_data_t* seek(list_t *list, int code){
product_data_t* iter = list->head;
while(iter != NULL)
if(iter->code == code)
return iter;
iter = iter->next;
}
return NULL; // element with code doesn't exist
}
Often times, the head and tail are fully constructed nodes themselves used as a sentinel to denote the beginning and end of a list. They don't store data themselves (well rather, their data represent a sentinel token), they are just place holders for the front and back. This can make it easier to code some algorithms dealing with linked lists at the expense of having to have two extra elements. Overall, linked lists are flexible data structures with several ways to implement them.
oh yeah, and nik is right, playing with linked-lists are a great way to get good with pointers and indirection. And they are also a great way to practice recursion too! After you have gotten good with linked-list, try building a tree next and use recursion to walk the tree.
I am not writing the code here but you need to do the following:
Create and object of list, this will remain global for the length of program.
Malloc the size of product _ data _ t.
For first element (head is NULL), point head to the malloced' address.
To add next element, move to the end of list and then add the pointer of malloced address to next of last element. (The next of the last element will always be NULL, so thats how you traverse to end.)
Forget tail for a while.
If you are learning C pointer theory this is a good exercise.
Otherwise, it feels like too much indirection for code that is not generic (as in a library).
Instead of allocating a static 128 byte character string, you might want to do some more pointer practice and use an allocated exact length string that you clean up at exit.
Academically, kungfucraigs' structure looks more generic then the one you have defined.
You're calloc'ing space for your list_t struct, just pointers to list head and tail, which isn't what you want to do.
When you add to a linked list, allocate space for an actual node in the list, which is your product_data_t struct.
You're allocating the wrong chunk of memory. Instead of allocating memory for each list element, you're allocating for the list head and tail.
For simplicity, get rid of the separate structure for the head and tail. Make them global variables (the same scope they're in now) and change them to be listhead and listtail. This will make the code much more readable (you won't be needlessly going through a separate structure) and you won't make the mistake of allocating for the wrong struct.
You don't need a tail pointer unless you're going to make a doubly linked list. Its not a major element to add once you create a linked list, but not necessary either.
In memory your items are linked by pointers in the list structure
item1 -> item2
Why not make the list structure part of your item?
Then you allocate a product item, and the list structure is within it.
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct list_t list; // contains the pointers to other product data in the list
}product_data_t;
I think u first need to Imagin back-end. Code are nothing to important. Go here and visualize back-end basic c code of all insertion.
1) Insertion at beginning Visit and scroll to get every instruction execution on back- end
And u need front and imagin Go here
Back end imagin
And All other possible insertion here.
And important thing u can use this way.
struct Node{
int data;//data field
struct Node*next;//pointer field
};
struct Node*head,*tail; // try this way
or short cut
struct Node{
int data;//data field
struct Node*next;//pointer field
}*head,*tail; //global root pointer
And << Click >> To visualize other linked list problem.
Thanks.
A demo for Singly Linked List. If you prefer, try to check Circular Linked List and Doubly Linked List.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node * next;
} node_t;
// Iterating over a list
void
print_list(node_t *head)
{
node_t *current = head;
while(current != NULL)
{
printf("%d\n", current->val);
current = current->next;
}
}
// Adding an item to the end of the list
void
push_end(node_t *head, int val)
{
node_t *current = head;
while (current->next != NULL)
{
current = current->next;
}
current->next = malloc(sizeof(node_t));
current->next->val = val;
current->next->next = NULL;
}
// Adding an item to the head of the list
void
push_head(node_t **head, int val)
{
node_t *new_node = NULL;
new_node = malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head;
*head = new_node;
}
// Removing the head item of the list
int
pop_head(node_t **head)
{
int retval = -1;
node_t *next_node = NULL;
if (*head == NULL) {
return -1;
}
next_node = (*head)->next;
retval = (*head)->val;
free(*head);
*head = next_node;
return retval;
}
// Removing the last item of the list
int
pop_last(node_t *head)
{
int retval = 0;
node_t *current = NULL;
if (head->next == NULL) {
retval = head->val;
free(head);
return retval;
}
/* get to the second to last node in the list */
current = head;
while (current->next->next != NULL) {
current = current->next;
}
/* now current points to the second to last item of the list.
so let's remove current->next */
retval = current->next->val;
free(current->next);
current->next = NULL;
return retval;
}
// Removing a specific item
int
remove_by_index(node_t **head, int n)
{
int i = 0;
int retval = -1;
node_t *current = *head;
node_t *temp_node = NULL;
if (n == 0) {
return pop_head(head);
}
for (i = 0; i < n - 1; i++) {
if (current->next == NULL) {
return -1;
}
current = current->next;
}
temp_node = current->next;
retval = temp_node->val;
current->next = temp_node->next;
free(temp_node);
return retval;
}
int
main(int argc, const char *argv[])
{
int i;
node_t * testnode;
for (i = 0; i < argc; i++)
{
push_head(&testnode, atoi(argv[i]));
}
print_list(testnode);
return 0;
}
// http://www.learn-c.org/en/Linked_lists
// https://www.geeksforgeeks.org/data-structures/linked-list/
The linked list implementation inspired by the implementation used in the Linux kernel:
// for 'offsetof', see: https://stackoverflow.com/q/6433339/5447906.
#include <stddef.h>
// See: https://stackoverflow.com/q/10269685/5447906.
#define CONTAINER_OF(ptr, type, member) \
( (type *) ((char *)(ptr) - offsetof(type, member)) )
// The macro can't be used for list head.
#define LIST_DATA(ptr, type, member) \
CONTAINER_OF(ptr, type, member);
// The struct is used for both: list head and list nodes.
typedef struct list_node
{
struct list_node *prev, *next;
}
list_node;
// List heads must be initialized by this function.
// Using the function for list nodes is not required.
static inline void list_head_init(list_node *node)
{
node->prev = node->next = node;
}
// The helper function, mustn't be used directly.
static inline void list_add_helper(list_node *prev, list_node *next, list_node *nnew)
{
next->prev = nnew;
nnew->next = next;
nnew->prev = prev;
prev->next = nnew;
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_after(list_node *node, list_node *nnew)
{
list_add_helper(node, node->next, nnew);
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_before(list_node *node, list_node *nnew)
{
list_add_helper(node->prev, node, nnew);
}
// 'node' must be part of a list.
static inline list_node *list_del(list_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
return node->prev;
}
Example of usage:
#include <stdio.h>
// The struct must contain 'list_node' to be able to be inserted to a list
typedef struct
{
int data;
list_node node;
}
my_struct;
// Convert 'list_node *' to 'my_struct*' that contains this 'list_node'
static inline my_struct* get_my_struct(list_node *node_ptr)
{
return LIST_DATA(node_ptr, my_struct, node);
}
void print_my_list(list_node *head)
{
printf("list: {");
for (list_node *cur = head->next; cur != head; cur = cur->next)
{
my_struct *my = get_my_struct(cur);
printf(" %d", my->data);
}
printf(" }\n");
}
// Print 'cmd' and run it. Note: newline is not printed.
#define TRACE(cmd) \
(printf("%s -> ", #cmd), (cmd))
int main()
{
// The head of the list and the list itself. It doesn't contain any data.
list_node head;
list_head_init(&head);
// The list's nodes, contain 'int' data in 'data' member of 'my_struct'
my_struct el1 = {1};
my_struct el2 = {2};
my_struct el3 = {3};
print_my_list(&head); // print initial state of the list (that is an empty list)
// Run commands and print their result.
TRACE( list_add_after (&head , &el1.node) ); print_my_list(&head);
TRACE( list_add_after (&head , &el2.node) ); print_my_list(&head);
TRACE( list_add_before(&el1.node, &el3.node) ); print_my_list(&head);
TRACE( list_del (head.prev) ); print_my_list(&head);
TRACE( list_add_before(&head , &el1.node) ); print_my_list(&head);
TRACE( list_del (&el3.node) ); print_my_list(&head);
return 0;
}
The result of execution of the code above:
list: { }
list_add_after (&head , &el1.node) -> list: { 1 }
list_add_after (&head , &el2.node) -> list: { 2 1 }
list_add_before(&el1.node, &el3.node) -> list: { 2 3 1 }
list_del (head.prev) -> list: { 2 3 }
list_add_before(&head , &el1.node) -> list: { 2 3 1 }
list_del (&el3.node) -> list: { 2 1 }
http://coliru.stacked-crooked.com/a/6e852a996fb42dc2
Of course in real life you will most probably use malloc for list elements.
In C language, we need to define a Node to store an integer data and a pointer to the next value.
struct Node{
int data;
struct Node *next;
};
To add a new node, we have a function add which has data as an int parameter. At first we create a new Node n. If the program does not create n then we print an error message and return with value -1. If we create the n then we set the data of n to have the data of the parameter and the next will contain the root as it has the top of the stack. After that, we set the root to reference the new node n.
#include <stdio.h>
struct node
{
int data;
struct node* next;
};
int main()
{
//create pointer node for every new element
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
//initialize every new pointer with same structure memory
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 18;
head->next = second;
second->data = 20;
second->next = third;
third->data = 31;
third->next = NULL;
//print the linked list just increment by address
for (int i = 0; i < 3; ++i)
{
printf("%d\n",head->data++);
return 0;
}
}
This is a simple way to understand how does pointer work with the pointer. Here you need to just create pointer increment with new node so we can make it as an automatic.
Go STL route. Declaring linked lists should be agnostic of the data. If you really have to write it yourself, take a look at how it is implemented in STL or Boost.
You shouldn't even keep the *next pointer with your data structure. This allows you to use your product data structure in a various number of data structures - trees, arrays and queues.
Hope this info helps in your design decision.
Edit:
Since the post is tagged C, you have equivalent implementations using void* pointers that follow the basic design principle. For an example, check out:
Documentation | list.c | list.h

Resources