linked list operations (core dumped) - c

Recently I've been improving my programming skills by coding different data structures, and this is the very beginning!!!
Now I'm writing the linked list, but something annoyed happen and the trouble has been annoyed me for a long time since I am not quite sure about this error,
Segmentation fault(core dumped), but I did know I made something wrong in the operation of memory.
link_list.h:
struct LINK_LIST {
char *string;
struct LINK_LIST *next;
}link_list;
==============================
link_list.c:
#include<stdio.h>
#include<stdlib.h>
int init_link_list(struct LINK_LIST *new_link) {
//char *new_string;
int i;
//new_string = (char *)malloc(sizeof(char) * STRING_SIZE);
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return ERROR;
}
//new_link->string = new_string;
new_link->string = NULL;
//new_link->next = NULL;
return OK;
}
Here I defined the init operation, then the insert operation:
int insert(struct LINK_LIST *link, int pos, char *in) {
int i;
if (get_length(link)>=STRING_SIZE) {
fprintf(stderr, "Link list is full!!!");
return ERROR;
}
else {
if (pos < 0 || pos-1 > get_length(link)) {
fprintf(stderr, "Invalid position");
return ERROR;
}
else {
i = 0;
do {
struct LINK_LIST *new_node;
init_link_list(new_node);
new_node->next = link->next;
link->next = new_node;
new_node->string = in;
i += 1;
} while(i<pos-1);
}
}
return OK;
}

