doubly linked list C implementation runtime error - c

Below is the C program I have written. It contains an implementation of the doubly linked list.
#include <stdio.h>
/* node of a doubly linked list */
typedef struct _dlnode {
struct _dlnode* prev;
int key;
struct _dlnode* next;
} dlnode;
/* doubly linked list */
typedef struct _dllist {
dlnode* head;
dlnode* tail;
} dllist;
/* returns an empty doubly linked list */
dllist* empty_dllist () {
dllist* l;
l->head=NULL;
l->tail=NULL;
return l;
}
int main()
{
dllist* l;
l=empty_dllist ();
return 0;
}
I get the following runtime error:
Segmentation fault: 11
What is it caused by?

You have to allocate memory for a structure before you use a pointer to it to access its members. Change your function empty_dllist to -
dllist *empty_dllist(void) {
dllist *l = malloc(sizeof *l);
if(l == NULL) {
// failed to allocate memory
// handle it
// return NULL
}
l->head = NULL;
l->tail = NULL;
return l;
}

A segmentation fault is usually caused by trying to follow an uninitialized or NULL pointer.
In your program, you have pointer variable l in the function empty_dllist, and you try to follow that pointer to what it points to. But the variable is uninitialized, and cointains garbage, so it is not surprising that you get a segmentation fault.
You probably want to add a call to malloc in empty_dllist, to allocate a header struct for your list.

You are not allocating memory:
dllist* l = malloc(sizeof(dllist));
so trying to access l->head causes error memory access

Related

Double free error with doubly linked list

