Cannot push element to the head of the linked list - c

I'm trying to implement linked list in C and I've got a problem with wrong output. The first element seems not to be pushed in the head of the list.
I expect the below output in the program:
1
1
Actual output:
0
0
Have you ideas what's wrong with the code? Thanks
Problematic code:
main.c
#include <stdio.h>
#include "linked_list.h"
int main(void) {
struct ll_node *node = ll_new();
ll_push_front(node, 1);
printf("%d\n", ll_size(node)); // should print 1, actual output: 0
printf("%d\n", ll_pop_back(node)); // should print 1, actual output: 0
ll_destroy(node);
return 0;
}
linked_list.h
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include <stdbool.h>
struct ll_node {
int data;
struct ll_node *prev;
struct ll_node *next;
};
struct ll_node *ll_new();
void ll_destroy(struct ll_node *node);
void ll_push_back(struct ll_node *node, int data);
void ll_push_front(struct ll_node *node, int data);
int ll_pop_back(struct ll_node *node);
int ll_pop_front(struct ll_node *node);
int ll_delete_at(struct ll_node *node, int index);
bool ll_contains(struct ll_node *node, int data);
int ll_find(struct ll_node *node, int data);
int ll_size(struct ll_node *node);
#endif //LINKED_LIST_H
linked_list.c
#include "linked_list.h"
#include <stdio.h>
#include <stdlib.h>
struct ll_node *ll_new() {
struct ll_node* node = (struct ll_node *) malloc(sizeof(struct ll_node *));
if (!node) {
fprintf(stderr, "Error: cannot allocate struct ll_node *node at ll_new");
exit(1);
}
node->prev = NULL;
node->next = NULL;
return node;
}
void ll_destroy(struct ll_node *node) {
while (node->next != NULL) {
struct ll_node *elem = node;
node = node->next;
free(elem);
}
}
void ll_push_back(struct ll_node *node, int data) {
while (node->next != NULL) {
node = node->next;
}
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node *));
current->data = data;
current->next = NULL;
current->prev = node;
node->next = current;
}
void ll_push_front(struct ll_node *node, int data) {
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node *));
current->data = data;
current->next = node;
current->prev = NULL;
node->prev = current;
}
int ll_pop_back(struct ll_node *node) {
struct ll_node *current = node;
while (current->next != NULL) {
current = current->next;
}
int old_data = current->data;
free(current);
return old_data;
}
int ll_pop_front(struct ll_node *node) {
// TODO: implement this
}
int ll_delete_at(struct ll_node *node, int index) {
// TODO: implement this
}
bool ll_contains(struct ll_node *node, int data) {
while (node->next != NULL) {
if (node->data != data) {
return false;
}
node = node->next;
}
return true;
}
int ll_find(struct ll_node *node, int data) {
// TODO: implement this
}
int ll_size(struct ll_node *node) {
int size = 0;
while (node->next != NULL) {
++size;
node = node->next;
}
return size;
}

When you push something on to the front of a list, don't you need to return a pointer to the new list?
Surely this code should be changed to return a pointer to current.
void ll_push_front(struct ll_node *node, int data) {
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node *));
current->data = data;
current->next = node;
current->prev = NULL;
node->prev = current;
}
Then in the calling function, you should be reading that result and storing it as the new list, I think?

