Memory leak detection caused errors - c

Well basically I had memory leaks. So I wanted to fix them! added free () in some functions. Run valgrind and got successful message All leak memories fixed or smth like that! And after that I have got bunch of errors :( I THINK i have put free() right. It is easy to get confused because there are node as a pointer and node as a struct (look in file.h). Any help appreciated. Thank you. Sorry if this question is simple. i am beginner.....
code in file.h
struct node {
int value;
struct node * next;
};
typedef struct node List;
int is_empty(List *);
List *add_node(List *, int);
List *remove_node(List *, int);
List *create_node(int);
char *tostring(List *);
code in file.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#define STRSIZE 128 /*assume string representation fits*/
/* Return true if the list h is empty
* and false otherwise.
*/
int is_empty(List *h) {
return h == NULL;
}
/* Create a list node with value v and return a pointer to it
*/
List *create_node(int v) {
List *node = malloc(sizeof(List));
free(node);
node->value = v;
node->next = NULL;
return node;
}
/* Insert a new node with the value v at the
* front of the list. Return the new head of
* the list.
*/
List *add_node(List *h, int v) {
List *node = create_node(v);
node->next = h;
return node;
}
/* Remove the first node in the list h that
* has the value v. Return the head of the
* list.
*/
List *remove_node(List *h, int v) {
List *curr = h;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
h = h->next;
return h;
}
/* Look for the value in the list (keeping the pointer to
* the previous element so that we can remove the right
* element) */
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
curr->next = curr->next->next;
return h;
}
}
/* Return a string representation of the list pointed to by h.
*/
char *tostring(List *h) {
char *str= malloc(STRSIZE);
char num[4]; /* assume integer has max. four digits*/
free(str);
str[0] = '\0';
while (h != NULL) {
sprintf(num, "%d", h->value);
strncat(str, num, STRSIZE - strlen(str) - 1);
h = h->next;
}
return str;
}

Possibly you want
temp = curr->next;
curr->next = curr->next->next;
free (temp);
In the current state of your code the remove_node is leaky (leaks the entire list actually, if you remove all the nodes).
Also, to stop memory leak in the tostring function, the caller of this function has the responsibility to free the string returned by tostring.

In your create_node(), why do you have a free()? You should remove that free().
In your remove_node(), you need to always return the head. I think the following recursive method should work. The recursive function will find the node to be deleted and return the next node. It returns the same node if nothing is deleted. Keeps recursing until a node with the value is found or end of the list. The main thing to check is, does it work when
Removing the head node
empty list
Removing the last node
Removing a middle node
The following code is not tested :-).
You mentioned you still have memory leak. As mentioned by Karthik, your toString() function allocates memory and it is up to the caller to free it. So make sure every time you call toString() function, a free() is called also. Otherwise you would be leaking memory.
List *remove_node(List *h, int v) {
List *retval = remove_recurse(h,v);
// if retval is different from head, means head is removed. return new head.
// Otherwise return old head.
return (retval!=h) ? retval : h;
}
List *remove_recurse(List *node, int v) {
if(node==NULL) return NULL;
List *retval = node; // default return current node
if(node!=NULL && node->value==v) { // need to remove node
retval = node->next; // return the next node
free(node); // delete node
}
else {
List *temp = remove_recurse(node->next,v);
// if next node was deleted, point to new node
if(node->next!=temp) node->next=temp;
}
return retval;
}

With this
List *node = malloc(sizeof(List));
free(node);
you allocate a node(List) then let node point to it, then you free what node is pointing to so after free it is pointing to some unallocated space somewhere in memory then you start assigning to that memory:
node->value = v;
node->next = NULL;
which causes undefined behavior, it is definitely wrong but will not be detected by the compiler.
remove free(node)
List *create_node(int v)
{
List *node = malloc(sizeof(List));
node->value = v;
node->next = NULL;
return node;
}
it is more readable if you keep the name of the struct the same as the typedef i.e.
typedef struct node {...} node;
instead of creating a new alias, use instead a better variable name e.g.
node* listStartOfNodes = NULL; // always initialize

