I am trying to make a Doubly Linked List in C.
And I get a Segmentation Fault even though I use malloc.
Here is my code so far.
list.h
#ifndef _LIST_
#define _LIST_
typedef struct listnode
{
char * data;
struct listnode * next;
struct listnode * prev;
}listnode;
typedef struct list
{
listnode * firstnode; // it will point to the first element in the list
int size; // the size of the list
}list;
list create_list();
void insert_first_element(char *, list);
#endif
list.c
#include "list.h"
#include <stdlib.h>
#include <string.h>
list create_list()
{
list L;
L.firstnode= NULL;
L.size = 0;
return L;
}
void incert_first_element(char * d, list L)
{
listnode * N= (listnode *)malloc(sizeof(listnode));
strcpy(N->data, d); // <-- I get Segmentation Fault Here
if(L.firstnode != NULL)
{
N->next=L.firstnode;
N->prev=L.firstnode->prev;
L.firstnode->prev=N;
L.firstnode=N;
}
else
{
N->next=NULL;
N->prev=N;
L.firstnode=N;
}
L.size++;
return 0;
}
main.c
#include <stdio.h>
#include "list.h"
int main(void)
{
list L = create_list();
incert_first_element("test",L);
return 0;
}
Any idea what is causing the Segmentation Fault?
Because any problems I found when googling were caused by the lack of malloc, but here I do implement it.
this code
listnode * N= (listnode *)malloc(sizeof(listnode));
strcpy(N->data, d); // <-- I get Segmentation Fault Here
allocates a listnode structure but the data field is a pointer on a char, so it's not initialized by the malloc call.
The second line should be replaced for instance by a strdup call
N->data = strdup(d);
deallocation should also be done in 2 passes. First free(N->data) then free(N)
There are multiple problems in your code:
incert_first_element receives a copy of the list structure and modifies it. This has no effect on the list object of the caller. You should instead pass a pointer to the caller's list object.
the incert_first_element function allocates a new listnode object, but not for the string. The member data is a pointer, not an array, malloc() does not initialize it so strcpy(N->data, d); copies the characters into an uninitialized pointer, invoking undefined behavior (a segmentation fault stooping the program). You should allocate a copy of the string with N-strcpy(N->data, d);
you insert the node at the beginning of the doubly linked list, thus it is incorrect to set N->prev = N; the previous node should be set to NULL in both cases.
in list.c, you should #include "list.h" after the standard headers.
Here is a modified version:
list.h
#ifndef LIST_H
#define LIST_H
typedef struct listnode {
char *data;
struct listnode *next;
struct listnode *prev;
} listnode;
typedef struct list {
listnode *firstnode; // it will point to the first element in the list
int size; // the size of the list
} list;
list create_list(void);
void insert_first_element(list *, const char *);
#endif
list.c
#include <stdlib.h>
#include <string.h>
#include "list.h"
list create_list(void) {
list L = { NULL, 0 };
return L;
}
void insert_first_element(list *L, const char *d) {
listnode *N = malloc(sizeof(*N));
if (N == NULL) {
return -1;
}
N->data = strdup(d);
N->prev = NULL;
N->next = L->firstnode;
if (L->firstnode != NULL) {
L->firstnode->prev = N;
}
L->firstnode = N;
L->size++;
return 0;
}
main.c
#include <stdio.h>
#include "list.h"
int main(void) {
list L = create_list();
insert_first_element(&L, "test");
return 0;
}
Related
This is an extract of a code, where I populate a list with the elements of an array.
#include <stdlib.h>
#include <stdio.h>
#include "../../lib/kernel/list.h"
#include "./listpop.h"
struct item {
struct list_elem elem;
int value;
int priority;
};
void populate(struct list * l, int * a, int n);
void populate(struct list * l, int * a, int n)
{
int i = 0;
while(i != n) {
struct item * newitem = malloc(sizeof(struct item));
newitem->value = a[i];
list_push_back(l,newitem);
i++;
}
}
void test_assignment_1()
{ struct list our_list;
list_init(&our_list);
populate(&our_list, ITEMARRAY, ITEMCOUNT);
}
Code inside list.h:
/* List element. */
struct list_elem
{
struct list_elem *prev; /* Previous list element. */
struct list_elem *next; /* Next list element. */
};
/* List. */
struct list
{
struct list_elem head; /* List head. */
struct list_elem tail; /* List tail. */
};
void list_init (struct list *);
Code inside list.c:
/* Initializes LIST as an empty list. */
void
list_init (struct list *list)
{
ASSERT (list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
And finally, the code inside listpop.h:
#define ITEMCOUNT 10
int ITEMARRAY[ITEMCOUNT] = {3,1,4,2,7,6,9,5,8,3};
Here are the warnings I get:
warning: implicit declaration of function ‘malloc’
warning: incompatible implicit declaration of built-in function ‘malloc’
So far, all I've read about those warnings is to add stdlib.h, but as you can see from my code I've already done it, and the code still give me those warnings. I've restarted the code many times, so the error lays somewhere in the code.
Anyone knows what is not working here?
You might be compiling on a obsolete system with a non conforming compiler and/or C library. Try including <malloc.h> in addition to <stdlib.h> and always include the standard headers first.
I have a requirement to implement two functions
directed_by(node_t * list, char * director)
rated(node_t * list, const rating_t rating)
Each will require I pass in a list and iterate through it. I'm new to C and actually I'm not that familiar with list structures either. Can someone please help me understand how do I return a list so that I can pass into my two functions so that I can iterate through each list?
Here is my code so far. I think I need to return something in my add_movie() function, such as node_t, but I'm not sure how to do that?
LIST.H
#ifndef BASICLIST_H_
#define BASICLIST_H_
typedef struct node {
void * data; /* pointer to data */
struct node * next; /* pointer to next next node */
} node_t;
int list_add(node_t ** list, void * data);
#endif
MOVIE.H
#include <stdio.h>
#ifndef MOVIE_H
#define MOVIE_H
#define SIZE_LIMIT 25
#define RATING_SIZE 6
typedef struct {
char title[SIZE_LIMIT];
char director[SIZE_LIMIT];
char rating[RATING_SIZE];
//rating_t rating;
int year;
}movie_t;
void get_movie(movie_t * movie);
void print_movie(const movie_t *m);
void print_movies(const movie_t *m);
void add_movie(movie_t movie);
#endif /* MOVIE_H */
LIST.C
#include <stdio.h>
#include <stdlib.h>
#include"basiclist.h"
int list_add(node_t ** list, void * data) {
int ret = 0;
node_t * newnode = (node_t *) malloc(sizeof(node_t));
if (newnode == NULL) {
ret = -1;
}
else {
newnode->data = data;
newnode->next = *list;
}
*list = newnode;
return ret;
}
MOVIE.C
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
#include "basiclist.h"
void print_movies(const movie_t *m) {
printf("%s\t%s\t%s\t%d\n", m->title, m->director, m->rating, m->year);
}
void add_movie(movie_t movie) {
node_t * list = NULL;
movie_t first_movie = movie;
movie_t * new_movie;
new_movie = malloc(sizeof (*new_movie));
*new_movie = first_movie;
list_add(&list, new_movie);
node_t * curr;
curr = list;
while (curr != NULL) {
print_movies(curr->data);
curr = curr->next;
}
}
MAIN.C
#include "movie.h"
#include <stdlib.h>
#include <stdio.h>
#include "basiclist.h"
int main(void) {
movie_t movie1 = {"Movie1", "Director1", "PG-13", 1900};
movie_t movie2 = {"Movie2", "Director2", "R", 1900};
movie_t movie3 = {"Movie3", "Director3", "G", 1900};
movie_t movie4 = {"Movie4", "Director4", "R", 1900};
add_movie(movie1);
add_movie(movie2);
add_movie(movie3);
add_movie(movie4);
/*undefined methods
directed_by(node_t * list, char * director)
rated(node_t * list, const rating_t rating)
*/
return 0;
}
The main problem with this code is that you are not returning or passing your list to the add_movie function.
In each call you are creating a new list and losing it's reference, so you can't use it.
The "easy" fix to your code would be to change:
void add_movie(movie_t movie)
to
void add_movie(node_t** list, movie_t movie);
and remove the first line of the function, then change your main to:
node_t* list = NULL;
add_movie(&list, movie1);
add_movie(&list, movie2);
add_movie(&list, movie3);
add_movie(&list, movie4);
With this change you will have the list with movie4, movie3, movie2 and movie1.
PS: you also want to change your list add method to return -1 instead of setting ret to -1. In its current form you would lose your list in case of an error because you are setting the given reference to NULL (also, that would create a memory leak).
PS 2: It is not really recommended to pass structs as arguments in C, you should use pointers instead. The reason is that when you pass a struct as argument C will copy its whole content to a temporary struct variable, so if you have, say, a 256 bytes struct you will be copying 256 bytes of information for every function call, instead of 4 (32 bits systems) or 8 (64 bits systems) if you had used a pointer.
I can't understand why this litle code doesn't work ! i get it from C struct and malloc problem (C) (selected answer) and I wonder why it doesn't work for me.
any idea ?
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
/* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
tree* atree = malloc(sizeof(tree)); /* different names for variables */
node* anode = malloc(sizeof(node));
atree->nodes[0] = anode; // <-------- SEG FAULT HERE !
return atree;
}
int main() {
tree* mytree = initTree();
return 0;
}
With a call to
tree* atree = malloc(sizeof(tree));
you have allocated a memory for tree object, so for a struct node** nodes pointer to (as it is a struct member), but it doesn't point to valid memory yet. You have to allocate also a memory for the nodes to which it is supposed to point to. For example:
atree->nodes = malloc( atree->numNodes*(sizeof (node*)));
I'm trying to create a simple singly linked list in C, and have encountered an infinite "Singal 11 being dropped" loop while running my program in Valgrind.
My .h file:
#ifndef TEST_H
#define TEST_H
struct fruit {
char name[20];
};
struct node {
struct fruit * data;
struct node * next;
};
struct list {
struct node * header;
unsigned count;
};
#endif
My .c file:
#include "test.h"
#include <stdio.h>
#include <string.h>
void init_list(struct list my_list)
{
my_list.header = NULL;
my_list.count = 0;
}
void add_to_list(struct list my_list, struct fruit my_fruit)
{
struct node my_node;
struct node nav_node;
my_node.data = &my_fruit;
my_node.next = NULL;
if(my_list.count == 0) { /* set head node if list is empty */
my_list.header = &my_node;
my_list.count++;
} else {
nav_node = *my_list.header;
while (nav_node.next != NULL) { /* traverse list until end */
nav_node = *nav_node.next;
}
nav_node.next = &my_node;
my_list.count++;
}
}
int main()
{
struct fruit fruit_array[5];
struct list fruit_list;
int i;
strcpy(fruit_array[0].name, "Apple");
strcpy(fruit_array[1].name, "Mango");
strcpy(fruit_array[2].name, "Banana");
strcpy(fruit_array[3].name, "Pear");
strcpy(fruit_array[4].name, "Orange");
init_list(fruit_list);
for(i=0; i < 5; i++) {
add_to_list(fruit_list, fruit_array[i]);
}
return 0;
}
I'm assuming the issue stems from my list traversal in add_to_list, but I'm unsure about what I'm doing wrong.
Thanks!
You're passing structs by value into functions. This will create a copy of the struct in the function, and changes to the copy will not occur on the struct in the calling function.
You should read about pointers in your favorite c-language book.
I am trying to create a linked list in my program and I am not able to allocate memory to the structure pointer using malloc(). How do I allocate memory to variables in GCC? The sample program is given below. How to make it work in gcc?
#include<stdio.h>
#include <alloc.h>
struct node
{
int data;
struct node * link;
};
void insert (struct node *p, int d)
{
struct node *temp;
temp = malloc(sizeof(struct node));
temp->data=d;
temp->link=NULL;
if(p==NULL)
{
p=temp;
}
else{
while(p->link!=NULL)
p=p->link;
p->link=temp;
}
}
void disp(struct node *p)
{
while(p!=NULL)
{
printf("%d\n",p->data);
p=p->link;
}
}
int main()
{
struct node *p;
p=NULL;
insert(p,7);
insert(p,9);
disp(p);
}
The error I'm encountering is:
Line 18: error: alloc.h: No such file or directory
In function 'insert':
Line 13: warning: incompatible implicit declaration of built-in function 'malloc'
malloc is in <stdlib.h>. Include that.
Reading the man page for that function would have given you that information. It's not compiler-dependent.
malloc is declared in <stdlib.h>, so that's what you want to #include.
The definition of malloc is in the stdlib.h file:
#include <stdlib.h>
instead of alloc.h.
Like the others say: your error occurs because you have to include stdlib.h instead of alloc.h
To get your list printed, you have to modify p in insert. Currently, you're passing NULL every time you call insert. Change your code that way (pass a pointer-to-pointer to insert):
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node * link;
};
/* note **p instead of *p */
void insert (struct node **p, int d)
{
struct node *temp;
temp = malloc(sizeof(struct node));
temp->data=d;
temp->link=NULL;
if(*p==NULL)
{
*p=temp;
}
else{
while((*p)->link!=NULL)
*p=(*p)->link;
(*p)->link=temp;
}
}
void disp(struct node *p)
{
while(p!=NULL)
{
printf("%d\n",p->data);
p=p->link;
}
}
int main()
{
struct node *p;
p=NULL;
insert(&p,7);
insert(&p,9);
disp(p);
}
and it will print
7
9