Building a Linked List of Strings - c

I had a singly linked list that took in integers successfully, but now I want to use strings. However it is not working. I am getting so many different errors about "casting". I am finding conflicting information online as well. One comment here, Creating linked list of strings, said not to use strcpy, but I see strcpy used in a few examples online.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
struct node {
char value[];
struct node* next; // pointer of structure type
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(char value) {
// create space for node with malloc
node_t *result = malloc(sizeof(node_t));
// set the value of the new node
result->value = value;
//strcpy(result->value, value);
// set the value's next pointer to null
result->next = NULL;
return result;
}
node_t *insert_at_head(node_t **head, node_t *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
//Prints linked list
void printlist(node_t* head) {
node_t *temporary = head;
while (temporary != NULL) {
//print out the value of the node that temporary points to
// printf("%d - ", temporary->value);
// to move along the list
temporary = temporary->next;
}
printf("\n");
}
int main() {
node_t *tmp;
// declaring head pointer
node_t *head = NULL;
// CREATING LINKED LIST
// for (int i = 0; i < 25; i++) {
// tmp = create_new_node(i);
// // sending the address of the head variable
// //calling by reference
// //SINCE HEAD IS ALREADY A NODE POINTER
// insert_at_head(&head, tmp);
// }
printlist(head);
tmp = create_new_node("I like food");
insert_at_head(&head, tmp);
}
How can I get this Linked List of string to work?
Thank you.

If you reorganize it a bit, you will be able to allocate the space the struct & the place for the string in the single malloc.
struct node
{
struct node* next; // pointer of structure type
char value[];
};
// set existing type, node, to the alias, node_t
typedef struct node node_t;
node_t *create_new_node(const char *value)
{
// create space for node with malloc
node_t *result = malloc(sizeof(*result) + strlen(value) + 1);
if(result)
{
strcpy(result->value, value);
result->next = NULL;
}
return result;
}

Please use your compiler! I ran $gcc -Wall a.c on this code and got:
a.c:7:10: error: flexible array member not at end of struct
char value[];
^
a.c: In function ‘main’:
a.c:67:5: warning: passing argument 1 of ‘create_new_node’ makes integer from pointer without a cast [enabled by default]
tmp = create_new_node("I like food");
^
a.c:15:9: note: expected ‘char’ but argument is of type ‘char *’
node_t *create_new_node(char value) {
^
a.c:70:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Now we know what the problems are. Firstly, char value[] should be char *value since it's a pointer rather than a flexible array member (FAM). You could also move the FAM to the end of the struct if you want as shown here.
Next, node_t *create_new_node(char value) is relying on a char value when you really want a string, char *value for the parameter. There are issues beyond this: you'll likely want to make a copy of the string for the node in case it disappears from the stack. This memory should be cleaned up after use.
Other tips:
Avoid noisy, redundant comments like:
// declaring head pointer
node_t *head = NULL;
malloc(sizeof(*name_of_the_var)); is safer than malloc(sizeof(node_t)); if the data changes.
node_t *insert_at_head(node_t **head, node_t *node_to_insert) modifying its parameter and returning it is a little unusual. I'd make it void to make the in-place contract explicit.
Alphabetize and remove unused imports.
Check that malloc calls succeeded.
Remember to return 0; from main.
typedef struct node node_t; is okay but also hides info--I prefer keeping the struct there.
Here's a possible rewrite:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *value;
struct node* next;
};
struct node *create_new_node(char *value) {
struct node *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->next = NULL;
node->value = strdup(value);
if (!node->value) {
fprintf(stderr, "%s:%d malloc failed\n", __FILE__, __LINE__);
exit(1);
}
return node;
}
void insert_at_head(struct node **head, struct node *node_to_insert) {
node_to_insert->next = *head;
*head = node_to_insert;
}
void print_list(struct node *head) {
for (; head; head = head->next) {
printf("%s->", head->value);
}
puts("");
}
void free_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp->value);
free(tmp);
}
}
int main() {
struct node *head = NULL;
for (int i = 0; i < 10; i++) {
char n[16];
sprintf(n, "%d", i);
insert_at_head(&head, create_new_node(n));
}
print_list(head);
free_list(head);
return 0;
}
Output:
9->8->7->6->5->4->3->2->1->0->

