segmentation fault linked-list in c - c

please dont press the rep minus button so easily im new here- be nice please
i have slist.h implementing by slist.c
here is the slist.h
#ifndef DBLLIST_H
#define DBLLIST_H
//! The definition of a double linked list node
typedef struct dbllist_node
{
void *data; // Pointer to data of this node
struct dbllist_node *next; // Pointer to next node on list
struct dbllist_node *prev; // Pointer to previous node on list
}dbllist_node_t;
//! The definition of a double linked list
struct dbllist
{
dbllist_node_t *head; // Pointer to head of list
dbllist_node_t *tail; // Pointer to tail of list
unsigned int size; // The number of elements in the list
};
//! double linked list type
typedef struct dbllist dbllist_t;
// you have to use these macros, do not use the inner variables of the list!!
//! Macro to get the head node of a list l
#define dbllist_head(l) l->head
//! Macro to get the tail node of a list l
#define dbllist_tail(l) l->tail
//! Macro to get the size of a list l
#define dbllist_size(l) l->size
//! Macro to get the next node of l
#define dbllist_next(n) n->next
//! Macro to get the prev node of l
#define dbllist_prev(n) n->prev
//! Macro to get the data of node l
#define dbllist_data(n) n->data
//! Specifies whether dbllist_destroy should deallocate or not stored elements
typedef enum { DBLLIST_LEAVE_DATA = 0, DBLLIST_FREE_DATA } dbllist_destroy_t;
/** Initialize a double linked list
\param list - the list to initialize */
void dbllist_init(dbllist_t *);
/** Destroy and de-allocate the memory hold by a list
\param list - a pointer to an existing list
\param dealloc flag that indicates whether stored data should also be de-allocated */
void dbllist_destroy(dbllist_t *,dbllist_destroy_t);
/** Append data to list (add as last node of the list)
\param list - a pointer to a list
\param data - the data to place in the list
\return 0 on success, or -1 on failure */
int dbllist_append(dbllist_t *,void *);
/** Prepend data to list (add as first node of the list)
\param list - a pointer to list
\param data - the data to place in the list
\return 0 on success, or -1 on failure
*/
int dbllist_prepend(dbllist_t *,void *);
/** \brief Remove the specific node from the list.
\param to a pointer to the list
\param pointer to the node that should be removed.
\param dealloc flag that indicates whether to de-allocated the data in the node
\return 0 on success, or -1 on failure
*/
int dbllist_remove(dbllist_t *, dbllist_node_t* ,dbllist_destroy_t);
#endif
and now the slist.c i wrote
my problem is when ever i call the destroy function im facing segmentation fault at the last node.. i can provide main that i wrote too.
#include "slist.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void dbllist_init(dbllist_t *list)
{ if(list != NULL)
{
dbllist_head(list) = NULL;
dbllist_tail(list) = NULL;
dbllist_size(list) = 0;
}
}
int dbllist_append(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = NULL;
dbllist_prev(temp) = dbllist_tail(list);
dbllist_next(dbllist_tail(list)) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
int dbllist_prepend(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = dbllist_head(list) ;
dbllist_prev(temp) = NULL;
dbllist_prev(dbllist_head(list)) = temp;
dbllist_head(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
/**
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
temp = dbllist_head(list);
if(list != NULL && pointer !=NULL)
{
if(pointer == dbllist_head(list))
{
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
dbllist_head(list) = NULL;
dbllist_size(list) = 0;
dbllist_tail(list) = NULL;
free(dbllist_head(list));
free(temp);
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list)) ;
dbllist_next(dbllist_tail(list)) = NULL;
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0 ;
}
int tempSize = 1;
for(temp = dbllist_next(temp) ; tempSize< dbllist_size(list); temp = dbllist_next(temp),tempSize++)
if(temp == pointer)
{
dbllist_next(dbllist_prev(temp)) = dbllist_next(temp);
dbllist_prev(dbllist_next(temp)) = dbllist_prev(temp);
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0;
}
}
return -1;
}
*/
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
if(list == NULL || pointer == NULL )
return -1;
//printf("%d \n",(int)dbllist_data(current));
if( pointer == dbllist_head(list))
{
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_next(dbllist_tail(list))));
free(dbllist_next(dbllist_tail(list)));
dbllist_next(dbllist_tail(list)) = NULL;
dbllist_size(list)--;
return 0;
}
//int i = 1;
dbllist_node_t *current = dbllist_next(dbllist_head(list));
while(current)
{
if(current == pointer)
{
dbllist_next(dbllist_prev(current)) = dbllist_next(current) ;
dbllist_prev(dbllist_next(current)) = dbllist_prev(current) ;
dbllist_size(list)--;
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(current));
free(current);
current = NULL;
return 0;
}
current = dbllist_next(current);
}
free(current);
return -1;
}
void dbllist_destroy(dbllist_t *list ,dbllist_destroy_t dealloc)
{
//dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
//dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
while (dbllist_head(list) != NULL)
{
//dbllist_node_t *current;
dbllist_node_t *temp ;
temp = dbllist_tail(list);
while(temp)
{
dbllist_remove(list,temp , dealloc);
printf("in\n");
temp = dbllist_tail(list);
printf("out \n");
}
//temp = dbllist_head(list);
//dbllist_remove(list,temp , dealloc);
//free(temp);
}
//free(current);
//free(temp);
}
can someone understand the error and explain to me how to fix it
im trying over a feew hours now without success