struct ll_node *node = ll_new(); allocates a new node (let's call it root), obviously, but then you push a new node into front (let's call it node(1):
root->next = NULL
root->prev = node(1)
node(1)->next = root
node(1)->prev = NULL
In main() node * still points to root, and indeed, it's next pointer is NULL, so ll_size() returns 0. You probably want to return the new root node and do this in main() or pass in the node as struct ll_node ** so you can update it.
node = ll_push_front(node, 1);
Prefer to use the variable rather than type for allocations, and don't cast the void * pointer:
struct ll_node *current = malloc(sizeof *current);
This also fixes the defect of allocating size of a pointer but you require size of the object.
You have a ll_new() function but but ll_push_front() and ll_push_back() implements the same thing again. You should refactor the latter two to use ll_new().
It's not necessarily wrong just confusing that you use struct ll_node to both represent a node of your linked list, and the entire linked list. The root node, for instance, has uninitialized data.
You will need to make similar changes to ll_pop_back(), and you need to update all the relevant pointers.
What should ll_pop_back() do if the list is empty?
ll_destroy() doesn't free the current node.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct ll_node {
int data;
struct ll_node *prev;
struct ll_node *next;
};
struct ll_node *ll_new() {
struct ll_node* node = malloc(sizeof *node);
if (!node) {
fprintf(stderr, "Error: cannot allocate struct ll_node *node at ll_new");
exit(1);
}
return node;
}
void ll_push_front(struct ll_node **root, int data) {
if(!root) {
printf("root must be non-NULL");
exit(1);
}
struct ll_node *current = ll_new();
current->data = data;
current->prev = NULL;
current->next = *root;
if(*root)
(*root)->prev = current;
*root = current;
}
int ll_pop_back(struct ll_node **root) {
if(!root) {
printf("root must be non-NULL");
exit(1);
}
if(!*root) {
printf("*root must be non-NULL");
exit(1);
}
struct ll_node *current = *root;
while (current->next != NULL) {
current = current->next;
}
int data = current->data;
if(current->prev)
current->prev->next = NULL;
else
*root = NULL;
free(current);
return data;
}
int ll_size(struct ll_node *node) {
size_t n = 0;
for(; node; node = node->next, n++);
return n;
}
void ll_destroy(struct ll_node *root) {
while(root) {
struct ll_node *tmp = root->next;
free(root);
root = tmp;
}
}
int main(void) {
struct ll_node *root = NULL;
ll_push_front(&root, 'a');
ll_push_front(&root, 'b');
printf("%d\n", ll_size(root));
printf("%c\n", ll_pop_back(&root));
printf("%d\n", ll_size(root));
printf("%c\n", ll_pop_back(&root));
printf("%d\n", ll_size(root));
ll_destroy(root);
}
and the resulting output:
2
a
1
b
0

sizeof (struct node *) != sizeof (struct node):
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node *));
only allocates memory for the pointer, which will likely be 8 bytes on a 64-bit machine or 4 bytes on a 32-bit machine.
Change it to:
struct ll_node *current = malloc (sizeof *current);
Note that the cast is redundant and may hide a bug. There's an implicit conversion to and from a void *.
One advice I see most often on codereview.com is to allocate based on the size of what an object points to rather than the object type itself. This eases maintainability.
The function is also discarding the return value of malloc(). malloc() returns NULL to indicate failure. I'd suggest returning a bool type for ll_push_front(), true would indicate success, and false can indicate a memory allocation failure.
Changes to local parameters are never reflected back in the caller's memory:
The first element seems not to be pushed in the head of the list.
Your push function is very close to being correct. Remember that C has pass-by-value semantics and pointers are not exempt to that rule. As is, your push function only changes its local copy of head. This change will not be reflected back in the main() function. We need the push function to be able to change the caller's memory. The traditional method to allow a function to change it's caller memory is to pass a pointer to the caller's memory instead of a copy.
So instead of:
struct node *head = /* some value */;
push_node (head, /* some value */);
We pass a pointer to the head pointer, so the changes made to the head pointer in the push function are reflected back in main().
push_node (&head, /* some value */);
And dereference the pointer in the push function to access the caller's memory.
There are other issues in your code. I'd suggest implementing a singly linked list before moving on to this.