Related

Can I use a CreatNode function to return a struct rather than its steps repeated in All other functions?

I want to make a CreatNode() function in C to be called by other functions. I am playing around with code trying to reach great readability and functionality. The professor has a CreatEmptyList() function but not a CreatNode().She is negligent and not the capable of the concepts and C lagnguage and didn't give me an answer.
I don't need this exploration and trying ideas that come to my mind to pass the course, but my aim is to become a Dev not to graduate.
This is the code of the Prof:
typedef struct nodetype
{
int info;
struct nodetype *next;
} node;
node *head;
void createemptylist(node *head)
{
head=NULL;
}
void insertatbeginning(node *head, int item)
{
node *newNode;
/* allocate memory for the new node and initialize the data in it*/
newNode= malloc(sizeof(node));
newNode->info=item;
/* assign the value of head to the “next” of newNode*/
newNode->next=head;
/* assign the address of newNode to head */
head=newNode;
}
void insertatend(node *head, int item)
{
node *newNode;
newNode=malloc(sizeof(node));
newNode->info=item;
newNode->next=NULL;
if(head==NULL)
head=newNode;
else
{
node *prev=head;
while(prev->next!=NULL)
prev=prev->next;
prev->next=newNode;
}
}
All are the snippets from the PDF she provided not exactly a compilable code.
This is the code I am working on and it keeps giving errors:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int info;
struct Node *Next;
}ListNode;
ListNode CreatNode(ListNode *Head){///These steps not to be repeated using this function
printf("\n=================\nEntered CreatNode Function");
ListNode *NewNode;
NewNode = malloc(sizeof(ListNode));
return *NewNode;
}
void CreatList(ListNode *Head){
printf("\n=================\nEntered CreatList Function");
Head = NULL;
}
void InserBeg(ListNode *Head, int item){
///CreatNode() steps here
NewNode=CreatNode(&Head);
NewNode->info = item; ///Inesrt value
NewNode->Next = Head;///Insert Adress inside Head to the Next point
Head = NewNode;
printf("\nFinished InsertBeg Function");
printf("\nValue inserted is: %d\n=================\n", NewNode->info);
}
void Append(ListNode *Head, int item){
///CreatNode() steps here
///NewNode=CreatNode(Head);
NewNode ->info = item;
NewNode ->Next = NULL;
if (Head==NULL){
Head=ListNode
}
else{
ListNode *Prev=Head;
while(while->Prev!=NULL){
Prev = Prev->Next;
}
Prev->Next=NewNode;
}
}
int main(){
ListNode *Head;
CreatList(&Head);
InserBeg(&Head, 8);
return 0;
}
errors:
C:\Users\User\Desktop\all\C\Single Linked List test.c|27|error: incompatible types when assigning to type 'ListNode * {aka struct Node *}' from type 'ListNode {aka struct Node}'|
Undeclared NewNode struct errors since it can't see it
Any help on coding my idea in different ways or make my code work?
The provided by the professor code is very bad.
For starters she uses a global variable head. As the variable is declared in the file scope then it is already initialized as a null pointer. So this function
void createemptylist(node *head)
{
head=NULL;
}
does not make a great sense. And moreover it does nothing with the original pointer head because it accepts its argument by value. That is it deals with a copy of the value of the original pointer.
By this reason other functions insertatbeginning and insertatend are wrong because they do not change the original pointer head that they accept by value.
void insertatbeginning(node *head, int item)
{
//...
head=newNode;
}
void insertatend(node *head, int item)
{
//...
head=newNode;
//...
}
They change a copy of the value of the original pointer.
The same problem is present in your functions.
As for the function CreatNode then as is it does not make a sense.
ListNode CreatNode(ListNode *Head){///These steps not to be repeated using this function
printf("\n=================\nEntered CreatNode Function");
ListNode *NewNode;
NewNode = malloc(sizeof(ListNode));
return *NewNode;
}
For starters the parameter head is not used within the function. You need to pass an integer argument to the function that will be used as an initializer for the data member info.
Instead of an object of the type ListNode you should return a pointer to the dynamically allocated object. Otherwise the function returns a copy of the dynamically allocated object and as a result the function will produce a memory leak.
Within the functions InserBeg and Append the name NewNode is undefined as for example
void InserBeg(ListNode *Head, int item){
///CreatNode() steps here
NewNode=CreatNode(&Head);
//...
And you are calling the functions passing expressions of incompatible pointer type ListNode ** instead of ListNode *.
CreatList(&Head);
InserBeg(&Head, 8);
Here is a demonstration program that shows how the function CreateNode and for example InsertBeg can be defined.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int info;
struct Node *next;
} ListNode;
ListNode * CreateNode( int info )
{
ListNode *new_node = malloc( sizeof( *new_node ) );
if ( new_node != NULL )
{
new_node->info = info;
new_node->next = NULL;
}
return new_node;
}
int InsertBeg( ListNode **head, int info )
{
ListNode *new_node = CreateNode( info );
int success = new_node != NULL;
if ( success )
{
new_node->next = *head;
*head = new_node;
}
return success;
}
int main( void )
{
ListNode *head = NULL;
if ( InsertBeg( &head, 10 ) )
{
puts( "New node is added." );
}
else
{
puts( "Error: not enough memory." );
}
}
The program output is
New node is added.