You have a bug there :
struct LINK_LIST *new_node;
init_link_list(new_node);
In init_link_list, the value of the argument is modified :
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
but that modification is only local to the function ; once you get back to your calling function, that change is lost :
struct LINK_LIST *new_node;
init_link_list(new_node);
// Oops ! new_node's new value is lost !
You have a memory leak (the malloc's result is lost) and new_node is not initialized. When you try to access *new_node, you access a random position in memory, hence core dumps.
There are a few possible corrections, the easiest is to discard your OK/ERROR return values and return either a non-null pointer if malloc succeeded, or NULL if it failed :
struct LINK_LIST *init_link_list(void) {
struct LINK_LIST *new_link = malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
new_link->next = NULL;
return new_link;
}
Then, code in insert becomes :
...
else {
i = 0;
do {
struct LINK_LIST *new_node = init_link_list();
// Note : here, should check whether new_node is NULL and deal with the situation
new_node->next = link->next;
link->next = new_node;
...

Related

Linked list in c adding to beginning of the list

Im trying to create a simple programme to add a value to a linked list.
the code does compile with out errors.
Im getting a segmentation fault when trying to execute the file.
I tried to debug using printf statements, but I don't get any output anywhere.
could someone point out what im doing wrong.
typedef struct in separate .h file, include files also in separate .h file
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
void list_push_front(t_list **begin_list, void *data)
{
t_list *l;
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
l->data = data;
l->next = *begin_list;
*begin_list = l;
printf("%s\n", l->data);
}
int main(void)
{
t_list *k;
k = (t_list*)malloc(sizeof(t_list));
if(k == NULL){
printf("No allocation");
}
printf("allocation");
char s[] = "Woow!";
k->data = "Hello";
k->next->data = NULL;
// k->next->next->data = NULL;
list_push_front(&k, s);
return(0);
}
In the printf call
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
you are trying to output non-initialized memory pointed to by the pointer l->data. So the function invokes undefined behavior. Remove this call of printf. It does not make sense.
Also in main this statement
k->next->data = NULL;
is incorrect and also invokes undefined behavior. It seems you mean
k->next = NULL;
As a general point, always compile with the -Wall -Werror flags and run your code frequently (every couple of lines). This should help avoid a lot of the problems here. Use valgrind, asan or gdb to detect and diagnose memory issues like the ones in this program.
k->next->data = NULL; is illegal because k->next is uninitialized.
printf("%s\n", l->data);, same problem. You must initialize a value before use.
Functions should not produce side effects like printing. It's OK for temporary debugging, but beyond that it makes for noisy programs and essentially unusable functions. If you want errors, print to stderr and exit or use return values such as an enum or NULL to indicate errors.
Always free allocated memory.
No need to cast the result of malloc.
Use consistent indentation and formatting.
A possible rewrite:
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
struct ListNode *next;
void *data;
} ListNode;
ListNode *list_create(void *data) {
ListNode *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s %d: malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->data = data;
node->next = NULL;
return node;
}
void list_push_front(ListNode **head, void *data) {
ListNode *node = list_create(data);
node->next = *head;
*head = node;
}
void list_free(ListNode *head) {
while (head) {
ListNode *dead = head;
head = head->next;
free(dead);
}
}
int main(void) {
ListNode *list = list_create("a");
list_push_front(&list, "b");
list_push_front(&list, "c");
for (ListNode *curr = list; curr; curr = curr->next) {
printf("%s\n", (char *)curr->data);
}
list_free(list);
return 0;
}

Segmentation fault accessing struct member

I've been learning C and am having problems using linked lists. When looping over a pointer to a linked list I run into segmentation faults and I'm not sure why.
Looking at similar questions the suggestion is to allocate the memory, but I find this answer confusing. Do you have to use heap memory for linked lists, and if so why?
Here is my code:
#include <stdio.h>
typedef struct Node {
char *name;
struct Node *next;
} Node;
typedef struct Thing {
Node *node;
} Thing;
Thing make_thing()
{
Thing t = {
.node = NULL
};
return t;
}
Thing * add_node(Thing *t, char *name)
{
Node node = {
.name = name,
.next = t->node
};
t->node = &node;
return t;
}
void print_nodes(Thing *t)
{
Node *n = t->node;
while(n != NULL) {
printf("Node: %s\n", n->name);
n = n->next;
}
}
int main()
{
printf("Start\n");
Thing t = make_thing();
add_node(&t, "one");
printf("First %s\n", t.node->name);
print_nodes(&t);
return 0;
}
You are using objects with automatic storage out of their scope:
Node node = {
.name = name,
.next = t->node
};
t->node = &node;
return t;
Here you leak the pointer &node, which is invalid (out of scope) after the return, to the caller and use it here:
printf("First %s\n", t.node->name);
You have to allocate memory by using malloc() for your Node structure.
Example:
Node *node = malloc(sizeof *node);
node->name = name;
node->next = t->node;
t->node = node;
return t;
You have to care about freeing the memory when it is no longer used to prevent memory leaks.

Why is `pLQ->tail` a null pointer?

I am working on an a queue and keep running into problems with enqueuing. Here is what I believe to be the relevant code:
typedef struct Qnode QNODE;
struct Qnode
{
int length;
QNODE* next;
QNODE* prev;
};
typedef struct lqueue lQUEUE;
struct lqueue
{
QNODE *head;
QNODE *tail;
};
lQueue lqueue_init_default(void)
{
lQUEUE* pQ = NULL;
pQ = (lQUEUE*)malloc(sizeof(lQUEUE));
if (pQ != NULL)
{
pQ->head = NULL;
pQ->tail = NULL;
}
pQ->head = pQ->tail;
return pQ;
}
Status lqueue_henqueue(lQueue* hLQ, int lc)
{
lQUEUE* pLQ = (lQUEUE*)hLQ;
QNODE* new = (QNODE*)malloc(sizeof(QNODE));
if (new == NULL)
{
printf("Couldn't allocate space.\n");
return FAILURE;
}
new->length = lc;
new->next = pLQ->tail->next;
pLQ->tail = new;
return SUCCESS;
}
Whenever I try to run the program, I get this error during run time:
Exception thrown: read access violation.
pLQ->tail was nullptr.
Why is it a null pointer? Does it have to do with the Initialization function?
Here is how it is called:
int cl = 0;//Individual car length
lQueue hLQ = lqueue_init_default();//Handle to the left queue
printf("Enter the length of the lcar:\n");
scanf("%d", &cl);
lqueue_henqueue(hLQ, cl);
Your code is highly prone to undefined behavior... Look at this if statement:
if (pQ != NULL)
{
pQ->head = NULL; // This pointer is now 'NULL'
pQ->tail = NULL; // This is also 'NULL'
}
Which should be this...
if (pQ != NULL)
{
pQ->head = (QNODE*)calloc(1, sizeof(lQUEUE)); // This is proper pointer initialization...
pQ->tail = (QNODE*)calloc(1, sizeof(lQUEUE));
}
And this:
lQueue lqueue_init_default(void)
should be this:
lQueue * lqueue_init_default(void) // Since you are returning a pointer...
You will see that the code works fine because there is no undefined behavior...
Note that you can never access an object that is assigned to NULL... (Only if you don't want your program to behave undefined...) So, this:
pQ->tail = NULL;
is not safe in the very least... Structural pointers being assigned to NULL are usually only seen when being destroyed... An example is given below...
Also, unrelated, but have a destructor for the structure and call it when you don't need the structure anymore, or it will leak the memory afterwards...
void destroy_lqueue(struct lqueue ** queue)
{
if (queue != NULL)
queue = NULL;
free(queue);
}

Passing a new node to a pointer within a structure

I'm having these two structures:
typedef struct node {
int info;
struct node *left, *right;
}NODE;
typedef struct bst {
NODE *root;
}BST;
And these functions:
NODE *newNode(int info) {
NODE *tmp = (NODE *)malloc(sizeof(NODE));
tmp->left = tmp->right = NULL;
tmp->info = info;
return tmp;
}
void addTree(BST **bst, int info) {
if (*bst == NULL) {
(*bst)->root = newNode(info); // <- Breaks the program
return;
}
else while ((*bst)->root != NULL) {
if (info < (*bst)->root->info)
(*bst)->root = (*bst)->root->left;
if (info >(*bst)->root->info)
(*bst)->root = (*bst)->root->right;
}
(*bst)->root->info = info; // <- Breaks the program
}
I can't figure out what have I've done wrong.
I'm calling the function like this in the main function:
addTree(&binST, tmp);
I've used the debugger and it gives me not a single error or warning.
Any help would be appreciated.
if (*bst == NULL) {
(*bst)->root = newNode(info); // <- Breaks the program
Excatly problem lies here , as *bst is NULL then in next line you dereference it (as you try to access struct member) which causes undefined behaviour and crash in your case .
You need to allocate memory to *bst before access members of the structure. Like this -
if (*bst == NULL) {
*bst=malloc(sizeof(BST)); //allocate memory first and then access struct members
(*bst)->root = newNode(info);
Note - Remember to free allocated memory.

linked-list queue, endless loop

I use nested structure to define the linked-list queue:
queue.h:
#define QUEUE_MAX_SIZE 4096
struct QUEUE_NODE {
char *string;
struct QUEUE_NODE *next;
}queue_node;
struct COMMON_QUEUE {
struct QUEUE_NODE *q_node;
}common_queue;
=================================
queue.c:
/* here I define the operations */
struct COMMON_QUEUE *C_init_queue() {
struct QUEUE_NODE *head;
head = malloc(sizeof(struct QUEUE_NODE));
if (head==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
struct COMMON_QUEUE *new_queue;
new_queue = malloc(sizeof(struct COMMON_QUEUE));
if (new_queue==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
head->next = NULL;
head->string = NULL;
new_queue->q_node = head;
return new_queue;
}
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
return count;
}
int C_enqueue(struct COMMON_QUEUE *q, char *in) {
if (C_get_queue_length(q)>=QUEUE_MAX_SIZE) {
fprintf(stderr, "Linked queue is full!!!");
return ERROR;
}
struct QUEUE_NODE *new_node;
new_node = malloc(sizeof(struct QUEUE_NODE));
if (new_node==NULL) {
return ERROR;
}
new_node->next = NULL;
new_node->string = NULL;
while (q->q_node->next!=NULL) {
q->q_node = q->q_node->next;
}
new_node->next = q->q_node->next;
q->q_node->next = q->q_node;
new_node->string = in;
return OK;
}
but when I use it in the main program, then it jumps into a endless loop, after backtracing, and I knew the problem is at:
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
but it seems correct, but I may make some mistake on my initialization of the two nested struct!
P.S. the I did not list the "free()".
This loop modifies the list while it traverses it. Specifically, it replaces q->q_node with q->q_node->next, which if nothing else will discard your entire loop.
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
If you want to correctly traverse the list, you need to declare a separate pointer that you use for traversal. Something like this:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
struct COMMON_QUEUE *p = q->q_node;
count = 0;
while (p->next != NULL) {
count += 1;
p = p->next;
}
return count;
}
The pointer p will step along the list without modifying the q_node pointers along the way.
You have a similar error in C_enqueue. You really want to use a separate pointer to walk the list, and not assign q->q_node during traversal. You can fix your C_enqueue similarly:
p = q->q_node;
while (p->next != NULL) {
p = p->next;
}
p->next = new_node; /* append the new node after where the list traversal stopped */
new_node->next = NULL; /* always NULL, because you always insert at the end */
One problem with your code is that your iterations through the queue are destructive: rather than using a temporary variable to iterate your linked list, you perform the iteration using the q_node itself. This leads to C_get_queue_length calls effectively destroying the queue, without freeing its nodes (a memory leak).
Here is an example of how to iterate a list non-destructively, using your "get length" method:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
struct QUEUE_NODE node = q->q_node;
while (node->next != NULL) {
count++;
node = node->next;
}
return count;
}
Your decision to pre-allocate one node when creating a queue is also questionable: it appears that the head node is unused, and also excluded from the count. This makes it easier to write the code to insert and delete nodes, but the same could be done with an extra level of indirection (i.e. a pointer to a pointer).

Resources