1、this function is wrong.
List *create_node(int v) {
List *node = malloc(sizeof(List));
free(node);
node->value = v;
node->next = NULL;
return node;
}
Why do you free(node)? please remove this free(node);.
And the same fault in this function, please remove free(str);
char *tostring(List *h) {
char *str= malloc(STRSIZE);
char num[4]; /* assume integer has max. four digits*/
free(str);
str[0] = '\0';
while (h != NULL) {
sprintf(num, "%d", h->value);
strncat(str, num, STRSIZE - strlen(str) - 1);
h = h->next;
}
return str;
}
2、you should modify this function:
List *remove_node(List *h, int v) {
List *curr = h;
List* freeNode = NULL;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
freeNode = h;
h = h->next;
free(freeNode);
return h;
}
/* Look for the value in the list (keeping the pointer to
* the previous element so that we can remove the right
* element) */
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
freeNode = curr->next;
curr->next = curr->next->next;
free(freeNode);
return h;
}
}

In the function remove_node
List *remove_node(List *h, int v)
{
List *curr = h,*prev;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
h = h->next;
free(curr);
return h;
}
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
prev = curr->next;
curr->next = curr->next->next;
free(prev);
return h;
}
}
You should free the memory when you no longer want that node in your case while removing the node you should free the memory.
And in the function tostring don't free the memory you just allocated free the memory in the called function after the str is no more used or required.

Related

Swapping neighbor linked list nodes

I have to make a function which swaps the neighbor nodes in a linked list with sentinel. Something like this: 1-2-3-4-5 -> 2-1-4-3-5, but I don't know how to do that. Can somebody help me?
#include <stdio.h>
#include <stdlib.h>
typedef struct _listelem {
int a;
struct _listelem* next;
} listelem;
void reverse_pairs(listelem* a)
{
listelem* head = NULL;
listelem* tail = NULL;
head = a->next;
tail = a->next;
while (head->next != NULL)
{
head = head->next->next;
tail = head;
}
return head;
}
You did not show how the list with a sentinel node is built.
I suppose that the sentinel node is the first node in the list pointed to by the pointer head.
In this case the function can look the following way.
void reverse_pairs( listelem *head )
{
if (head)
{
for (; head->next && head->next->next; head = head->next->next)
{
listelem *tmp = head->next;
head->next = head->next->next;
tmp->next = head->next->next;
head->next->next = tmp;
}
}
}
As for your function implementation then it is incorrect at least because a function with the return type void may not have a statement like this
return head;
Also within this while loop
while (head->next != NULL)
{
head = head->next->next;
tail = head;
}
you are changing the local variables head and tail. Such changes do not influence on the original list.
If you have a circular list when the data member next of the last node points to the head (sentinel) node then the function can look the following way.
void reverse_pairs( listelem *head )
{
if (head)
{
for ( listelem *current = head;
current->next != head && current->next->next != head;
current = current->next->next)
{
listelem *tmp = current->next;
current->next = current->next->next;
tmp->next = current->next->next;
current->next->next = tmp;
}
}
}
While the answer from #VladFromMoscow shows the proper approach for swapping nodes in the list to accomplish your objective, if you are stuck passing a single pointer, and the function return type is fixed at void, then there is another way to go about it.
Instead of swapping nodes, you simply swap the int member value between nodes. Approaching the problem that way, the address of the first node never changes, so there is no need to pass the address of the list as a parameter.
The approach is simple. Take the current node, swap the integer value between the current and next node and advance past the nodes holding the swapped integers. To do so, you advance from the current node to the next and check if the node that follows next is NULL (marking the end of the list). If it is NULL, you are done. If it is not NULL, advance again and repeat. You can write the function either with a while() loop, e.g.
void reverse_pairs (listelem *head)
{
while (head && head->next) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
head = head->next;
if (head->next)
head = head->next;
}
}
Or, slightly less readable, using a for() loop and a ternary, e.g.
void reverse_pairs (listelem *head)
{
for (; head && head->next;
head = head->next->next ? head->next->next : NULL) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
}
}
Example Use/Output
With a normal list where the last pointer is NULL, your output printing the original list, calling reverse_pairs(), and then outputting the modified list would look as follows:
$ ./bin/lls_revpairs
1 2 3 4 5
2 1 4 3 5
Complete Test Code
The complete test code is included below. Compiling as normal will use the for() loop above, or adding the define -DUSEWHILE, to your compile string will cause the while() loop form of the function to be used:
#include <stdio.h>
#include <stdlib.h>
typedef struct _listelem {
int a;
struct _listelem* next;
} listelem;
/** add node at end of list, update tail to end */
listelem *add (listelem **head, int v)
{
listelem **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*node = malloc (sizeof *node); /* allocate new node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
node->a = v; /* initialize members values */
node->next = NULL;
while (pn) {
ppn = &pn->next;
pn = pn->next;
}
return *ppn = node; /* add & return new node */
}
#ifdef USEWHILE
/** reverse node pairs in list - while loop */
void reverse_pairs (listelem *head)
{
while (head && head->next) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
head = head->next;
if (head->next)
head = head->next;
}
}
#else
/** reverse node pairs in list - for loop + ternary */
void reverse_pairs (listelem *head)
{
for (; head && head->next;
head = head->next->next ? head->next->next : NULL) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
}
}
#endif
/** print all nodes in list */
void prn_list (listelem *l)
{
if (!l) {
puts ("list-empty");
return;
}
size_t i = 0;
for (listelem *n = l; n && i < 10; n = n->next, i++)
printf (" %d", n->a);
putchar ('\n');
}
int main (void) {
listelem *list = NULL;
for (int i = 1; i <= 5; i++)
add (&list, i);
prn_list (list);
reverse_pairs (list);
prn_list (list);
}