Fixing load of null pointer of type 'Node *' error

I am working on implementing a Linked List data structure in C. Below are my current functions for my Linked List implementation file (llist.c)
#include "llist.h"
// Frees all allocated memory associated with the list pointers iteratively
void deleteList(Node **list) {
Node* ptr = *list;
Node* temp;
while(ptr != NULL) {
free(ptr->data);
temp = ptr;
ptr=ptr->next;
free(temp);
}
}
// Frees all allocated memory associated with a single node
void deleteNode(Node **toDelete) {
Node * del = *toDelete;
free(del->data);
free(del);
}
// Allocates memory for a new string and returns a pointer to the memory
Node *newNode(char *string) {
unsigned long len = strlen(string);
printf("length : %lu \n\n", len);
Node *temp = (Node*)malloc(sizeof(Node));
temp->data = (char*)malloc(len + 1*sizeof(char));
strcpy(temp->data, string);
temp->next = NULL;
return temp;
}
// Removes a node from the front of a list
Node *pop(Node **list) {
Node *newptr = (*list)->next;
deleteNode(list);
return newptr;
}
// Adds a node to the front of a list
void push(Node **list, Node *toAdd) {
toAdd->next = *list;
*list = toAdd;
}
// Return a list of pointers in order
void reverseOrder(Node **list) {
Node* prev = NULL;
Node* current = *list;
Node* next;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*list = prev;
}
// Prints the string stored in a single node
void printNode(Node *singleNode) {
printf("Data : %s", singleNode->data);
}
// Prints an entire linked list. Nodes are printed from first to last
void printLinkedList(Node *linkedList) {
Node *temp = linkedList;
while(temp!=NULL) {
printf("Data : %s", temp->data);
temp = temp->next;
}
}
When testing the implementation in my driver file, I receive the following error
runtime error: load of null pointer of type 'Node *' (aka 'struct listNode *')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior llist.c:49:19
where line 49 corresponds to toAdd->next = *list in the llist.c file
I am struggling to figure out why this error is occurring as I am calling my push function with the appropriate parameters to an initially empty (NULL) linked list.
driver file (testllist.c) for reference:
#include "llist.h"
int main (int argc, char *argv[]) {
printf("argc: %d", argc);
printf("\n\n");
int num_inputs = argc;
Node **list = NULL;
if (argc == 1) {
printf("No arguments passed.\n");
} else {
for (int i = 1; i < num_inputs; i++) {
printf("String is: %s\n", argv[i]);
Node *n = newNode(argv[i]);
printf("String is : %s\n\n", argv[i]);
push(list, n);
printLinkedList(*list);
}
reverseOrder(list);
pop(list);
deleteList(list);
}
return 0;
}
header file (llist.h) where Node data type and functions are defined
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// The listNode data type for storing entries in a linked list
typedef struct listNode Node;
struct listNode {
char *data;
Node *next;
};
// Frees all allocated memory associated with the list pointers iteratively
void deleteList(Node **list);
// Frees all allocated memory associated with a single node
void deleteNode(Node **toDelete);
// Allocates memory for a new string and returns a pointer to the memory
Node *newNode(char *string);
// Removes a node from the front of a list and returns a pointer to said node
Node *pop(Node **list);
// Adds a node to the front of a list
void push(Node **list, Node *toAdd);
// Return a list of pointers in order
void reverseOrder(Node **list);
// Prints the string stored in a single node
void printNode(Node *singleNode);
// Prints an entire linked list. Nodes are printed from first to last
void printLinkedList(Node *linkedList);
As you initialized the pointer list as a null pointer
Node **list = NULL;
then within the function push you may not dereference this pointer
void push(Node **list, Node *toAdd) {
toAdd->next = *list;
*list = toAdd;
}
And the error message reports this problem.
You should declare the pointer like
Node *list = NULL;
and pass it to functions that expect an object of the type Node ** like for example
push( &list, n );
And it would be much better if the function will be declared like
int push( Node **list, const char * );
That is it should report whether a new node was successfully pushed or not and the allocation of the new node should be hidden from the user that calls the function.
Pay attention to that for example the function deleteNode does not make a great sense.
void deleteList(Node **list) {
Node* ptr = *list;
Node* temp;
while(ptr != NULL) {
free(ptr->data);
temp = ptr;
ptr=ptr->next;
free(temp);
}
}
The pointer to the head node of the list is passed by reference. However within the function its value is not being changed. So after exiting the function the pointer to the head node will still have its original value.
The function can be defined the following way
void deleteList( Node **list )
{
while ( *list != NULL )
{
Node *ptr = *list;
*list = ( *list )->next;
free( ptr->data );
free( ptr );
}
}
The function pop does not check whether the passed pointer to the head node of the list is equal to NULL.
Node *pop(Node **list) {
Node *newptr = (*list)->next;
deleteNode(list);
return newptr;
}
Also it returns a pointer to the next node in the list that becomes the current head node. But the returned pointer is not used in main
pop(list);
Pay attention to that the expression 1 * sizeof( char ) does not make a sense in the expression used as an initializer in this declaration
temp->data = (char*)malloc(len + 1*sizeof(char));
Either write
temp->data = (char*)malloc(len + 1);
or like
temp->data = (char*)malloc( ( len + 1 )*sizeof(char));