In this code:
if( pointer == dbllist_head(list))
{
// After next line: list->head points to next node (could be null)
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
// -- If head is now NULL, what happens below? --
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}

the right answer is:
if(!dbllist_next(dbllist_head(list)))
{
if(dealloc == DBLLIST_FREE_DATA )
free(dbllist_data(dbllist_head(list)));
free(dbllist_head(list));
dbllist_head(list) = NULL;
dbllist_size(list)--;
return 0;
}
add this before the head part in remove function
because of a null pointer exception i did when in the head of the list.
thanks

In your Remove function dbllist_remove the section that is for the head case(pun intended ;)) tries to free memory that is NULL and not allocated.
The arguments free(dbllist_data(dbllist_prev(dbllist_head(list)))) AND dbllist_data(dbllist_prev(dbllist_head(list))) will not work as you have already removed the next element as well as its pointers. It was freed earlier in your destroy function. So, you cannot rely on the previous pointer actually pointing to anything.
So, I would modify your while loop in the destroy function to wait until head->next is null and then simply delete it outside of the loop and not use the standard remove function. Or modify your head case to take into account when head->next is null.

Related

C: getchar() destroys pointer

typedef struct LinkedList LinkedList;
struct LinkedList {
LinkedList* next;
char* head;
char current;
};
LinkedList makeList()
{
char* headPointer = calloc(60, sizeof(char));
LinkedList temp = { 0xCCCCCCCC, headPointer, 0 };
return temp;
}
int addToList(LinkedList* lstPointer, char toAdd) {
if (lstPointer->head == NULL || lstPointer->head == 0xCCCCCCCC)
return -1;
if (lstPointer->current + 1 < 60) { /* enough space in the list to add */
*(lstPointer-> head + lstPointer -> current) = toAdd;
lstPointer->current = lstPointer->current + 1;
}
else /* not enough space, will create new node in the list */
{
if (lstPointer->next == 0xCCCCCCCC) {
LinkedList nextNode = makeList();
lstPointer->next = &nextNode;
}
return addToList(lstPointer->next, toAdd);
}
/*Added succsessfully*/
return 0;
}
int main(){
char chr;
LinkedList lst = makeList();
while ((chr = getchar()) != EOF) {
if (addToList(&lst, chr) == -1)
return -1;
}
return 0;
}
i am trying to use linked list but after i fill the first, i create a new one and able to add an item to it. on the second item the next list pointer get destroyed by getchar(). i have no idea why or how is it related.
In makelist you need to allocate a new list, but then instead of returning it, you copy it into a local variable, leaking the memory that you just allocated. Instead, return a pointer:
LinkedList *makeList() // Note *
{
LinkedList *temp = calloc(1, sizeof(LinkedList));
temp->head = calloc(60, sizeof(char));
temp->next = 0;
temp->current = toAdd;
return temp; // Note temp is a pointer
}
In addToList you don't need the nextNode variable:
lstPointer->next = makelist();

How can I display the data I created in a linked list?

