I am attempting to construct my first linked list, and having read a basic introduction, have done the following. Firstly, declare a linked list node as:
struct errorNode {
uint8 error;
struct errorNode* next;
};
Secondly, define the first node globally as:
struct errorNode errorList = {0, NULL};
This has been done to allow each of the libraries that make up my current project to insert errors into a common list. The function to do this is:
void errorListWrite(uint8 error) {
struct errorNode* newNode = malloc(sizeof(struct errorNode));
newNode->error = error;
newNode->next = &errorList;
errorList = *newNode;
}
Whilst this compiles without error, it does not function as expected. I thnk the problem is with the last two statements of the list write function, but I am unsure. A hint as to what I am doing wrong would be most appreciated.
The problem is that you create a circular list.
newNode->next = &errorList;
So newNode links to the global node.
errorList = *newNode;
This is equivalent to errorList.error = newNode->error; errorList.next = newNode->next;.
So now errorList links to the global node. Oops.
What you could do instead, is insert the new node after the global node in the list:
newNode->next = errorList.next;
errorList.next = newNode;
This is assuming that you want a global node at all. If you don't, then you could start with struct errorNode *errorList = 0;, and add a new node like this:
newNode->next = errorList;
errorList = newNode;
When you come to use the list, your list-traversal may look a little different. With a global pointer-to-node you'll start with a pointer to the first node, that you must check for null before using. With a global node you'd start with a node that definitely exists, but whose next pointer might be null.
Well, the problem is with the last line: you are just overwriting the data in in the old error node!
What you probably need is to have the head (pointer to the first node) globally accessible, not the first node itself. This way you don't need a fake entry in your list.
(Be warned that your code is not thread-safe.)
Code:
errorNode* pGlobalErrorList = NULL;
// in errorListWrite
newNode->next = pGlobalErrorList;
pGlobalErrorList = newNode;
Your head (errorList) should be a pointer and should be initialized to NULL unless you have a need for the initial entry of a node with a value of 0:
struct errorNode* errorList = NULL;
Then your function needs to reassign errorList properly.
void errorListWrite(uint8 error) {
struct errorNode* newNode = malloc(sizeof(struct errorNode));
newNode->error = error;
newNode->next = errorList;
errorList = newNode;
}
This is all assuming your new node will be the new head of the list, and not the new tail.
errorList should be a pointer to first node (not the first node)
also you need to know what is the last node this will be modified
the head of list will not be modified, it will be used only when you want to travel from the beginning of list.
Related
I apologize for this noob question but I'm really struggling with this. I have a linked list with two different links: Next and sort. I want to add to the front with next but add in increasing order to sort. However whenever I try and add to sort I get a segfault and I'm not sure how I'm supposed to access them in a way that they act as two distinct linked lists with the same data but in a different order.
this is my list:
typedef struct NODE {
value_t value;
key_t key;
struct NODE * next;
struct NODE * sort;
} Node;
and this is how I'm trying to write to it
Node * add_sorted(Node ** head, int value, key_t key){
Node *new_node = malloc(sizeof(Node));
if (new_node != NULL) {
new_node->sort->value = value;
new_node->sort->key = key;
new_node->sort = *head;
*head = new_node;
}
return new_node;
}
thank you in advance for enduring my ignorance
You are trying to assign value to somewhere that you did not initialize in address space.
new_node->sort->value = value;
new_node->sort->key = key;
In this part, you did not create *sort but it is declared like it is there. Creating new_node does not mean there is a *sort. Because it is a pointer. In this case, it does not point anywhere but void.
I do not know if it is related to your problem but I think you need to solve that one too.
Hope it helps.
In adding, new_node->sort = *head; doesn't have any sense. Because, previous setting of attribute sort will be erased.
first you are assigning value to a pointer without allocating memory for it or initializing it.
this should work:
if (new_node != NULL) {
new_node->sort = malloc(sizeof(Node));
new_node->sort->value = value;
new_node->sort->key = key;
new_node->sort = *head;
*head = new_node;
}
also note that your function argument int value has different type from the member you are assigning it to.(value_t value)
also I think here new_node->sort = *head; you meant new_node->next = *head; ,because with this assignment data ,you assigned to fields of sort will be lost.
I'm trying to create a singly linked list with nodes containing two parameters. Whenever I enqueue another node using the tail pointer, the head pointer takes the same value as the new node.
I'm sure the pointers are pointing to the same memory location or something similar, but I'm not sure how to fix this.
struct node
{
struct process *p;
struct node *next;
}
struct node* head;
struct node* tail;
void enqueue(struct process* newProcess)
{
struct node *newNode = malloc(sizeof(struct node));
newNode->p = malloc(sizeof(struct process));
newNode->p = newProcess);
if(tail==NULL)
{
head = tail = newNode;
return;
}
tail = tail->next;
tail = newNode;
}
I'd like to use this function to be able to create a singly linked list with the head node pointing to the first element in the list and the tail node pointing to the last element in the list. The current code results in both variables representing the last element added.
Setting tail = tail->next is setting tail to null because it isn't set the first time around, and then both tail and head are immediately overwritten in the subsequent call.
There are some issues here. First, to fix your problem, replace the two last lines with:
tail = tail->next = newNode;
Also, consider this:
tail = tail->next;
tail = newNode;
What is the point of assigning a variable to a value if you reassign the same variable in the next statement? You have the same error earlier on too:
newNode->p = malloc(sizeof(struct process));
newNode->p = newProcess;
Because of the second line, the only thing you achieve with the first line is a memory leak. Remove the first line completely.
For my program, I need to create a function that accepts a linkedlist as a parameter, then deletes the first node from the list. There are other steps, but I'd like to get this sub-part done first.
This is what I have so far:
struct node *del_the_first(struct node *head) {
struct node *temp = head;
head = head->next;
temp->next = NULL;
return NULL;
}
I believe my solution is correct, however I have no way of testing it at this time. I'm more interested in why I am or am not wrong.
What you should test is:
print the value of temp at the end of the function,
this is what head was at the start of the function
print the value of head at the end of the function,
which is what the head of the list should be after returning for the function
print (from outside the function, e.g. from main) the value of the variable
which is supposed to point to the head of the list,
especially after deleting the first element
You will notice that outside your function the pointer to the head of the list is still pointing to where the first element still is.
You do not want that, do you? The variable which points to the head of the list is supposed to point to the second element of the list, isn't it?
If above is true, you probably want to use free() on the formerly first element of the list, before returning from the function.
Read this for more information on how to fix the first problem:
Parameter Passing in C - Pointers, Addresses, Aliases
Basically, you will want to return the new value of the pointer to the head of the list:
struct node *del_the_first(struct node *head)
{
struct node *temp = head;
head = head->next;
temp->next = NULL; /* not really needed */
free(temp);
return head;
}
Then call it like:
global_head = del_the_first(global_head);
Note that this code assumes that the list is not empty,
see the answer by ccpan on how to remove this assumption.
You need to check for boundary conditions. Suppose your linkedList is empty, then during runtime, you will get a segmentation fault. So you need to check if head pointer is NULL or not before trying to access next node.
Also, I don't know why you are returning a NULL. You are most probably wanting to return the new head node pointer.
struct node *del_the_first(struct node *head) {
if (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
temp = NULL;
}
return head;
}
Bit of a lengthy question so please bear with me. I am trying to create a doubly linked list in C using a dummy node as the head. For whatever reason, however, the list only saves the last node I read into it, and links the prev node pointer and the next node pointer to that last node, so if I try and iterate over the list, it gets stuck in an infinite loop.
Here is my node header file and C file. The linked list implementation isn't meant to be a full linked list implementation, so I only included the functions I need:
node.h:
#ifndef _node_h
#define _node_h
#include "task_block.h"
#include <stdio.h>
typedef struct node {
task_block_type *data;
struct node *next;
struct node *prev;
}node_t;
node_t *node_new(task_block_type *data);
void add(node_t *new, node_t *head);
#endif
node.c:
#include "node.h"
#include "task_block.h"
#include <stdlib.h>
node_t *node_new(task_block_type *data) {
node_t *node = NULL;
node = malloc(sizeof(node_t));
node->data = data;
node->next = NULL;
node->prev = NULL;
return node;
}
void add(node_t *new, node_t *head) {
node_t *current = head;
if (head->next == NULL) {
head->next = new;
head->next->prev = head;
return;
}
while(current->next != NULL) {
current = current->next;
}
current->next = new;
current->next->prev = current;
return;
}
And finally, the code that is messing up from main.c:
while (j < numTasks) {
if (tasks[j].taskID == currentID) {
*newTask = *task_block_new(tasks[j].taskID, tasks[j].period);
newTask->startTime = starts[i];
newTask->deadline = deadlines[i];
newTask->executionTime = executions[i];
*nodeNew = *node_new(newTask);
add(nodeNew, eventQueue);
}
I have already tested that my new task_block_type get the correct data form the text file and that the new node I create is initialized properly with the task block. Once I read it into my list with add(), however, it messes up. Any help would be greatly appreciated as I've been trying to fix this problem for several hours now and still haven't found a solution
EDIT:
self contained example:
*node_new is meant to be a constructer for my node objects and is supposed to return a pointer to a node object. So for example, say instead of having a node which contains the task_block_type as above, I have one that contains an int. If I wanted to initialize it with a value of 5, I would call
*newNode = (node_t *)malloc(sizeof(node_t));
*newNode = *node_new(5);
Hope that helps
Change this:
*nodeNew = *node_new(newTask);
To this:
nodeNew = node_new(newTask);
Your original code copies the (dereferenced) value returned by node_new() to the value at (dereference of) *nodeNew. Thus, the pointer nodeNew never gets updated with the address of the new node created by node_new()... so you keep overwriting the value at *nodeNew while passing its unchanging address to add().
And you get a memory leak into the bargain. You are responsible for free()ing every pointer ever returned to you by malloc(). But here, for the same reason given above, you're not keeping copies of the returned pointers to enable this... just linking to nodeNew over and over again.
You need to update the pointer nodeNew with the location of, well, each new node, before passing it on to add(). Then you'll actually be linking different nodes, and at their original addresses, rather than copying them to the same address in a leaky fashion and linking it to itself, infinitely.
You also need to free() all memory that you have dynamically allocated once you're finished using it, e.g. through a sweep of the linked list in a 'destructor' function or at the end of your program. Otherwise you're leaking memory. This is a basic error and, even in cases where it doesn't stop a program from working, wastes users' RAM, which they rightly dislike!
I highly recommend studying pointers and dynamic allocation some more before continuing trying to write code like this.
Updated with some new details:
Interestingly if I get no segfault if I don't use: node->next = NULL. I can create the nodes fine, but it seems there's an issue in setting the initial list head to my new node, as well as dereferencing ->next.
Note that without the structure definitions, it make be a bit harder for us to know what is wrong...
You have a problem here where you use the allocated pointer before testing whether the malloc() failed. Although that's probably not the culprit at this point.
struct node *head = (struct node*)malloc(sizeof(struct ftt_node));
foodList->head = head; // <<<---- here using the pointer NULL or not
head->next = NULL;
rest->foods = foodList;
if (NULL == rest->foods) { // <<<---- testing here if malloc() failed
printf("List creation failed");
return FALSE;
}
As a side note, the head pointer has the same problem.
Then in add_node you do that, with newNode never allocated... so probably garbage!
struct node *newNode;
newNode->data = newFood;
You probably wanted to allocate newNode and use curr to find the last existing node.
Something like this:
void add_node(POS * POS, struct food * newFood)
{
struct node *newNode;
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = newFood;
curr = POS->foods->head;
while (curr != NULL)
{
curr = curr->next;
}
curr->next = newNode;
newNode->next = NULL;
}
That being said, I would very strongly suggest that you create a base list object with functions to handle the list, and then start your node with that list, instead of writing it this way.
As a side note: You should NOT name the variable POS in your add_node(). That's bad practice as it shadows your variable type.
Just wondering, why not use C++? At least testing for NULL is not required because new throws if memory cannot be allocated... And for list you have std::list, although in your case std::vector would probably work better so you could go through your array of nodes with a very simple for().
Your newNode variable in add_node is unitialised so it can point anywhere in memory, which can be the cause of the segfault when you try to dereference it on the second line. In addition, you allocated a new struct node structure but overwrote its adress immediately. So your first few lines should be rewritten thus:
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = newFood;
struct node *curr = POS->foods->head;
The add_node() function never modifies pos->foods->head. It also never initializes new_node, so that pointer cannot be dereferenced without triggering undefined behavior.
Thus, the list can never grow from being empty.