So I'm trying to do a method to clear a doubly linked list for school where the doubly linked list and nodes are defined as:
struct word_entry
{
char *unique_word ;
int word_count ;
} ;
struct node
{
struct word_entry one_word ;
struct node *p_previous ;
struct node *p_next ;
} ;
struct linked_list
{
struct node *p_head ;
struct node *p_tail ;
struct node *p_current ;
} ;
I have a method to clear a linked list by doing
int clear_linked_list( struct linked_list *p_list ) //return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
}
else {
int count = 0;
struct node *curr = p_list->p_head;
while (curr != NULL) {
struct node *next = curr->p_next;
free(curr->one_word.unique_word);
free(curr);
curr = next;
count++;
}
return count;
}
}
I do a free() on curr->one_word.unique_word because it's a malloc'd char array. I was taught to free when I use malloc, so that's there.
The issue I run into is I get a "bogus pointer (double free?)" and a core dump when I run the test file provided by my professor. I've worked on this for a few hours and can't seem to find out where (or how) I'm calling free twice.
When you loop through the list, you should constantly change the position of the head, so that even if you repeat clear_linked_list, you will not get an error.
int clear_linked_list(struct linked_list* p_list) // return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
} else {
int count = 0;
while (p_list->p_head != NULL) {
struct node* curr = p_list->p_head;
p_list->p_head = p_list->p_head->p_next;
free(curr->one_word.unique_word);
free(curr);
count++;
}
return count;
}
}
When freeing memory it is a good practice to set NULL to pointers that were freed to avoid this kind of problems.
So you should do:
free(curr->one_word.unique_word);
curr->one_word.unique_word=NULL;
//if that one_word.unique_word was shared between multiples nodes that free could cause problems if you dont set it to NULL afterwards
free(curr);
curr=NULL; //or curr=next...
Also. Check that when you create the nodes that:
*p_next is NULL on the last node of the double linked list
*p_previous is NULL on the first node of the list
You don't null out p_head before you leave the clear function.
So, if you called it twice, you'd have problems (i.e. p_head would point to an already freed node). Likewise for p_tail.
Also, if you tried to add to the list again, you'd have similar problems.
Otherwise, your clear code is just fine.
So, can you prove that the list is constructed correctly (e.g. before you free, add a printf that prints out all the node's pointers before you free anything).

Linked List head not being updated across function calls

I trying to implement my own linked list and have been messing around with the code learning about dynamic memory allocation and pointers and such. When I try to add something to my linked list I get a segfault, and upon using the debugger I realized that it was because initially my linked list's head pointer was not pointing to null and then my add function was not recognizing the head as being empty. But I have an initialize function that is setting the linked list's head pointer to NULL but for some reason once I exit out of the initialize function and into the add function, the head is no longer pointing to NULL.
Here's my code:
list.h
typedef struct node{
int value;
struct node *next;
} Node;
typedef struct list{
Node *head;
} List;
list.c
void initialize(List *l){
if(l != NULL){
l = malloc(sizeof(List));
l->head = NULL;
}
}
void add(List *l, int a){
//Code
}
int main(){
List l;
initialize(&l)
add(&l, 2);
}
As soon as I step into the add function and print out *l, I see that the head is not pointing to 0x0. And I've been scratching my head as to why it's not. I thought it was something to do with pass by value but I don't think it is. What am I doing wrong here?
Yes, pass-by-value is your culprit. You are passing a pointer by value.
Suppose l in your main() is at address 0xABCD. Then your main() gets compiled to
int main(void) {
List l;
initialize(0xABCD);
add(0xABCD, 2);
}
and your initialize() call looks like this (suppose malloc() succeeds and allocates memory at address 0xCDEF:
void initialize(List *l) {
if(l != 0x0) {
l = 0xCDEF; // malloc()
l->head = 0x0;
}
}
That l = 0xCDEF does not propagate to main(), because l was passed by value.
What you want to do is
void initialize(List **l) {
if(l != NULL) {
*l = malloc(sizeof(List)); // note dereferencing the passed-by-value pointer
(*l)->head = NULL;
}
}
int main(void) {
List * l;
initialize(&l);
add(l, 2);
}
which will pass pointer to pointer to list (actually the address of the pointer in your main(). It allows the code in initialize() to change the l variable in main().
Alternatively, you can use
List * list_init() {
List * retval = malloc(sizeof(List));
if(retval == NULL) { // you should check malloc return value
// abort(), print warning or just
return NULL;
}
retval->head = NULL;
return retval;
}
int main(void) {
List * l = list_init();
if(l == NULL) {
// handle the error
}
add(l, 2);
}
You declare a List in main() that lives on the stack. You pass a pointer to that List to initailize(). You then create a new List on the heap. When you return from initialize() you still are using the List on the stack that you had in the beginning. The List on the heap is leaked and you cannot access it. So you never initialized the List you pass as a pointer to add(). You can forget about initialize() and just have
l.head = NULL;
instead.
Did you code compile this line l->malloc(sizeof(list)); seems odd.
Create a structure with only one argument is not really useful, a simple typedef should do the job : typedef Node* List

segmentation fault when trying to deference pointer : C

I was trying to implement circular queue functionality. I am a C++ coder and I found it surprising that in C, struct cannot have member functions. Anyway this is my implementation:-
#include <stdio.h>
#include <stdlib.h>
struct node
{
int nvalue;
struct node *next;
};
struct CLlist
{
struct node* head;
struct node* tail;
int size;
};
void insert(struct CLlist *l,int num)
{
struct node *n=malloc(sizeof(struct node));
n->nvalue=num;
n->next=NULL;
if((l->head==l->tail)==NULL)
{
l->head=l->tail=n;
}
else if(l->head==l->tail && l->head!=NULL)
{
l->head->next=n;
l->tail=n;
l->tail->next=l->head;
}
else
{
l->tail->next=n;
l->tail=n;
l->tail->next=l->head;
}
l->size++;
}
void print(struct CLlist *l)
{
int idno=1;
printf("printing the linked list with size as %d\n",l->size);
struct node *cptr;
for(cptr=(l->head);cptr!=(l->tail);cptr=cptr->next)
{
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
idno++;
}
//this is to print the last node in circular list : the tail node
idno++;
cptr=cptr->next;
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
}
int main()
{
struct CLlist a;
struct CLlist *l;
l=&a;
insert(l,2);
insert(l,5);
insert(l,7);
insert(l,10);
insert(l,12);
print(l);
return 0;
}
I get segmentation fault in the line
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
why does the error occur? I guess I am not passing l by pointer by value (passing pointers as by value) properly. could somebody help me in pointing out where I am going wrong?
Thanks
You never initialize the variable a in the main function, so its contents is indeterminate and using the members of that structure will lead to undefined behavior.
Your code has two issues, the first one more serious.
Your first issue is that the head and tail members of your CLlist structure are not being initialized to NULL, which can (non-deterministically) keep any real data from being stored in your structure. This can be fixed by adding the following 2 lines in main just before the first insert call:
l->head = NULL;
l->tail = NULL;
Your second problem is in this line:
if((l->head==l->tail)==NULL)
While it looks like this is comparing both l->head and l->tail to NULL, it's actually comparing l->head to l->tail, and then comparing that boolean result to NULL, which is effectively 0. The line should be changed to:
if((l->head == NULL) && (l->tail == NULL))
This will individually test both the head and tail pointers, and will only take that branch if they are both NULL.
You have a pointer
struct node *cptr;
// You're probably trying to access an unassigned pointer head in the next step
for(cptr=(l->head);cptr!=(l->tail);cptr=cptr->next)
As per the standards, there is no requirement that
a->head & a->tail are initialized to NULL
when you did
struct CLlist a;
Standard ISO/IEC 9899:201x clause 6.7.9->10 states
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
In fact you're:
struct CLlist a;
// missing something here.
struct CLlist *l;
l=&a;

C program acting weird

I've started implementing a circular queue in C, and I have the following lines of code:
#include <stdio.h>
#include <stdlib.h>
#include "cirq.h"
//allocate a circular queue
cirq cq_alloc(void){
cirq cq = NULL;
element *head;
element *tail;
if((head = malloc(sizeof(struct element*))) &&
(tail = malloc(sizeof(struct element *)))){
head->content = 0; // head node keeps track of size.
tail->content = NULL;
head->next = tail;
tail->next = head;
cq = &head;
} else {
printf("ERROR: No space for more cqueues.\n");
}
return cq;
}
int cq_size(cirq q){
return (int)(*q)->content;
}
int main(){
cirq q = cq_alloc();
printf("Size of element ptr %lu\n", sizeof(struct element *));
printf("%d\n", cq_size(q));
return 0;
}
Now when I compile and run this program, having commented out the line in main that prints out sizeof(struct element *)), the program runs fine and I get the right size of the queue, 0. When I leave the line in, the size of the struct is printed out, but after that I get a segmentation fault: 11. Also, to make things clear, the struct element has void *data and struct element *next fields. How can adding in a line that prints stuff change the behavior of the program so much?
EDIT: cirq.h
#ifndef CIRQ_H
#define CIRQ_H
typedef struct element **cirq; // cirq handle
typedef struct element {
void *content;
struct element *next;
} element;
extern cirq cq_alloc(void);// allocate a queue
extern int cq_size(cirq q);// return the size of a queue
extern void cq_enq(cirq q, void *value);// add a value to the queue
extern void *cq_deq(cirq q);// dequeue and return a queue value
extern void *cq_peek(cirq q);// return the value at the queue head
extern void cq_rot(cirq q);// requeue the head element at the tail
extern void cq_free(cirq q);// return all space allocated to queue
#endif
This is a bad smell:
if((head = malloc(sizeof(struct element*))) &&
You're mallocing the size of a pointer. I think you meant to malloc the struct itself...?
It doesn't really matter what cirq is, the fact that you return the address of a local object is the problem.
This here
cq = &head;
is causing the undefined behavior, because that's the address of the pointer head which is stored locally in the function only, when the function returns it's deallocated and thus invalid. Using it elsewhere (outside the function) is Undefined Behavior.
Also, do not typedef a pointer. Never do that, let the code reader know that it is a pointer.

Segmentation fault (core dumped) while running the program

#include<stdio.h>
#include<string.h>
#include<malloc.h>
//#include<conio.h>
struct list
{
char *value;
struct list *link;
};
struct list *arr[12];int val;
int hf(char *item)
{
int sum,i=0;
while(item[i]!='\0')
{
sum+=item[i];
i++;
}
return sum%12;
}
void insert(struct list ** arr,char *item,int val)
{
struct list *temp,*r;
r=*arr;
temp=(struct list *)malloc(sizeof(struct list));
strcpy((temp->value),item);
if(strcmp((r->value),NULL))
{
strcpy((r->value),(temp->value));
(r->link)=NULL;
}
else
{
while(r->link!=NULL)
r=r->link;
r->link=temp;
r=r->link;
strcpy((r->value),(temp->value));
r->link=NULL;
}
*arr=r;
}
void main()
{
struct list *li[12];int i=0;
for(i=0;i<12;i++)
{
li[i]=NULL;
}
char *item;int ret;
strcpy(item,"Steve");
ret=hf(item);
insert(&li[ret],item,ret);
strcpy(item,"raj");
ret=hf(item);
insert(&li[ret],item,ret);
strcpy(item,"Notes");
ret=hf(item);
insert(&li[ret],item,ret);
}
The above program is to implement array of linked list and im trying to insert string
as the value. When i am trying to run the program, there are no errors but it tells segmentation fault(core dumped)
so please explain the reason
The code
char *item;int ret;
strcpy(item,"Steve");
tries to copy the string literal "Steve" to an uninitialised pointer. You need to allocate memory for item. The easiest way of doing this is to hard-code a suitably sized stack buffer
char item[50];
You also have a similar problem inside insert. You could solve this in the same way
struct list
{
char value[50];
struct list *link;
};
or you could dynamically allocate the correct size of buffer inside insert
temp->value = malloc(strlen(item) + 1);
if (temp->value == NULL) {
/* handle oom error */
}
strcpy(temp->value, item);
In this latter approach, make sure to free(node->value) when you free that list node. Note also that freeing of all dynamically allocated memory is currently missing from your program, meaning that you leak all memory allocated using malloc.
There is one more bug in your code - insert assumes that arr is a pointer to a valid list* but it is always NULL. You need to update either main or the assumption in insert here.
change the following
In insert() function change the if loop
if(r==NULL){
r = temp;
}
Change the structure. change the size of the structure for your need
struct list
{
char value[25];
struct list *link;
};
Change the variable item to
char item[25];
EDIT :
There is no need to typecast the output of malloc

Resources