Why deleting function gives error on linked-list in C

I am currently working on a program based on linked-list. But my delete function causes crashes on my program. I want to allow users to delete a flight by it's fligt number. But I don't know what causes crash. How to fix this? Thanks
struct flight {
int number;
char source[20];
char destination[20];
struct flight* next;
};
void enter();
void display();
void delete();
int count();
typedef struct flight NODE;
NODE* head_node, * first_node, * temp_node = 0, * prev_node, next_node;
int data;
char data2[20], data3[20];
void delete()
{
temp_node = (NODE*)malloc(sizeof(NODE));
temp_node = first_node;
int counter, flightno, j;
temp_node->number = data;
counter = count();
printf("\nEnter flight number to delete: \n");
scanf("%d", &flightno);
for (j = 0; j <= counter; j++)
{
if (flightno == data) {
temp_node = temp_node->next;
first_node = temp_node;
printf("\nFlight log deleted.\n");
}
else
{
printf("Flight number not found.");
}
}
}
int count()
{
int count = 0;
temp_node = first_node;
while (temp_node != 0) {
count++;
temp_node = temp_node->next;
}
return count;
}
Short answer: Avoid global variables!
In your delete function you set the value of the global variable temp_node.
Then you call the function count. In count you also use the global variable temp_node. You change it until it has the value NULL.
Then back in the delete function, you do:
temp_node = temp_node->next;
Dereference of a NULL pointer! That is real bad and crashes your program.
So to start with: Get rid of all global variables
As an example, your count function should be:
int count(NODE* p)
{
int count = 0;
while (p != NULL) {
count++;
p = p->next;
}
return count;
}
and call it like: counter = count(first_node);
And your delete function could look like:
NODE* delete(NODE* first_node) { ... }
That said ...
The principle in your delete function is wrong. You don't need to count the number of nodes. Simply iterate until you reach the end, i.e. next is NULL.
Further - why do you malloc memory in the delete function? And why do you overwrite the pointer just after malloc? Then you have a memory leak.
temp_node = (NODE*)malloc(sizeof(NODE)); // WHY??
temp_node = first_node; // UPS... temp_node assigned new value.
// So malloc'ed memory is lost.
Now - what happens when you find the matching node:
if (flightno == data) {
temp_node = temp_node->next;
first_node = temp_node; // UPS.. first_node changed
printf("\nFlight log deleted.\n");
}
Then you change first_node. So all nodes before the current node is lost! That's not what you want. You only want to change first_node when the match is on the very first node in the linked list.
Then: for (j = 0; j <= counter; j++) --> for (j = 0; j < counter; j++) But as I said before... don't use this kind of loop.
Use something like:
while (temp_node != NULL)
{
...
temp_node = temp_node->next;
}
BTW: Why do you do a print out in every loop? Move the negative print out outside the loop.
A delete function can be implemented in many ways. The below example is not the most compact implementation but it's pretty simple to understand.
NODE* delete(NODE* head, int value_to_match)
{
NODE* p = head;
if (p == NULL) return NULL;
// Check first node
if (p->data == value_to_match)
{
// Delete first node
head = head->next; // Update head to point to next node
free(p); // Free (aka delete) the node
return head; // Return the new head
}
NODE* prev = p; // prev is a pointer to the node before
p = p->next; // the node that p points to
// Check remaining nodes
while(p != NULL)
{
if (p->data == value_to_match)
{
prev->next = p->next; // Take the node that p points to out
// of the list, i.e. make the node before
// point to the node after
free(p); // Free (aka delete) the node
return head; // Return head (unchanged)
}
prev = p; // Move prev and p forward
p = p->next; // in the list
};
return head; // Return head (unchanged)
}
and call it like:
head = delete(head, SOME_VALUE);
You are probably making an extra loop in your delete function. You should check if you are deleting an node which isn't part of your linked list.