For starters within the function ll_new there is incorrectly allocated memory for a node of the list.
struct ll_node* node = (struct ll_node *) malloc(sizeof(struct ll_node *));
Instead you need to write either
struct ll_node* node = (struct ll_node *) malloc(sizeof(struct ll_node ));
or
struct ll_node* node = (struct ll_node *) malloc(sizeof( *node ));
The function does not make a great sense because it does not initialize the data member data of the created node.
The same problem with allocation memory exists also in the function ll_push_front
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node *));
Again you need to write either
struct ll_node *current = (struct ll_node *) malloc(sizeof(struct node ));
or
struct ll_node *current = (struct ll_node *) malloc(sizeof( *current ));
Actually everywhere in the code you are using incorrect expressions in calls of malloc.
Also the function does not change the pointer to the head node of the list.
It only sets its data member prev to the newly created node
As a result the function ll_size will always return 0 because the data member next of the node pointed to by the pointer node declared in main is equal to NULL
int ll_size(struct ll_node *node) {
int size = 0;
while (node->next != NULL) {
++size;
node = node->next;
}
return size;
}
The function ll_push_back can invoke undefine behavior if a null pointer is passed to the function due to this while loop within teh function
while (node->next != NULL) {
node = node->next;
}
The function ll_pop_back again does not check whether a null pointer is passed
while (current->next != NULL) {
current = current->next;
}
Also if the list contains only one node then the function does not change the passed pointer. The node will be deleted by the pointer that points to the deleted node will stay unchanged.
Or the function ll_destroy does not free all the allocated memory
void ll_destroy(struct ll_node *node) {
while (node->next != NULL) {
struct ll_node *elem = node;
node = node->next;
free(elem);
}
}
leaving the last node in the list undeleted that results in a memory leak due to the condition in the while loop
while (node->next != NULL) {
Your code contains many errors. You need to rewrite it. Start from this declaration in main
struct ll_node *head = NULL;
and try to write at first the function ll_push_front that adds one node to the empty list.
The list shall not have a dummy node.
Pay attention to that it would be better to declare one more structure like for example
struct linked_list {
size_t size;
struct ll_node *head;
struct ll_node *tail;
};
that will indeed specify the double-lonked list.
In this case there will be much efficient to add new nodes to teh tail of the list or to determine the size of the list.
You could define a list in main like
struct linked_list list = { .size = 0, .head = NULL, .tail = NULL };
And a function that adds a node to the beginning of the list could look like
int ll_push_front( struct linked_list *list, int data );
The function can be defined the following way
int ll_push_front( struct linked_list *list, int data )
{
struct ll_node *new_node = malloc( sizeof( *new_node ) );
int success = new_node != NULL;
if ( success )
{
new_node_>data = data;
new_node->next = list->head;
new_node->prev = NULL;
if ( list->head != NULL )
{
list->head->prev = new_node;
}
else
{
list->tail = new_node;
}
list->head = new_node;
++list->size;
}
return success;
}
And the function is called in main like for example
ll_push_front( &list, 1 );
or
if ( !ll_push_front( &list, 1 ) )
{
puts( "Error: not enough memory!" );
}
In turn the function ll_push_back can look the following way
int ll_push_back( struct linked_list *list, int data )
{
struct ll_node *new_node = malloc( sizeof( *new_node ) );
int success = new_node != NULL;
if ( success )
{
new_node_>data = data;
new_node->next = NULL;
new_node->prev = list->tail;
if ( list->tail != NULL )
{
list->tail->next = new_node;
}
else
{
list->head = new_node;
}
list->tail = new_node;
++list->size;
}
return success;
}
To get the size of the list you can write for example
size_t ll_size( const struct linked_list *list )
{
return list->size;
}

Related

I'm having a problem creating a linked list [duplicate]

This question already has answers here:
Linked lists - single or double pointer to the head
(3 answers)
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 10 months ago.
#include<stdio.h>
#include<stdlib.h>
void insert_front(struct node* head, int block_number);
void insert_rear(struct node* head, int block_number);
void print_list(struct node* head);
struct node {
int block_number;
struct node* next;
};
int main(void)
{
struct node* list = NULL;
insert_front(list, 10);
insert_rear(list, 20);
insert_front(list, 30);
insert_rear(list, 40);
print_list(list);
return 0;
}
void insert_front(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
void insert_rear(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL) {
head = p;
}
else {
struct node* q = head;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
}
}
void print_list(struct node* head)
{
struct node* p = head;
while (p != NULL) {
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
When I ran it, there was no result at all.
Now, in the insert_front function p->block_number = block_number, a message appears saying that the NULL pointer 'p' is being dereferenced... (The same thing appears in the insert_rear function.)
Could it be that I am declaring the pointer wrong?
Both insert_front and insert_rear need to convey possibly head modification back to the caller, and the caller needs to reap that information. Both should be declared to return struct node *, do so, and the code in main react accordingly. E.g.:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
struct node * insert_front(struct node *head, int block_number);
struct node * insert_rear(struct node *head, int block_number);
void print_list(struct node *head);
struct node
{
int block_number;
struct node *next;
};
int main(void)
{
struct node *list = NULL;
list = insert_front(list, 10);
list = insert_rear(list, 20);
list = insert_front(list, 30);
list = insert_rear(list, 40);
print_list(list);
return 0;
}
struct node *insert_front(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
struct node *insert_rear(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL)
{
head = p;
}
else
{
struct node *q = head;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
}
return head;
}
void print_list(struct node *head)
{
struct node *p = head;
while (p != NULL)
{
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
Output
--> 30 --> 10 --> 20 --> 40
I leave the memory leaks for you to resolve.
In C all variables are passed by value – if you pass a pointer, then it is copied, too (not the pointed to object, of course...), and function parameters, apart from being initialised from outside, are nothing more than local variables. Thus via head = p; you just assign the local copy of the outside pointer, not the latter itself!
To fix that you have two options:
Return the new head and make the user responsible for re-assigning the returned value to his own head pointer.
Accept the head as pointer to pointer.
With second approach a user cannot forget to re-assign the (potentially) new head, so that's what I'd go with:
void insert_whichEver(node** head, int block_number)
{
// use `*head` where you had `head` before...
}
void demo()
{
node* head = NULL;
insert_front(&head, 1012);
}
And in insert_front drop return head;, a function with void cannot return anything concrete and does not require a return at all (but bare return; can be used to exit a function prematurely).

How to Use Typedef Structure Name with Pointer

I am trying to implement a linked list using the given structure for a bigger project. The structure is defined below:
typedef struct node {
unint32_t size; // = size of the node
struct node * link; // = .next pointer
} * ListNode;
I was able to implement a linked list using struct node *. But when I attempt to use ListNode like in the following program:
typedef struct node {
unint32_t size;
struct node * link;
} * ListNode;
void insert_node (ListNode * head, unint32_t size) {
ListNode new_node = (ListNode) malloc (sizeof(ListNode));
new_node->size = size;
new_node->link = NULL;
if (head == NULL) {
head = &new_node;
}
else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main (int argc, char const * argv[]) {
ListNode head = NULL;
insert_node (&head, 10);
insert_node(&head, 20);
ListNode ptr = head;
while (ptr != NULL) {
printf ("%d ", ptr->size);
}
printf ("\n");
return 0;
}
I get a segmentation fault. Why is that? It even says that struct node * and ListNode are incompatible pointers/types. I thought they were the same struct just named differently.
A little clarification
typedef struct node {
unint32_t size;
struct node * link;
} *ListNode;
creates a type called ListNode. It is a pointer to a struct node. It is not a struct node
So when you do
sizeof(ListNode)
you get the size of a pointer, not the size of struct node
You needed to do
sizeof(struct node)
A very common thing to do is this
typedef struct node {
uint32_ size;
struct node* link;
} *PListNode, ListNode;
this creates 2 types
PlistNode which is a pointer to a struct node
ListNode which is a struct node
the 'P' is a reminder that this is a pointer
so now you can do
PListNode pn = malloc(sizeof(ListNode));
Since you supply a struct node** (a ListNode*) to insert_node, you need to dereference it to assign to it.
You malloc the size of a struct node* (a ListNode) but you need to malloc the size of a struct node.
You also need to do ptr = ptr->link in the loop in main.
Example:
void insert_node(ListNode* head, uint32_t size) {
// corrected malloc, you don't want the sizeof a pointer but the
// size of a `node`:
ListNode new_node = malloc(sizeof *new_node);
new_node->size = size;
new_node->link = NULL;
if (*head == NULL) { // corrected check (dereference head)
*head = new_node; // corrected assignment
} else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main() {
ListNode head = NULL;
insert_node(&head, 10);
insert_node(&head, 20);
// the below loop had no exit condition before:
for(ListNode ptr = head; ptr; ptr = ptr->link) {
printf("%d ", ptr->size);
}
printf("\n");
}
Demo

Linked list implementation in C(printing only last two nodes)

#include <stdlib.h>
#include <stdio.h>
struct node {
int data;
struct node *next;
};
void addLast(struct node **head, int value);
void printAll(struct node *head);
struct node *head1 = NULL;
int main() {
addLast(&head1, 10);
addLast(&head1, 20);
addLast(&head1, 30);
addLast(&head1, 40);
printAll(head1);
return 0;
}
void addLast(struct node **head, int value) {
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = value;
if (*head == NULL) {
*head = newNode;
(*head)->next = NULL;
} else {
struct node **temp = head;
while ((*temp)->next != NULL) {
*temp = (*temp)->next;
}
(*temp)->next = newNode;
newNode->next = NULL;
}
}
void printAll(struct node *head) {
struct node *temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("\n");
}
addLast() will append the new node at the end of the list, with printAll(), I am printing entire list.
Every time when I am printing the list, I can only see the last two nodes.
Can anyone please help, why loop is not iterating over entire list ?
The function addLast is too complicated and as result is wrong due to this statement
*temp = (*temp)->next;
in the while loop. It always changes the head node.
Define the function the following way
int addLast( struct node **head, int value )
{
struct node *newNode = malloc( sizeof( struct node ) );
int success = newNode != NULL;
if ( success )
{
newNode->data = value;
newNode->next = NULL:
while( *head ) head = &( *head )->next;
*head = newNode;
}
return success;
}
Take into account that there is no need to declare the variable head1 as global. It is better to declare it inside the function main.
Also all the allocated memory should be freed before exiting the program.

Implementing a list C

I have the code with the structure of a list and the code that implements it.
Structure,entry_t is the type of data on the list:
#ifndef _list_private_h
#define _list_private_h
typedef struct list_t{
struct node_t *head;
int size;
};
typedef struct node_t{
struct entry_t *element;
struct node_t *next;
}node_t;
#endif
Code:
struct list_t *list_create(){
struct list_t *list = (struct list_t*) malloc(sizeof(struct list_t));
list->head=NULL;
list->size=0;
return list;
}
int list_destroy(struct list_t *list){
node_t *no = list->head;
while(no!=NULL){
node_t *aux=no;
entry_destroy(no->element);
no=no->next;
free(aux);
list->size=(list->size)-1;
}
free(list);
return 0;
}
int list_add(struct list_t *list, struct entry_t *entry){
node_t *no = list->head;
if(no==NULL){
list->head=(node_t*) malloc(sizeof(node_t));
list->head->element=entry_dup(entry);
list->size=list->size+1;
return 0;
}
else{
while(no!=NULL){
no=no->next;
}
no=(node_t*) malloc(sizeof(node_t));
no->element=entry_dup(entry);
list->size=list->size+1;
return 0;
}
return -1;
}
struct entry_t *list_get(struct list_t *list, char *key){
node_t *no = list->head;
while(no!=NULL){
if(strcmp(no->element->key,key)==0){
return no->element;
}
no=no->next;
}
return NULL;
}
When I run these tests it doesn't add the element to the list:
int testEmptyList() {
struct list_t *list = list_create();
int result = list != NULL && list_size(list) == 0;
list_destroy(list);
printf("Test empty list: %s\n",result?"pass":"not pass");
return result;
}
int testAddHead() {
int result;
struct list_t *list = list_create();
struct entry_t *entry = entry_create(strdup("abc"),data_create(5));
memcpy(entry->value->data,"abc1",5);
list_add(list,entry);
result = list_get(list,"abc") == entry &&
list_size(list) == 1;
list_destroy(list);
printf("Module list -> test add first: %s\n",result?"pass":"not pass");
return result;
}
So, what I want is put this code adding elements to the list. Thanks.
Several issues:
You are destroying the list via list_destroy which can call entry_destroy on the entry added to the list before calling list_get which returns a pointer to (not a copy of) an entry.
In list_add you call malloc to allocate space for a new node, however you don't set its next element to NULL. Since malloc does not guarantee that the memory allocated is wiped, the list may never end with a node that has its next element set to NULL resulting in spurious results.
Your else branch in list_add guarantees no will be NULL (or the program will have crashed from a segfault given earlier problems.) You probably want to terminate when no->next is NULL instead of when no is NULL. Also, this branch needs to assign the next element to NULL explicitly.
Try this:
int list_add(struct list_t *list, struct entry_t *entry){
node_t *no = list->head;
if(no==NULL){
list->head=(node_t*) malloc(sizeof(node_t));
list->head->element=entry_dup(entry);
list->size=list->size+1;
return 0;
}
else{
while(no->next!=NULL){
no=no->next;
}
no->next=(node_t*) malloc(sizeof(node_t));
no->next->element=entry_dup(entry);
no->next->next = NULL;
list->size=list->size+1;
return 0;
}
return -1;
}
The problem is that the previous node needs to know the address of the next one, via the pointer next. In your case, no->next will be equal to NULL (after the loop), so it's the last node. You never assign the next pointer of the last node to the new node, so it will be lost.

trouble updating tail pointer in queue adt using singly linked list

i am trying to make a queue library that is based on a linked list library i already made. specifically i am having troubles updating the tail pointer in the queue structure after i add a new node to the linked list.
linked list structure:
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
queue structure:
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
so here is my add function in the queue library
void add(queue currentQueue, int data){
addTail(currentQueue.list, data, data+5);
currentQueue.back = currentQueue.back->next;
}
and the addTail function from the linked list library
void addTail (node *head, int value, int length) {
node *current = head;
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
while (current->next != NULL)
current = current->next;
newNode->next = NULL;
current->next = newNode;
}
so again my problem is the tail pointer is not getting set to the last node in the list. it is remaining in the same place as the head pointer. ive been researching this for hours trying to see if im just missing something small but i cant find it. if more code or explanation is needed to understand my problem i can provide it.
how a queue is created:
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
node *initNode (int value, int length){
node *newNode = NULL;
newNode = (struct listNode *)malloc(sizeof(node));
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
return newNode;
}
void add(queue currentQueue, int data){
You are passing a copy of the queue struct to add, so only the copy's members are changed. You need to pass a queue* to the function to be able to change the members of the queue itself.
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
and call it as add(&your_queue);
In your addTail function, you should check whether head is NULL too.
And with
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
in addTail, you have a serious problem. With the assignment newNode = initNode(value, length);, you are losing the reference to the just malloced memory.
If initNode mallocs a new chunk of memory, it's "just" a memory leak, then you should remove the malloc in addTail.
Otherwise, I fear initNode returns the address of a local variable, à la
node * initNode(int val, int len) {
node new;
new.nodeValue = val;
new.nodeLength = len;
new.next = NULL;
return &new;
}
If initNode looks similar to that, that would cause a problem since the address becomes invalid as soon as the function returns. But your compiler should have warned you, if initNode looked like that.
Anyway, without seeing the code for initNode, I can't diagnose the cause.
But if you change your addTail to
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
it should work.
However, since you have pointers to the first and the last node in the list, it would be more efficient to use the back pointer to append a new node,
void add(queue *currentQueue, int data){
node *newNode = malloc(sizeof *newNode);
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = data;
newNode->nodeLength = data+5;
newNode->next = NULL;
currentQueue->back->next = newNode;
currentQueue->back = newNode;
}
since you needn't traverse the entire list to find the end.
A simple sample programme
#include <stdlib.h>
#include <stdio.h>
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
int main(void) {
queue myQ = createQueue(10);
for(int i = 1; i < 6; ++i) {
add(&myQ, i);
printf("list: %p\nfront: %p\nback: %p\n",
(void*)myQ.list, (void*)myQ.front, (void*)myQ.back);
}
node *curr = myQ.front->next;
while(curr) {
printf("Node %d %d, Back %d %d\n", curr->nodeValue,
curr->nodeLength, myQ.back->nodeValue, myQ.back->nodeLength);
curr = curr->next;
}
while(myQ.list) {
myQ.front = myQ.front->next;
free(myQ.list);
myQ.list = myQ.front;
}
return 0;
}
works as expected, also with the alternative add implementation.
i think you never initialized back, so back->next is some random pointer?

Resources