Double pointer in linked list

I almost figured out this code, but there are two details I can't figure out.
I found this code on YouTube.
source: https://www.youtube.com/watch?v=VOpjAHCee7c
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int vaule;
struct node *next;
}node_t;
void printlist(node_t *head)
{
node_t *temp = head;
while(temp != NULL)
{
printf("%d - ", temp->vaule);
temp = temp->next;
}
printf("\n");
}
node_t *create_node(int var)
{
node_t *res = malloc(sizeof(node_t));
res->vaule = var;
res->next = NULL;
return res;
}
node_t *insert_at_head(node_t **head, node_t *node_to_insert)
{
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
void find_node()
int main()
{
node_t *tmp;
node_t *head = NULL;
for(int i = 0; i < 15; i++)
{
tmp = create_node(i);
head = insert_at_head(&head, tmp);
}
printlist(head);
return 0;
}
1) Why do we use the nested struct?
typedef struct node{
int vaule;
struct node *next;
}node_t;
I know about nested structures but I didn't understand why we use it here.
2) Why do we use double pointer?
node_t *insert_at_head(node_t **head, node_t *node_to_insert)
{
node_to_insert->next = *head;
*head = node_to_insert;
return node_to_insert;
}
if I change this code like this:
node_t *insert_at_head(node_t *head, node_t *node_to_insert)
{
node_to_insert->next = head;
return node_to_insert;
}
then nothing will change
Why do we use the nested struct?It's not a nested struct. struct node *next is a pointer, and as its name indidcates, it points to the next element.
Why do we use double pointer? Read this: How do I modify a pointer that has been passed into a function in C?
1)Why do we use the nested struct?
It is not a nested struct, but a linked list. Each node has a pointer to the next node (or to NULL for the last node of a list
2)Why do we use double pointer?
C only passes parameters by value. The idiomatic ways to change a variable from the caller are:
assign the return value to that variable. It is the best way, but you can only return one single value that way
pass a pointer to the variable and use the pointer to change the value. As we want to change the value of head which is already a pointer, we have to pass a pointer to pointer.
Here the write of the code has decided to change the passed header to clearly show that it is an input/output parameter, and also returns it because it had no better value to return.