How to free more complex nested structs

Solution in comments.
typedef struct Vertex {
int i;
int color;
} vertex;
typedef struct Edge {
vertex v1;
vertex v2;
} edge;
typedef struct Node {
void *p;
struct Node *next;
} node;
Basically this is a linked list (of nodes).
In my program I know if a node array holds edges or vertices.
I'm not sure how to free a list of edges properly, I've tried the following:
static void freeEdgeList(node *list) {
if (list == NULL) return;
node *ptr = list;
node *tmp;
do {
tmp = ptr->next;
free(&((*((edge *)(ptr->p))).v1));
free(&((*((edge *)(ptr->p))).v2));
free(ptr->p);
free(ptr);
} while ((ptr = tmp) != NULL);
}
Because my struct Edge doesn't store pointers, is it enough to free the edge struct, without freeing the vertices stored in the edge?
I'm a little confused.
Edit:
static int addEdge(edge *e, node **list) {
if ((*list) == NULL) {
(*list) = malloc(sizeof(node));
if ((*list) == NULL) return -1;
(*list)->p = malloc(sizeof(edge));
if ((*list)->p == NULL) return -1;
memcpy(&((*list)->p), &e, sizeof(edge));
(*list)->next = NULL;
} else {
node *tmp = (*list);
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = malloc(sizeof(node));
if (tmp->next == NULL) return -1;
tmp = tmp->next;
tmp->p = malloc(sizeof(edge));
if (tmp->p == NULL) return -1;
tmp->next = NULL;
memcpy(&(tmp->p), &e, sizeof(edge));
}
return 0;
}
This is the function that adds edges to a list (initially the list passed in is NULL).
It seems to add the edges correctly because I can output the list to the console just fine.
But if I try to free with:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
I get different error (segfault, invalid pointer)
You can only pass to free exactly what was returned from malloc and family. Since you presumably called malloc to allocate a node, you only need to free a node.
Neither vertex nor edge contain fields that are pointers, so there is nothing else to free. All you need to do is:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
EDIT:
In the code where you add an edge, you incorrectly do this:
memcpy(&((*list)->p), &e, sizeof(edge));
...
memcpy(&(tmp->p), &e, sizeof(edge));
Since e is a edge *, what this is doing is copying the pointer value e to the field p instead of what it points to. That results in the edge object pointed to by p having invalid values. You instead want:
memcpy((*list)->p, e, sizeof(edge));
...
memcpy(tmp->p, e, sizeof(edge));
This will copy the values contained in the edge that e points to.
The rule is if you don’t allocate it you don’t free it. The struct Edge doesn’t contain any dynamic memory allocation or pointers, as you said, so you don’t free them yourself. The memory is allocated as part of Edge and be freed when you free it.
So remove the free()s from v1 and v2 and only use free(ptr->p).
Edit: Seems I didn't quite get it yet..
Thanks for your help, many thanks! That makes it clear to me.
while (list) {
node *tmp = list;
list = list->next;
free(&(tmp->p));
free(tmp);
}
This solution worked, I needed to pass the address of the pointer to free, not the pointer itself, I don't quite understand why though.
Yes, it's correct. Since you are not malloc()ing the vertex (they aren't pointers, but variables allocated inside the Edge structure) a simple free() for the Edge structure will suffice
As others have mentioned freeEdgeList needs a fix [so follow their responses].
In addEdge, your memcpy calls are incorrect. You are copying to/from the address of a pointer and not what the pointer points to.
You want: memcpy((*list)->p, e, sizeof(edge)) and memcpy(tmp->p, e, sizeof(edge))
Also, in addEdge, if *list == NULL, you don't set it to the first/new element.
Also, the code can be simplified a bit. For example, using *list everywhere is a bit cumbersome.
Here's a refactored version with the memcpy and *list bugs fixed:
static int
addEdge(edge *e, node **list)
{
node *head = *list;
node *cur;
node *prev;
int ret = -1;
// find the end of the list
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next)
prev = cur;
do {
// allocate new node
cur = malloc(sizeof(node));
if (cur == NULL)
break;
cur->next = NULL;
// add pointer to new edge
cur->p = malloc(sizeof(edge));
if (cur->p == NULL) {
free(cur);
break;
}
// copy in the edge data
memcpy(cur->p,e,sizeof(edge);
// link in new node
if (prev != NULL)
prev->next = cur;
else
head = cur;
// adjust list pointer
*list = head;
ret = 0;
} while (0);
return ret;
}

