I understand that a set fault happens when you try to access memory out of the scope of your program, but I can't figure out where mine is happening, or why. I have a list defined:
*ListType list = NULL; ,
and then I add data to the List calling the add function in main:
addNodeToList(&list, song);
void addNodeToList(ListType **list, SongType *song)
{
printf("Starting Add");
NodeType *newNode = malloc(sizeof(NodeType));
NodeType *currNode;
currNode = (*list)->head;
newNode->data = song;
newNode->next = NULL;
if(currNode == NULL) {
printf("List is Empty");
(*list)->tail = newNode;
(*list)->head = newNode;
}
else {
(*list)->tail->next = newNode;
(*list)->tail = newNode;
}
}
The song I'm passing is properly initialized, and I can access it's elements, so I know that isn't causing the seg fault. Any help would be very appreciated!
typedef struct Song {
char title[MAX_STR];
char artist[MAX_STR];
char album[MAX_STR];
char duration[MAX_STR];
} SongType;
typedef struct Node {
struct Node *next;
SongType *data;
} NodeType;
typedef struct List {
NodeType *head;
NodeType *tail;
} ListType;
in main if you're declaring
ListType* list = NULL;
then in your function you're calling
(*list)->head
dereferencing (*list) is fine, but as soon as you do ->head it's trying to dereference that original NULL assignment. You need to allocate some space for list first.
It appears that your calling code contains:
ListType *list = NULL;
and you call your function like this:
addNodeToList(&list, song);
and in your addNodeToList() function you have:
NodeType *currNode;
currNode = (*list)->head;
which means you are dereferencing a null pointer (*list), which crashes your code. At minimum, check whether *list == NULL before setting currNode, but you'll need rethink the code to handle the case where list is a null pointer.
This code compiles, and runs. It avoids the problem by allocating the list when necessary:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
enum { MAX_STR = 64 };
typedef struct Song
{
char title[MAX_STR];
char artist[MAX_STR];
char album[MAX_STR];
char duration[MAX_STR];
} SongType;
typedef struct Node
{
struct Node *next;
SongType *data;
} NodeType;
typedef struct List
{
NodeType *head;
NodeType *tail;
} ListType;
void addNodeToList(ListType **list, SongType *song);
void addNodeToList(ListType **list, SongType *song)
{
printf("Starting Add\n");
assert(list != NULL);
if (*list == NULL)
{
*list = malloc(sizeof(**list));
assert(*list != 0); // Too lazy for production
(*list)->head = 0;
(*list)->tail = 0;
printf("List created\n");
}
NodeType *newNode = malloc(sizeof(NodeType));
newNode->data = song;
newNode->next = NULL;
printf("Node created\n");
NodeType *currNode = (*list)->head;
if (currNode == NULL)
{
printf("List is Empty\n");
(*list)->tail = newNode;
(*list)->head = newNode;
}
else
{
(*list)->tail->next = newNode;
(*list)->tail = newNode;
}
printf("Node added - all done\n");
}
int main(void)
{
ListType *list = NULL;
SongType data = { "Title", "Artist", "Album", "2m 30s" };
SongType *song = &data;
printf("Add song once\n");
addNodeToList(&list, song);
printf("Add song again\n");
addNodeToList(&list, song);
return 0;
}
Example run:
Add song once
Starting Add
List created
Node created
List is Empty
Node added - all done
Add song again
Starting Add
Node created
Node added - all done
The code leaks like a sieve; no memory is freed.
The problem deals with this statement
ListType *list = NULL;
You may not call addNodeToList for a list initialized such a way. Otherwise there will be undefined behaviour.
You should declare the list the following way
ListType list = { NULL, NULL };
Also the function addNodeToList can be declared simpler
void addNodeToList(ListType *list, SongType *song);
^^^^^^^^^^^^^^
You can call it like
addNodeToList( &list, song );
For example
void addNodeToList( ListType *list, SongType *song )
{
printf("Starting Add");
NodeType *newNode = malloc( sizeof( NodeType ) );
if ( newNode != NULL )
{
newNode->data = song;
newNode->next = NULL;
if ( list->tail == NULL )
{
printf( "List is Empty\n" );
list->head = list->tail = newNode;
}
else
{
list->tail->next = newNode;
list->tail = newNode;
}
}
}
Or if you want to have a pointer to list then you should write
ListType *list = malloc( sizeof( ListType ) );
list->head = list-tail = NULL;;
and then call the function the definition of which I showed the following way
addNodeToList( list, song );
Related
I implemented a linked list for my school assignment but when I try to print out value of a node, the first node always get printed with memory address and I can't figure out why it's happening.
I tried debugging and as I assign tail of list to the new node, the value of the node gets printed out as memory address.
Why is this happening?
int AppendLinkedList(LinkedListPtr list, int value) {
LinkedListNodePtr newNode = CreateLinkedListNode(value);
if (list->head == NULL) {
list->head = newNode;
list->tail = newNode;
return 0;
}
LinkedListNodePtr tailCopy = list->tail;
newNode->prev = tailCopy;
tailCopy->next = newNode;
list->tail = newNode;
return 0;
}
LinkedListNode *CreateLinkedListNode(int data) {
LinkedListNodePtr newNode;
newNode = (LinkedListNodePtr)malloc(sizeof(LinkedListNode));
newNode->data = data;
printf("%d\n", data);
return newNode;
}
int main() {
LinkedListPtr list = CreateLinkedList();
int data = 5;
AppendLinkedList(list, data);
}
typedef struct ll_node {
int data; // Data this node holds
struct ll_node *next; // next node in list, or NULL
struct ll_node *prev; // prev node in list, or NULL
} LinkedListNode, *LinkedListNodePtr;
typedef struct ll_head {
uint64_t num_elements; // # elements in the list
LinkedListNodePtr head; // head of linked list, or NULL if empty
LinkedListNodePtr tail; // tail of linked list, or NULL if empty
} *LinkedListPtr;
LinkedListPtr CreateLinkedList() {
LinkedListPtr list;
list = (LinkedListPtr)malloc(sizeof(LinkedListPtr));
if (list == NULL) {
return NULL;
}
return list;
}
There are multiple problems in your code:
you do not initialize the prev and next members to NULL in CreateLinkedListNode().
the allocation size is incorrect in CreateLinkedList(): you should use:
LinkedList *list = malloc(sizeof(*list));
and you should initialize the members num_elements to 0 and head and tail to NULL.
the order of definitions is inadequate and the header files are missing.
AppendLinkedList() does not update num_elements.
More generally, hiding pointers behind typedefs is error prone. The code is much more readable with the explicit pointer syntax.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
typedef struct ll_node {
int data; // Data this node holds
struct ll_node *next; // next node in list, or NULL
struct ll_node *prev; // prev node in list, or NULL
} LinkedListNode;
typedef struct ll_head {
uint64_t num_elements; // # elements in the list
LinkedListNode *head; // head of linked list, or NULL if empty
LinkedListNode *tail; // tail of linked list, or NULL if empty
} LinkedList;
LinkedList *CreateLinkedList() {
LinkedList *list = malloc(sizeof(*list));
if (list != NULL) {
list->num_elements = 0;
list->head = NULL;
list->tail = NULL;
}
return list;
}
LinkedListNode *CreateLinkedListNode(int data) {
LinkedListNode *newNode = malloc(sizeof(*newNode));
if (newNode != NULL) {
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
}
return newNode;
}
int AppendLinkedList(LinkedList *list, int value) {
if (list == NULL)
return -1;
LinkedListNode *newNode = CreateLinkedListNode(value);
if (newNode == NULL)
return -1;
if (list->head == NULL) {
list->head = newNode;
} else {
LinkedListNode *tail = list->tail;
newNode->prev = tail;
tail->next = newNode;
}
list->tail = newNode;
list->num_elements += 1;
return 0;
}
int main() {
LinkedList *list = CreateLinkedList();
int data = 5;
AppendLinkedList(list, data);
}
I want to delete node from singly linked list using only one local pointer variable in C, the debugger stops on the free(cur) of the delete function without any error, but it runs normally in free(cur->next), why is this? What error in this code section?
struct node
{
int val;
struct node *next;
};
typedef struct
{
struct node *header;
} List;
void add(List *pList, int val)
{
struct node *new_node = malloc(sizeof pList->header);
if (new_node == NULL)
{
exit(EXIT_FAILURE);
}
new_node->val = val;
new_node->next = pList->header;
pList->header = new_node;
}
void delete(List *pList, int val)
{
struct node *cur = pList->header;
if (cur != NULL)
{
if (cur->val == val)
{
struct node *temp = cur->next;
//debug stop in free(cur) without any error,why?
free(cur);
cur = temp;
}
else
{
while (cur->next != NULL && cur->next->val != val)
{
cur = cur->next;
}
if (cur->next != NULL)
{
struct node *temp = cur->next->next;
// run normally, why?
free(cur->next);
cur->next = temp;
}
}
}
}
There is a problem in the add function: you pass the size of a pointer to malloc instead of the size of the node structure. A safer way to always pass the correct size is this:
struct node *new_node = malloc(sizeof *new_node);
As coded, the memory allocated is too small and you have undefined behavior when you initialize the structure, writing beyond the end of the allocated block.
There is another problem in the delete() function: you do not update pList->header when you free the first node.
Here is a modified block:
struct node {
int val;
struct node *next;
};
typedef struct {
struct node *header;
} List;
void add(List *pList, int val) {
struct node *new_node = malloc(sizeof(*new_node));
if (new_node == NULL) {
exit(EXIT_FAILURE);
}
new_node->val = val;
new_node->next = pList->header;
pList->header = new_node;
}
void delete(List *pList, int val) {
struct node *cur = pList->header;
if (cur != NULL) {
if (cur->val == val) {
pList->header = cur->next;
free(cur);
} else {
while (cur->next != NULL) {
struct node *temp = cur->next;
if (temp->val == val) {
cur->next = temp->next;
free(temp);
break;
}
cur = temp;
}
}
}
}
I want to implement linked list from scratch. I programmed it, but when I run it gives me a Segmentation fault in my node_adder(int data) function. I don't know what caused this.
struct linked_list
{
int value;
struct linked_list *next;
};
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
void node_adder(int data)
{
struct linked_list *new = NULL;
new->value = data;
new->next = NULL;
if (head == NULL)
{
head = new;
tail = new;
printf("head added\n");
}
else
{
tail->next = new;
tail = new;
printf("tail added\n");
}
}
In node_adder(), you are not allocating any memory for the new node before accessing its members.
Try this instead:
struct linked_list
{
int value;
struct linked_list *next;
};
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
void node_adder(int data)
{
struct linked_list *newNode;
// ADD THIS!!!
// in C:
newNode = malloc(sizeof(struct linked_list));
// in C++:
newNode = new linked_list;
//
newNode->value = data;
newNode->next = NULL;
if (head == NULL)
{
head = tail = newNode;
printf("head added\n");
}
else
{
tail->next = newNode;
tail = newNode;
printf("tail added\n");
}
}
This line initializes a pointer to a node to NULL:
struct linked_list *new = NULL;
Yet, no memory is allocated for this node. Therefore, in this line, attempting to assign a value to one of the members of the node leads to a segmentation fault:
new->value = data;
You probably meant to do this:
struct linked_list *new = malloc(sizeof(struct linked_list));
Of course, a corresponding free(..) should also be added when the allocated memory will no longer be used.
For starters it is a bad idea to declare global variables and define functions that depend on the global variables as you are doing
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
because in this case you will not be able to define for example more than one list.
It is much better to introduce one more structure like for example
struct node
{
int value;
struct node *next;
};
struct linked_list
{
struct node *head;
struct node *tail;
};
As for your problem then you are using a null pointer to access memory that results in undefined behavior
void node_adder(int data)
{
struct linked_list *new = NULL;
new->value = data;
new->next = NULL;
//...
You need to allocate a node dynamically as for example
int node_adder(int data)
{
struct linked_list *new = malloc( sizeof( *new ) );
int success = new != NULL;
if ( success )
{
new->value = data;
new->next = NULL;
if (head == NULL)
{
head = new;
}
else
{
tail->next = new;
}
tail = new;
}
return success;
}
But using the approach I showed in the beginning of my answer You could write instead
struct node
{
int value;
struct node *next;
};
struct linked_list
{
struct node *head;
struct node *tail;
};
int node_adder( struct linked_list *list, int data )
{
struct node *new = malloc( sizeof( *new ) );
int success = new != NULL;
if ( success )
{
new->value = data;
new->next = NULL;
if (list->head == NULL)
{
list->head = new;
}
else
{
list->tail->next = new;
}
list->tail = new;
}
return success;
}
and in main you can write
int main( void )
{
struct linked_list list = { .head = NULL, .tail = NULL };
node_adder( &list, 10 );
//...
}
I am writing for deleting the last node of a doubly linked list. But, every time this function is giving me segmentation fault when I have 2 or more than 2 elements in the list.
void deleteEnd()
{
struct node *ptr;
if(head==NULL)
printf("\nList is empty.First add some numbers");
else if(head->next==NULL)
{
head = NULL;
free(head);
}
else
{
ptr = head;
while(ptr->next != NULL)
{
ptr = ptr -> next;
}
ptr -> prev -> next = NULL;
free(ptr);
}
}
Normally, when you are deleting a node from a linked list it is a good practice to pass a reference to the first node of the list as an argument of the function. In your case you are not showing us where the head is coming from, and I think that it could be quite a useful info, and I bet that the error hides there.
That is how the implementation could look like:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
// insert end node: this is for testing purposes
struct node *insertEnd(struct node *head, int value) {
struct node *ptr, *new_node;
ptr = head;
new_node = (struct node *) malloc(sizeof(struct node));
new_node->data = value;
new_node->next = NULL;
// The list is empty
if (head == NULL) {
head = new_node;
return head;
}
// Non empty list
while (ptr->next != NULL) {
ptr = ptr->next;
}
ptr->next = new_node;
return head;
}
// delete end node
struct node *deleteEnd(struct node *head) {
struct node *ptr, *preptr;
ptr = head;
preptr = NULL;
// The list is empty
if (head == NULL) {
printf("The list is empty. Nothing to delete.\n");
return head;
}
while(ptr->next != NULL) {
preptr = ptr;
ptr= ptr->next;
}
free(ptr);
if (preptr == NULL) {
head = NULL;
}
else {
preptr->next = NULL;
}
return head;
}
int main(void) {
struct node *llist;
llist = NULL;
llist = insertEnd(llist, 10);
llist = insertEnd(llist, 20);
llist = insertEnd(llist, 30);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
return 0;
}
It is always a great idea to maintain a global variable head and update it after every push/pop. See this:
struct node
{
int data;
struct node *next;
};
struct node *start = NULL;
struct node *deleteEnd(struct node *start)
{
struct node *ptr = start;
if(ptr==NULL)
{
printf("\nList is empty!!!");
return start;
}
else if(ptr->next == NULL)
{
free(ptr);
start = NULL;
return start;
}
else
{
while((ptr->next)->next!=NULL) //by doing this you dont have to maintain a prev pointer
{
ptr=ptr->next;
}
struct node *temp = ptr->next;
free(temp);
ptr->next = NULL;
return start;
}
}
Hope this helps!!!
I am writing linked list in Xcode in C.
in fact I can append the first node to the list. And everything runs well.
However when I append the second to the list, Xcode shows me EXC_BAD_ACCESS error on the line of malloc() a new node.
I know this error caused by accessing NULL pointer, but I cannot find where is wrong.
Here is part of my code.
SinglyLinkedList.c:
void llist_node_append(SList *ptr, const void *datap)
{
struct llist *me = ptr;
struct node *newnodep;
newnodep = malloc(sizeof(struct node));
if (newnodep == NULL)
FatalError("No space to append new node.\n");
newnodep->datap = malloc(sizeof(me->elemsize));
if (newnodep->datap == NULL)
FatalError("No space to append new node.\n");
memcpy(newnodep->datap, datap, me->elemsize);
newnodep->next = NULL;
me->last->next = newnodep;
me->last = newnodep;
if (llist_is_empty(me))
me->head->next = newnodep;
}
void llist_travel(SList *ptr, node_proc_fun_t *proc)
{
struct llist *me = ptr;
struct node *curr;
for (curr = me->head.next; curr != NULL; curr = curr->next) {
proc(curr->datap);
}
}
main.c:
struct node {
void *datap;
struct node *next;
};
struct llist {
struct node *head;
struct node *last;
int elemsize;
};
typedef struct food_list {
char breakfast[20];
char lunch[20];
char dinner[20];
} FoodList;
void llist_print(void* elem)
{
FoodList *temp = elem;
printf("the breakfast is %s\nthe lunch is %s\nthe dinner is %s\n", temp->breakfast, temp->lunch, temp->dinner);
}
int main()
{
SList list = *llist_new(sizeof(FoodList));
FoodList UCSB = {
"milk and bread",
"beef",
"burger",
};
FoodList UCB = {
"apple",
"juice",
"eggs",
};
llist_node_append(&list, &UCSB);
llist_node_append(&list, &UCB);
llist_travel(&list, llist_print);
return 0;
}