I think there is something wrong with my create.
void add(N *p) {
N *current, *start;
current = malloc(sizeof(p));
scanf("%d", &current->data);
current->next = NULL;
if (p == NULL) {
p = current;
start = current;
} else {
start->next = current;
start = current;
}
}
I think that my display() is correct.
void display(N *p) {
N *current;
current = p;
while (current != NULL) {
printf("\n%d", current->data);
current = current->next;
}
}
Your malloc(sizeof(p)) only returns enough space for a pointer. You instead want malloc(sizeof(N)).
Also, you need to return the new value of p instead of throwing it away at the end of add(). (Your start has a similar issue; pick one to be the head of your linked list.)
There are problems:
function add() does not allocate the correct amount of memory. Use this method:
current = malloc(sizeof(*current));
The way you are inserting the newly allocated object into the list does not work: you modify p, which is an argument with local scope, and you set start which also has local scope. No side effect is performed on the N pointer is the callers scope.
Your display function is correct, but I would favor adding the newline at the end of the output instead of at the beginning.
Here is an updated version with a better API:
int add(N **headp) {
N *current = calloc(sizeof(*current));
if (current == NULL) {
fprintf(stderr, "cannot allocate memory for new object\n");
return -1;
}
if (scanf("%d", &current->data) != 1) {
fprintf(stderr, "cannot read value for new object\n");
return -2;
}
current->next = *headp;
*headp = current;
return 0;
}
void display(const N *list) {
for (const N *p = list; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
The add function is used this way from the caller:
#include <stdio.h>
#include <stdlib.h>
typedef struct N {
int data;
struct N *next;
} N;
int main(void) {
N *list = NULL;
for (i = 0; i < 10; i++) {
if (add(&list))
break;
}
display(list);
return 0;
}

Double free or corruption - error when deleting first node of list

I have the following code to delete elements from a list. When one of the elements of the struct is lower than the value I use it, I must delete the node.
The code is as follows:
void DeleteNode(frota** head, int MAX, int nSquareW){
int i, eliminate = 0;
frota* curr = *head;
frota* curr1 = curr;
if(*head != NULL)
{
while(curr1 != NULL)
{
if(curr1->bateria < MAX)
{
if( *head == curr1){
if(curr1->next != NULL){
(curr1->next)->prev = NULL;
}
*head = curr1->next;
}else if(curr1 -> next == NULL){
(curr1->prev)->next = NULL;
}else{
(curr1->next)->prev = curr1->prev;
(curr1->prev)->next = curr1->next;
}
eliminate = 1;
}
curr1 = curr1->next;
if(eliminate == 1){
eliminate = 0;
printf("entrei1");
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
}
curr = curr1;
}
}
}
The code is working well when I try to delete the last and middle nodes (value head is equal to first node, unless there is none, then value is NULL), but when I try to delete the first node, I get the following error:
*** Error in './iClean': double free or corruption (!prev): 0x09bd4a20 ***
Someone has already told me that the problem is when deleting the node (the free() ) and that I can't do anything about that.
Any help would be appreciate.
EDIT
nSquareWidth is the width of the map.
This is the code which generates percorridos:
void faz_mapa(matriz *** mapa, int nSquareW, int nSquareH){
*mapa = malloc(nSquareW * sizeof(matriz*));
for (int i = 0; i < nSquareW; i++)
{
(*mapa)[i]= malloc( nSquareH * sizeof(matriz));
}
for (int i = 0; i < nSquareW; i++)
{
for (int j = 0; j < nSquareH; j++)
{
//inicializa divisao suja
(*mapa)[i][j].limpo = 0;
(*mapa)[i][j].ocupado = NULL;
}
}
}
And struct:
typedef struct robot {
int bateria;
char nome[STRING_SIZE];
int pos_x;
int pos_y;
int target_x;
int target_y;
int limpos;
matriz ** percorridos;
struct robot * next;
struct robot * prev;
}frota;
I haven't run your code, but it is apparent that there is only one spot where we can run into a double free.
for(i=0;i<nSquareW;i++){
free(curr->percorridos[i]);
}
free(curr->percorridos);
free(curr);
Either you have a case where curr->percorridos is the same as curr, or maybe curr->percorridos[i] is the same as curr->percorridos?
You could find this out by adding a print statement before each call to free. Then find out which is being called twice.
for(i=0;i<nSquareW;i++){
printf("Freeing curr->perrcorridos[i] at %p\n", curr->percorridos[i]);
free(curr->percorridos[i]);
}
printf("Freeing curr->perrcorridos at %p\n", curr->percorridos);
free(curr->percorridos);
printf("Freeing curr at %p\n", curr);
free(curr);
Since double linked list programming questions show up so often on Stack Overflow, my answer will showcase how to do a double linked list in a pretty safe way. It uses a top level list type definition and sentinel entries. There is still some room to mess up, but the code is pretty easy to test and debug as different aspects are treated locally by individual functions.
The delete() function in the original question has the problem that it is in charge of 2 different things: 1. handle the double linked list removal stuff 2. Do some application specific filtering.
My code also shows, that application code running on such a list can be separated from list management code.
#include <stdint.h>
#include <stdlib.h>
typedef struct NodeType_tag { int32_t value; NodeType_tag *Next; NodeType_tag *Prev; } NodeType;
typedef struct { NodeType sentinel; NodeType *head; NodeType *tail; } NodeList;
void NodeListInit(NodeList * nodeList)
{
nodeList->sentinel.Next = &nodeList->sentinel;
nodeList->sentinel.Prev = &nodeList->sentinel;
nodeList->head = &nodeList->sentinel;
nodeList->tail = &nodeList->sentinel;
}
int NodeListIsEmpty(NodeList * nodeList)
{
return nodeList->head == &nodeList->sentinel;
}
void NodeListAddFront(NodeList* nodeList, uintptr_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (NULL != newNode)
{
newNode->value = value;
newNode->Prev = nodeList->head->Prev;
newNode->Next = nodeList->head;
nodeList->head->Prev = newNode;
nodeList->head = newNode;
if (nodeList->tail == &nodeList->sentinel)
nodeList->tail = newNode;
}
}
void NodeListAddBack(NodeList* nodeList, int32_t value)
{
NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
if (newNode != NULL)
{
newNode->value = value;
newNode->Prev = nodeList->tail;
newNode->Next = nodeList->tail->Next;
nodeList->tail->Next = newNode;
nodeList->tail = newNode;
if (nodeList->head == &nodeList->sentinel)
nodeList->head = newNode;
}
}
NodeType *NodeListHead(NodeList*nodeList)
{
if (&nodeList->sentinel != nodeList->head)
return nodeList->head;
return NULL;
}
NodeType *NodeListTail(NodeList* nodeList)
{
if (&nodeList->sentinel != nodeList->tail)
return nodeList->tail;
return NULL;
}
NodeType *NodeListNext(NodeList * nodeList, NodeType * current)
{
if (NULL != current)
{
if (current->Next != &nodeList->sentinel)
return current->Next;
}
return NULL;
}
NodeType *NodeListPrev(NodeList *nodeList, NodeType *current)
{
if (NULL != current)
{
if (current->Prev != &nodeList->sentinel)
return current->Prev;
}
return NULL;
}
NodeType* NodeListRemoveForward(NodeList* nodeList, NodeType *target)
{
NodeType* next = NULL;
if (target != NULL)
{
target->Prev->Next = target->Next;
target->Next->Prev = target->Prev;
if (target == nodeList->head)
nodeList->head = target->Next;
if (target == nodeList->tail)
nodeList->tail = target->Prev;
if (&nodeList->sentinel != target->Next)
next = target->Next;
free(target);
}
return next;
}
// return 1 if value passes filter.
// return 0 if value is not passing filter.
typedef int(*FilterFunction_t)(int32_t value);
size_t NodeListFilter(NodeList *nodeList, FilterFunction_t filter)
{
NodeType * current = NodeListHead(nodeList);
size_t removeCount = 0;
while (current != NULL)
{
if (filter(current->value))
{
// passed filter -> keep it.
current = NodeListNext(nodeList, current);
}
else
{
// did not pass filter - kill it!
current = NodeListRemoveForward(nodeList, current);
removeCount++;
}
}
return removeCount;
}
void NodeListClear(NodeList *nodeList)
{
NodeType *current = NodeListHead(nodeList);
while (current != NULL)
{
current = NodeListRemoveForward(nodeList, current);
}
}
void DumpNodeList(NodeList* nodeList)
{
NodeType * current = NodeListHead(nodeList);
size_t i;
for (i = 0; current != NULL; i++, current = NodeListNext(nodeList,current))
{
printf("%d: %d\n", i, current->value);
}
}
int FilterAllOddValues(int32_t value)
{
if (0 == value % 2)
return 1;
return 0;
}
void TestNodeList()
{
NodeList myNodeList;
NodeListInit(&myNodeList);
for (int32_t value = 0; value < 10; value++)
{
NodeListAddBack(&myNodeList, value);
}
DumpNodeList(&myNodeList);
size_t removeCount = NodeListFilter(&myNodeList, FilterAllOddValues);
printf("%d nodes removed by filter.\n", removeCount);
DumpNodeList(&myNodeList);
NodeListClear(&myNodeList);
}
One obvious aspect is, that the number of head/tail special handling if-branches is greatly reduced compared to a non-sentinel implementation.
Another obvious aspect is that I ran it with a c++ compiler and thusly added a cast to the malloc() statements. Please resist the urge to write comments like "Don't cast malloc()", all you hardcore c-programmers ;)
I did a brief smoke test with the test code given below. There still might be errors in functions not covered by the test code.

printing tree results , segmentation error , insertion into tree

Here's the code , i run it with one example it works , but when it comes
to comparing i do not understand what's wrong ? , thanks in advance for
any help .I need to print dictionary texts properly (inserting , printing) , can not still come up with a solution , i mean using dictionary data structure like .
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
typedef struct Node_s {
char *element;
struct Node_s *left, *right;
} Node;
typedef struct {
Node *head;
} Table;
//Table *initialize();
//Node *createNode(const char *element);
Table *initialize() {
Table *tb = malloc(sizeof(Table)*1000);
tb->head = NULL;
return tb;
}
Node *createNode( char * element ) {
Node *temp = malloc(sizeof(temp));
temp->element = element ;
temp->left = temp->right = NULL;
return temp;
}
void insert(Table *temp, char *element) {
Node *nd = createNode(element);
Table * place = NULL;
Node *new = NULL;
int cmp = 0;
if(temp->head == NULL) {
temp->head= nd;
printf("empty ! \n");
return;
}
else {
Table *current = temp;
while (current!=NULL) {
cmp = strcmp(current->head->element,element);
if(cmp < 0) {
current->head= current->head->left;
}
else if(cmp > 0) {
current->head = current->head->right;
}
} //while
place = current;
new = nd;
if(cmp > 0 ) {
place->head->right = new ;
}
else if(cmp <0 ) {
place->head->left = new;
}
}
}
void print_table(Table *temp) {
if(temp!=NULL || !temp->head) return;
print_table(temp->head->left);
printf("%s \n",temp->head->element);
print_table(temp->head->right);
}
int main () {
Node * nd = NULL;
//nd->element = "key";
// nd = createNode("key");
Table *tb = initialize();
//tb->head = createNode("key");
//tb->head = createNode("key");
insert(tb, "table element1");
insert(tb, "table element2");
insert(tb, "table element2");
//nd = createNode("key1");
// print_table(t);
//printf("%s \n",nd->element);
print_table(tb);
// printf("%s \n",tb->head->element);
free(nd);
return 0;
}
There are a lot of potential bugs here, but your primary issue is in the following line of createNode:
Node *temp = malloc(sizeof(temp));
Here you're doing a sizeof(temp) and temp is a pointer. This means that you are only allocating enough memory for a pointer (usually 8 bytes). You are hence writing outside of allocating memory when using the left/right members of the heap allocated structure. The fix:
Node *temp = malloc(sizeof(Node));
// EXTRA: I also recommend that you verify that the allocation was successful
if (temp) {
temp->element = element ;
temp->left = temp->right = NULL;
}
return temp;
In printTable, you should also verify that temp itself isn't NULL as you are passing the function parameters that might be NULL:
if(!temp || !temp->head) return;
Also, remove the free(nd); at the end of main, as calling free() on unallocated heap memory corrupts the heap and typically leads to a segfault.
Your printing method crashes when reaching the last node on the left because it will call print_table(NULL) since there's nothing more on the left. After that when it executes the line
if(!temp->head) return;
You get a memory access violation because temp is NULL, you should also check if temp itself is NULL.
if( !temp || !temp->head ) return;
That should fix your problem.
One issue right away is on your second call to insert:
while (current != NULL) {
cmp = strcmp(current->head->element, element); // this line
You didn't check if current->head is NULL itself. According to what you've implemented, you use head as a sentinel, thus it can be NULL. However, your search loop totally forgot about this condition and assumes that head is never NULL.
Your loop doesn't seem fundamentally correct. You traverse the left, so what is supposed to happen if the left branch "runs out" (as it does now when you call insert the second time)?
In addition, your insert function has a memory leak. You potentially allocate 2 new nodes here:
Node *nd = createNode(element);
and here:
new = createNode(element);
Only one is stored while the other is leaked.
Another issue is that your tree does nothing in the while loop if the two items are equal. Two equal items results in an infinite loop:
while (current!=NULL)
{
cmp = strcmp(current->head->element,element);
if(cmp < 0)
current->head= current->head->left;
else if(cmp > 0)
current->head = current->head->right;
else
printf("these are equal ! \n"); // but we don't do anything with current!
}
If the goal is to not have duplicates, then you should exit this function if a duplicate is found. If the goal is to store duplicates, only test for < 0, anything else, goes on the right branch.
This might be what you are looking for.
It handles a doubly linked list
error checking is added
removed undesirable/unnecessary typedef's from struct definitions
corrected the logic to link in new nodes
avoided recursion in the printing of the linked list
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
struct Node
{
char *element;
struct Node *left;
struct Node *right;
};
// define the head pointer for the linked list
struct Node *head = NULL;
// struct Node *createNode(const char *element);
struct Node *createNode( char * element )
{
struct Node *pNewNode = NULL;
if( NULL == (pNewNode = malloc(sizeof(struct Node)) ) )
{ // then, malloc failed
perror( "malloc for new node failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
pNewNode->element = element ; // copies a char pointer
pNewNode->left = NULL;
pNewNode->right = NULL;
return pNewNode;
} // end function: createNode
void insert(char *element)
{
int cmp = 0;
// get ptr to first node in list
struct Node *pCurrentNode = head;
// create the node to be inserted into linked list
struct Node *pNewNode = createNode(element);
if (pCurrentNode == NULL)
{ // then list empty
head = pNewNode;
printf("added first node\n");
return;
}
// implied else, not first node
while (pCurrentNode->right)
{
cmp = strcmp(pCurrentNode->element,element);
if(cmp < 0)
{
// insert new node before current node
pNewNode->right = pCurrentNode;
pNewNode->left = pCurrentNode->left;
pCurrentNode->left = pNewNode;
(pNewNode->left)->right = pNewNode;
}
else if(cmp > 0)
{
// step to next node
pCurrentNode = pCurrentNode->right;
} // end if
// note: if data same, don't insert new node
} //while
if( pCurrentNode->right == NULL )
{ // then, reached end of list
// append new node to end of list
pNewNode->left = pCurrentNode;
pNewNode->right = NULL;
pCurrentNode->right = pNewNode;
} // end if
} // end function: insert
void print_table()
{
struct Node *pCurrentNode = head;
if( pCurrentNode == NULL ) return;
// implied else, list not empty
while( pCurrentNode )
{
printf("%s \n",pCurrentNode->element);
pCurrentNode = pCurrentNode->right;
} // end while
} // end function: print_table
void cleanup()
{
struct Node *pCurrentNode = head;
while( pCurrentNode )
{
pCurrentNode = pCurrentNode->right;
free( pCurrentNode->left );
}
} // end function: cleanup
int main ()
{
// exercise the insert function
insert("table element1"); // append first element
insert("table element2"); // append second element
insert("table element4"); // append third element
insert("table element3"); // insert forth element
insert("table element3"); // duplicate within list
insert("table element4"); // duplicate at end of list
print_table();
cleanup();
return 0;
} // end function: main
I tried a different implementation, it compiles and works, it does not allow duplicates.
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#define ELEMENT_SIZE 1024
typedef struct Node_s
{
char element[ELEMENT_SIZE];
struct Node_s *left, *right;
} Node;
Node * createNode(char *element)
{
Node *node = malloc(sizeof(Node));
node->left = NULL;
node->right = NULL;
memcpy(node->element, element, ELEMENT_SIZE);
return node;
}
void free_node(Node *node)
{
if(!node)
return;
free_node(node->left);
free_node(node->right);
free(node);
}
Node * insert(Node **head_ptr, char *element)
{
Node *head = *head_ptr;
if(head == NULL){
Node *node = createNode(element);
head = node;
*head_ptr = node;
return node;
}else{
int comp = strcmp(head->element, element);
if(comp < 0){
// go left
if(head->left == NULL){
// set element to be temp left
Node *node = createNode(element);
head->left = node;
return node;
}else{
return insert(&head->left, element);
}
}else if(comp > 0){
// go right
if(head->right == NULL){
// set element to be temp left
Node *node = createNode(element);
head->right = node;
return node;
}else{
return insert(&head->right, element);
}
}else{
// element exists
printf("Element \"%s\" already exists\n", element);
return NULL;
}
}
}
void print_table(Node *temp)
{
if(!temp)
return;
printf("%s \n",temp->element);
print_table(temp->left);
print_table(temp->right);
}
int main ()
{
Node *nd = NULL;
printf("Address of nd is %p\n", &nd);
Node *n1 = insert(&nd, "table element 1");
n1 = insert(&nd, "table element 2");
n1 = insert(&nd, "table element 3");
n1 = insert(&nd, "element 1");
n1 = insert(&nd, "element 2");
n1 = insert(&nd, "element 3");
n1 = insert(&nd, "alternative 1");
n1 = insert(&nd, "alternative 2");
n1 = insert(&nd, "alternative 3");
n1 = insert(&nd, "alternative 1");
n1 = insert(&nd, "alternative 2");
n1 = insert(&nd, "alternative 3");
print_table(nd);
free_node(nd);
return 0;
}

Mergesort on a linked-list using only one function, segmentation fault

I need to implement the function: struct listnode * mergesort(struct listnode *data)
My professor provided the main() function testing code. I only need to submit the mergesort function. He told us to do it in C or C++ but the test code main() he gave us is in C.
This is my code right now:
I can compile it but when I run it, it crashes. I checked debugger and it gave me segmentation fault. I am also not really sure if this function is correct since I can't get past the testing point in the main().
#include <stdio.h>
#include <stdlib.h>
struct listnode { struct listnode * next;
long value; } ;
struct listnode * mergesort(struct listnode *data)
{ int temp, finished = 0;
struct listnode *tail, *head, *ahead, *bhead, *atail, *btail;
if ( data == NULL )
return;
//Split
ahead = atail = head = data; // first item
btail = head->next; // second item
while(btail->next != NULL) // anything left
{
atail = atail->next;
btail = btail->next;
if( btail->next != NULL)
btail = btail->next;
}
bhead = atail->next; // disconnect the parts
atail->next = NULL;
//sort
mergesort(ahead);
mergesort(bhead);
//merge
if(ahead->value <= bhead->value) // set the head of resulting list
head = tail = ahead, ahead = ahead->next;
else
head = tail = bhead, bhead = bhead->next;
while(ahead && bhead)
if(ahead->value <= bhead->value) // append the next item
tail = tail->next = ahead, ahead = ahead->next;
else
tail = tail->next = bhead, bhead = bhead->next;
if(ahead != NULL)
tail->next = ahead;
else
tail->next = bhead;
return(head);
}
int main(void)
{
long i;
struct listnode *node, *tmpnode, *space;
space = (struct listnode *) malloc( 500000*sizeof(struct listnode));
for( i=0; i< 500000; i++ )
{ (space + i)->value = 2*((17*i)%500000);
(space + i)->next = space + (i+1);
}
(space+499999)->next = NULL;
node = space;
printf("\n prepared list, now starting sort\n");
node = mergesort(node);
printf("\n checking sorted list\n");
for( i=0; i < 500000; i++)
{ if( node == NULL )
{ printf("List ended early\n"); exit(0);
}
if( node->value != 2*i )
{ printf("Node contains wrong value\n"); exit(0);
}
node = node->next;
}
printf("Sort successful\n");
exit(0);
}
if ( data == NULL )
return;
You should return NULL.
btail = head->next; // second item
while(btail->next != NULL) // anything left
{
If btail is set to head->next. If head->next is NULL, you're trying to check in the loop NULL->next != NULL which isn't a thing.
if( btail->next != NULL)
btail = btail->next;
}
You need to check if btail is NULL before you check ->next. Just above you are setting btail = btail->next; so it could be set to NULL.
Also the loop above has the same issue, you need to check null before you do stuff with next.
There may be issues with the below code, but the above code needs way more error checking.
Example function to merge two already sorted lists using pointer to pointer. Since your'e only allowed a single function, you'll have to merge this logic into your mergesort() function. If this is homework, it may seem like you had too much help, but I'm not sure how else to explain the ideas shown in this example.
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
while(1){
if(pSrc1 == NULL){
*ppDst = pSrc2;
break;
}
if(pSrc2 == NULL){
*ppDst = pSrc1;
break;
}
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
*ppDst = pSrc2;
pSrc2 = *(ppDst = &(pSrc2->next));
continue;
} else { /* src1 <= src2 */
*ppDst = pSrc1;
pSrc1 = *(ppDst = &(pSrc1->next));
continue;
}
}
return pDst;
}

Resources