ANSI C S-Linked List - deleteLast() not functioning correctly

When trying to run my deleteLast() function twice (to get an empty list) on a linked list with two nodes, I am running into a problem. The code compiles and runs, but when I call traverse() on my empty linked list, I get an infinite while loop, and I cannot determine why.
Oddly enough, if I call deleteFirst() twice instead of deleteLast(), the program runs and terminates properly.
Below is the code for my methods:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
struct NODE
{
struct NODE *link;
int value;
};
typedef struct NODE Node;
/* Deletes the first item in the list and returns next item */
Node *deleteFirst(Node **ptrToHeadPtr)
{
Node *current;
// If list is empty do nothing
if (*ptrToHeadPtr == NULL)
return NULL;
else
{
current = *ptrToHeadPtr;
*ptrToHeadPtr = current->link;
free(current);
}
return *ptrToHeadPtr;
}
/* Inserts a new Node to the end of the list and returns it */
Node *insertLast(Node **ptrToHeadPtr, int val)
{
Node *current, *lastNode;
lastNode = (Node *)malloc( sizeof (Node) );
// Check if malloc was successful
if(!lastNode) return NULL;
lastNode->value = val;
lastNode->link = NULL;
if (*ptrToHeadPtr == NULL)
*ptrToHeadPtr = lastNode;
else
{
current = *ptrToHeadPtr;
// Walk to the end of the list
while(current->link != NULL)
current = current->link;
// Insert new item at the end of the list
current->link = lastNode;
}
return lastNode;
}
/* Deletes the last Node in the list and returns*/
Node *deleteLast(Node **ptrToHeadPtr)
{
Node *current, *previous;
/* If list is empty do nothing */
if (*ptrToHeadPtr == NULL)
return NULL;
current = *ptrToHeadPtr;
previous = NULL;
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL;
free(current);
return NULL;
}
else
{
/* Walk to the end of the list */
while (current->link != NULL)
{
previous = current;
current = current->link;
}
previous->link = NULL;
free(current);
return previous;
}
}
/* Traverses the list, printing the value of each Node */
void traverse(Node*p)
{
while( p!= NULL )
{
printf("%d ",p->value);
p=p -> link;
}
}
/* Walks through the linked list, freeing memory of each Node */
void freeList(Node *p)
{
Node *temp;
while( p != NULL )
{
temp = p;
p = p-> link;
free(temp);
}
}
int main()
{
Node *headPtr = NULL;
insertLast( &headPtr, 33 );
insertLast( &headPtr, 35 );
traverse(headPtr);
printf("\n");
deleteFirst ( &headPtr );
traverse(headPtr);
printf("\n");
deleteLast ( &headPtr );
traverse(headPtr);
freeList(headPtr);
return 1;
}
In your deleteLast() function (They're called functions in C, just so you know, not methods. Not trying to sound snarky.)
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL; // CHANGE THIS TO =, NOT ==
free(current);
return NULL;
}
edit: Just like the above poster suggested, you should definitely compile with -Wall (the W is case sensitive, must be capitalized.) It would have caught this.

C - Linked Lists - Deleting Head - Segmentation Fault

