Creating a linked list in C - c

I am currently trying to make a linked list and initialize it within a function. It looks like this:
void add_forest(node_t *head, unsigned char value)
{
int key;
node_t *current = head;
while (current->next != NULL)
{
current = current->next;
}
}
int main()
{
node_t *head;
*head = init_forest(); //error here
}
I am currently getting a segfault at the following area in my code and can not figure out why. I am creating the head in init_forest() and then passing back in the main. When I go through the init_forest() the tree does become built. Any suggestions?

The immediate problem is in main():
node_t *head;
*head = init_forest();
head is an uninitialized pointer; you can't dereference it, and you don't actually want to. You should be using:
node_t *head = init_forest();
But you then need to ensure that init_forest() returns a node_t *, rather than a node_t value. This is the more orthodox style for such linked list management functions. You allocated the structure in the function; if you return a copy of the structure rather than a pointer to the structure, you're leaking memory (and you end up with other problems later).

Related

Add node to multilevel linked list

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.

copying a struct in a function and returning the copy in c

I am implementing a queue using a generic linked list in C where each node in list is a simple struct which contains a void pointer and a node pointer to the next node. In the dequeue operation I want to remove the head (which is working fine), but I also want to return that node after it is removed.
EDITED TO CLARIFY
What i did in the dequeue function is (example):
//This is my queue struct
typedef struct Queue{
LinkedList* list;
size_t item_size;
} Queue;
//this is the dequeue function
Node* dequeue(Queue* queue){
Node* head = queue->list->head;
Node* returnedValue = (Node*)malloc(sizeof(Node));
memcpy(returnedValue, head, sizeof(Node));
removeBegin(queue->list);
return returnedValue;
}
//this is the remove head function
void removeBegin(LinkedList* list){
Node* tempHead = list->head;
list->head = list->head->next;
tempHead->next = NULL;
free(tempHead->value);
tempHead->value = NULL;
free(tempHead);
tempHead = NULL;
}
the problem is everything before the free function is ok. Everything is being copied correctly. But immediately after the free function call the value that is copied to the newly allocated node becomes garbage (or 0).
The way I call the function is simply initialize the queue using this function:
Queue* init_queue(size_t size){
Queue* queue = (Queue*)malloc(sizeof(Queue));
// int x = 10;
queue->list = createList(NULL, size);
return queue;
}
then call dequeue and pass it the pointer of the queue.
How can I solve this?
thanks a lot.
The memory allocating using
Node* n1 = (Node*)malloc(sizeof(Node));
is uninitialised. This means that accessing the value of n1->value gives undefined behaviour. A consequence is that
memcpy(n1->value, n->value, sizeof(n->value));
also gives undefined behaviour.
When behaviour is undefined, the consequences of executing any further code could be anything. Your observation
newly allocated node becomes garbage (or 0)
is one possible outcome.
There are more problems as well. However, you haven't provided enough information (e.g. how is the function called? how is the pointer passed as n initialised? how is n->value initialised?) so it is not possible to give advice on how to FIX your function.

C linked list can't properly add data to list

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.

Linked List access violation in C