Converting array to a generic list in C

I have created a new struct that represents a linked list and two functions listDestroy and arr2list. The second function gets a generic array and converts it into a list. The code:
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(List* list, void freeElement(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
if (length == 0 || !copyElement || !freeElement) {
return NULL;
}
struct List* head = (struct List*) malloc(sizeof(struct List));
if (head == NULL) {
return NULL;
}
List* current_node = head;
for(int i = 0; i < length; i++) {
current_node->value = copyElement(array[i]);
struct List* new_node = (struct List*) malloc(sizeof(struct List));
if (new_node == NULL) {
listDestroy(head, freeElement);
return NULL;
}
current_node->next = new_node;
current_node = new_node;
}
return head;
}
I think that I have a problem with the copyElement(array[i]);. I want to pass a generic array of elements to arr2list but I'm not sure if void* array[] is the right way. If I change it to be void* array I get an error for array[i]. What is the right way to make it work? Is it possible to also show a working example?
The last node of the list ends up with a NULL next and a garbled value. I don't think this is what you wanted. Try this loop:
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = malloc(sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = copyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
This uses a pointer to pointer so that we can update head or next depending on where we are in the loop without an extra if condition. Note that the allocaction of head is inside the loop now, so we always allocate exactly as many nodes as we need.
void* array[] is completely valid in this scenario, although I don't see the point of copyElement.
Perhaps just remove it and use array[i] instead?
I'd also like to point out a few mistakes that you may want to fix in your code:
Don't cast the result of malloc and use sizeof(*var) instead of sizeof(type). They're unneeded and may cause issues later on if you change the type of head. So, change this (and any later occurrences):
struct List* head = (struct List*) malloc(sizeof(struct List));
to this:
struct List* head = malloc(sizeof(*head));
Consider returning struct List * from arr2list. Change this:
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
to this:
struct List* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
Also, use either struct List * or List *. Inconsistencies may make it hard to understand your code.
It may be clearer if you pass function pointers to your functions instead of just functions. So, instead of doing this:
returntype func(params),
do this:
returntype (*func)(params),
You may also want to change malloc calls to calloc calls. calloc zeroes out memory, which can help in debugging. Change:
malloc(...)
to:
calloc(1, ...)
Here's an example combining code fixes from Joshua's post and mine:
list.c:
#include <stdlib.h>
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(struct List* list, void (*freeElement)(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
struct List* arr2list(void* array[], int length, void (*freeElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
if (length == 0 || !freeElement) {
return NULL;
}
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = array[i];
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.c"
void free_element(void *el)
{
free(el);
}
int main(void)
{
List *list;
int ctr;
void *array[4];
for(ctr = 0; ctr < 4; ctr++)
{
/* Don't usually pass sizeof(type) to malloc(),
* but these are extenuating circumstances. */
array[ctr] = malloc(sizeof(int));
if(!array[ctr]) return 1;
*(int *)array[ctr] = ctr * 4;
}
list = arr2list(array, sizeof(array)/sizeof(array[0]), free_element);
while(list)
{
printf("%d\n", *(int *)list->value);
list = list->next;
}
listDestroy(list, free_element);
return 0;
}
Output:
0
4
8
12
One last note: you may consider creating a header file that defines these structures and functions (and remove the structure from list.c). Here's an example:
#ifndef LIST_H
#define LIST_H 1
typedef struct List { // Remove this from list.c
struct List* next;
void *value;
} List;
void listDestroy(struct List*, void (*)(void*));
struct List* arr2list(void* [], int, void (*)(void*));
#endif

Segmentation fault when freeing String in a Struct - C

I've been stuck on a segmentation fault of a long time. I declared a struct with a pointer to a string. I wrote two functions, create and remove to manipulate values. The struct is as follows:
#include "filename.h"
//*in filename.h:* typedef struct linkNode linkNode_t;
struct linkNode{
struct linkNode *next;
char *value;
};
The create function will first allocate memory for the node, then allocate memory for the value, and then copy the input value into the value field:
linkNode_t* create(char* stuff){
linkNode_t *ptr=malloc(sizeof(linkNode_t));
if(ptr==NULL){
printf("malloc failure");
return NULL;
}
char* tempvalu=malloc(sizeof(char)*strlen(stuff)+1);
if(tempvalu==NULL){
printf("malloc failure");
return NULL;
}
strcpy(tempvalu,stuff);
ptr->next=NULL;
ptr->value=tempvalu;
return ptr;
}
A function is used to insert a node into the linked list:
linkNode_t* insertLast(linkNode_t* start, linkNode_t* newNode){
linkNode_t* current=start;
while(current->next!=NULL){
current=current->next;
}
//now current points to the last element in the linked list
current->next=newNode;
return start;
}
The part causing me problem is as follows:
linkNode_t* removebyValue(linkNode_t* start, char* valu){
/**removes the first instance of a node with a certain value. Return *start after removing.
if linked list becomes empty, return NULL*/
linkNode_t *current=start;
linkNode_t *previous=start;
while(current!=NULL){
if(strcmp(valu,current->value)==0) {//found the node to delete
if(current==start){//removing the head
linkNode_t* retvalue= current->next;
free(current->value);
free(current);
return retvalue;
}
else{ //removing other elements in the linked list
previous->next=current->next;
free(current->value);
free(current);
return start;
}
}
else{
previous=current;
current=current->next;
}
}
return start;
}
In the Main I created a linked list of two elements,1 and 2, and tried to free element 1 when segmentation fault occured.
int main(){
linkNode_t *pt1=create("1");
pt1=insertLast(pt1,create("2"));
removebyValue(pt1,"1"); //Causes seg fault. If I replace "1" by "2" nothing happens
Can someone give some suggestions on this? Thanks in advance
EDIT: I put all the code that could be related since someone said the sections I put on didn't have an error
I think you're over-thinking the removal of a node while maintaining the start pointer properly. Consider a hopefully simpler approach.
typedef struct node_t
{
struct node_t* next;
char* value;
} node_t;
node_t* remove(node_t *start, const char* valu)
{
node_t* current=start;
node_t* prev=NULL;
while(current && strcmp(current->value, valu))
{
prev = current;
current = current->next;
}
if (current)
{
if (prev) // we're not deleting start node
prev->next = current->next;
else // we *are* deleting start node
start = current->next;
// now the node is unlinked. remove it.
free(current->value);
free(current);
}
return start;
}
here's an alternative test code that works fine, take a loot at it and see if it helps.
in addition, you can add
typedef struct node_t {
struct node_t* next;
char* value;
} node;
this may appear simpler to understand, but it isn't because nature of typedef is confusing.
I STRONGLY suggest you take a look at https://github.com/torvalds/linux/blob/master/Documentation/CodingStyle
This is the coding style of the linux kernel, it is very short and simple, not particularly a law, but it is worth noting...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node_t {
struct node_t* next;
char* value;
};
struct node_t* create(const char* istr)
{
struct node_t* ptr = (struct node_t*)malloc(sizeof(struct node_t));
char* tmp = (char*)malloc(sizeof(char) * (strlen(istr) + 1));
strcpy(tmp, istr);
ptr->next = 0;
ptr->value = tmp;
return ptr;
}
struct node_t* remove(struct node_t* start, const char* value)
{
struct node_t* current = start;
struct node_t* prev = start;
while (current != 0) {
if (!strcmp(value, current->value)) {
if (current == start) {
struct node_t* retval = current->next;
free(current->value);
free(current);
return retval;
} else {
/* nothing happens */
return 0;
}
}
}
}
int main(const int argc, const char** argv)
{
struct node_t* pt = create("1");
printf("%s\n", pt->value);
pt->next = create("2");
printf("%s\n", pt->next->value);
remove(pt, "1");
return 0;
}

Resources