I am working on a problem for a class and we're learning linked lists in C. I was given a section of code to complete, specifically the delete a node section and I'm having a problem deleting head. Every time I try to delete head I receive a segmentation fault. Can someone tell me what I'm doing wrong?
EDIT2
My teacher wrote everything but the lookup and delete functions.
I have fixed the glaring errors pointed out by the gentleman from Moscow and Mr. Petriuc, however the code still doesn't run. It does compile, but there is still a problem in head.
Here is the full code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "linkedList.h"
// keep an unsorted array of char *'s, strings.
/*
Create an empty node, return 0 if fail, 1 if succeed
*/
struct node * createNode() {
struct node *p = (struct node *) malloc(sizeof(struct node));
if (p == NULL) return 0;
p->prev = p->next = NULL;
p->data = NULL;
}
/*
Lookup string in the list, return pointer to node of first occurence, NULL if not found.
*/
struct node * lookup(struct node *head, char *s) {
struct node *p;
for(p=head; p!=NULL; p=p->next){
if(strcmp(s,p->data)==0){
return p;
}
// just like print, but check if strcmp(s, p->data) == 0, and if so then return p
}
return NULL;
}
/*
Insert new string into the linked list, return 1 if success, 0 if fail.
*/
int insert(struct node **head, char *newS, int insertDuplicate) {
struct node *p = lookup(*head, newS);
if (p == NULL || insertDuplicate) {
// create a new node, put it at the front.
p = createNode();
if (p == NULL) return 0;
// put the string in the new node
p->data = (char *) malloc(sizeof(char) * (1 + strlen(newS)));
if (p->data == NULL) return 0;
strcpy(p->data, newS);
// note: make changes and use old head before setting the new head...
p->next = *head; // next of new head is previous head
if (*head != NULL)
(*head)->prev = p; // previous of old head is new head
*head = p; // set the new head
}
return 1;
}
/*
Remove string from list if found, return 1 if found and deleted, 0 o/w.
*/
int delete(struct node **head, char *s) {
struct node *p,*pr,*ne;
// first do a lookup for string s, call lookup.
p=lookup(*head, s);
if(p==*head){
*head = p->next;
free(p);
return 1;
}
if(p!=NULL){
printf("%s",p);
pr = p->prev;
ne = p->next;
free(p->data);
free(p);
if(pr==NULL||ne==NULL){
return 0;
}
pr->next=ne;
ne->prev=pr;
// if lookup returns NULL, done, return 0.
// if lookup returns p, not NULL,
// pr = p->prev, ne = p->next
// set pr->next to ne, ne->prev to pr
// but what if pr or ne is NULL
// and note that we need node **head because if delete head,
// need to update head pointer back in calling function, in
// here if you want head probably do *head. like in insert.
// also, before the pointer to the one you're deleting is gone,
// free p->data and p.
return 1;
}
return 0;
}
void print(struct node *head) {
struct node *p;
for(p = head; p != NULL ; p = p->next) {
printf("%s\n", p->data);
}
}
You are doing
p->next = *head;
But p is not assigned anywhere.
Your function does not make sense. You call the function lookup three times.
Moreover you use pointers that were not initialized like for example
p->next = *head;
or
printf("%s",p);
pr = p->prev;
ne = p->next;
The function can be written the following way
int delete( struct node **head, char *s )
{
int success;
struct node *target = lookup( *head, s );
if ( ( success = target != NULL ) )
{
if ( target->prev != NULL )
{
target->prev->next = target->next;
}
else
{
*head = target->next;
}
if ( target->next != NULL )
{
target->next->prev = target->prev );
}
free( target );
}
return success;
}
Take into account that the second parameter of the function and the corresponding parameter of the function lookup should be declared with qualifier const
int delete( struct node **head, const char *s ) ;
^^^^^
struct node * lookup( struct node *head, const char *s );
^^^^^^
Simplified delete() function. I inlined lookup() because the function as it is is worthless (you need a pointer to pointer, not a pointer to act upon)
/*
Remove string from list if found, return 1 if found and deleted, 0 o/w.
*/
int delete(struct node **head, char *s) {
struct node *tmp;
// first do a lookup for string s, no need to call call lookup.
for( ;*head; head = &(*head)->next ){
if (!strcmp( (*head)->data, s)) break;
}
if (!*head) return 0; // not found
tmp = *head
*head = tmp->next
free(tmp);
return 1;
}

Resources