Im not sure i got the concept of Linked List properly. What im trying to do is to create a linked list which receives the integer 6 as it's first "data". instead i get this access violation error when trying to write in the integer into the first node's data. is there something specific i missed here?
///////////////////////////////
typedef struct List_Node
{
int data;
struct List_Node* next;
}List_Node;
typedef struct List
{
List_Node* head;
}List;
////////////////////////////////
List* create_list();
void print_list(List_Node *x);
void add_to_node(List_Node *a,int val);
////////////////////////////////
void main()
{
List *a = create_list();
List_Node *ind = a->head;
printf("List:\n");
add_to_node(ind,6);
}
void print_list(List_Node *a)
{
while(a != NULL)
{
printf("%d \n",a->data);
a = a->next;
}
return;
}
void add_to_node(List_Node *a,int val)
{
a->data = val;
}
struct List* create_list()
{
struct List* list = (List*) malloc(sizeof(List));
list->head = NULL;
return list;
}
The code is dereferencing a NULL pointer as a->head is NULL:
list->head = NULL; /* inside create_list()` and 'list' returned to ...*/
List_Node *ind = a->head; /* ... inside main(), and then passed to */
add_to_node(ind,6); /* add_to_node() ... */
a->data = val; /* and dereferenced inside add_to_node(). */
Dereferencing a NULL pointer is undefined behaviour. To correct, malloc() memory for a List_Node and assign to a->head. Recommend creating an add_node() function that allocates memory and assigns the new int value to newly malloc()d node.
Do I cast the result of malloc?
As all have pointed out, you are dereferencing a NULL pointer as your list->head contains NULL.
Another thing I should point out is that, you are creating a List. but not any Node. There is no node in the list. You have to allocate memory for a Node and then use it.
So, instead of add_to_node(), you may use a function add_node that will take the list or the head and the value as parameters, create a node(i.e. allocating memory for the node), set the value and add it to the list.
Also, in your case, the structure List is redundant as it contains only one member. instead you can simply use List_node* head.
What you are doing:
In create_list:
Allocating memory for a List pointer.
Setting the list's head to NULL.
In add_to_node:
Setting the specified node pointer's data element to the specified val.
In main:
Creating a List pointer a by calling create_list. This list has a NULL head.
Initializing a List_Node pointer, ind, to point to the created list's head (which is NULL).
Trying to set ind's data element to 6 by calling add_to_node.
This is where your program is causing the access violation exception.
ind = NULL. Therefore NULL->data = undefined behaviour.
What you should be doing:
In create_list:
Allocate memory for a List pointer, say linked_list.
Allocate memory for linked_list's head pointer.
For the linked_list's head, initialize data and the next pointer to 0 and NULL respectively.
In add_to_node:
Do the same thing you're doing now.
In main:
Create a List pointer a by calling create_list. Now, this list will have a valid, initialized NULL head, but with no meaningful data.
Set the list's head data by calling add_to_node(a->head, 6);.
Note: This will only ensure you have a head node in your list. Nowhere are you creating additional nodes.

Delete Linked List Function

Here's my function to delete a linked list:
void deleteList( NODE* head )
{
NODE* temp1;
NODE* tempNext;
temp1 = head;
tempNext = NULL;
while( temp1 != NULL )
{
tempNext = temp1->next;
free(temp1);
temp1 = tempNext;
}
}
So temp1 first points where the head pointer is pointing. If it isn't NULL, tempNext will be set to point to the next element of the list. Then the first element (temp1) is free'd, and temp1 is reassigned to point to where tempNext is pointing and process repeats.
Is this the right approach to deleting an entire list?
I ask this because when I print the list after using this function, it still prints the list. And IIRC freeing something doesn't delete it but only marks it as available so I'm not sure how to tell if this is correct or not.
Your code looks correct.
You're also correct that freeing a list's elements doesn't immediately change the memory they pointed to. It just returns the memory to the heap manager which may reallocate it in future.
If you want to make sure that client code doesn't continue to use a freed list, you could change deleteList to also NULL their NODE pointer:
void deleteList( NODE** head )
{
NODE* temp1 = *head;
/* your code as before */
*head = NULL;
}
It still print the list, because you probably don't set the head pointer to NULL after calling this function.
I ask this because when I print the list after using this function, it still prints the list.
There is a difference between freeing a pointer and invalidating a pointer. If you free your whole linked list and the head, it means that you no longer "own" the memory at the locations that head and all the next pointers point to. Thus you can't garintee what values will be there, or that the memory is valid.
However, the odds are pretty good that if you don't touch anything after freeing your linked list, you'll still be able to traverse it and print the values.
struct node{
int i;
struct node * next;
};
...
struct node * head = NULL;
head = malloc(sizeof(struct node));
head->i = 5;
head->next = NULL;
free(head);
printf("%d\n", head->i); // The odds are pretty good you'll see "5" here
You should always free your pointer, then directly set it to NULL because in the above code, while the comment is true. It's also dangerous to make any assumptions about how head will react/contain after you've called free().
This is a pretty old question, but maybe it'll help someone performing a search on the topic.
This is what I recently wrote to completely delete a singly-linked list. I see a lot of people who have heartburn over recursive algorithms involving large lists, for fear of running out of stack space. So here is an iterative version.
Just pass in the "head" pointer and the function takes care of the rest...
struct Node {
int i;
struct Node *next;
};
void DeleteList(struct Node *Head) {
struct Node *p_ptr;
p_ptr = Head;
while (p_ptr->next != NULL) {
p_ptr = p_ptr->next;
Head->next = p_ptr->next;
free(p_ptr);
p_ptr = Head;
}
free(p_ptr);
}

Resources