Using fgets to read lines from a file into Binary Search Tree - c

Currently i'm trying to store each separate line in my file into a string, and then store it in a binary search tree, but a problem occurs. For some reason when I print my BST only the last line is outputted and not the first 3. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
int count;
char* key;
struct node* left;
struct node* right;
};
struct node *newNode(char* item)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->key = item;
temp->left = NULL;
temp->right = NULL;
temp->count = 1;
return temp;
};
void printInorder(struct node* root)
{
if(root != NULL)
{
printInorder(root->left);
printf("%s \n", root->key);
printInorder(root->right);
}
}
struct node* insert(struct node* node, char* key)
{
if(node == NULL)//When tree is empty
return newNode(key);
if(strcmp(key, node->key) < 0)
node->left = insert(node->left, key);
if(strcmp(key, node->key) > 0)
node->right = insert(node->right, key);
return node;
};
int main()
{
struct node *root = NULL;
int i = 0;
char str[100];
FILE* fp;
fp = fopen("textFile.txt", "r");
if ((fp = fopen("textFile.txt","r")) == NULL)
{
printf("Could not open textFile.txt\n");
exit(1);
}
while(fgets(str, 100, fp) != NULL)
{
++i;
root = insert(root, str);
printf("%3d: %s", i, str);
}
printf("bst printed\n");
printInorder(root);
return 0;
}
textFile.txt contains
bob is working.
david is a new hire.
alice is bob's boss.
charles doesn't like bob.
And when the bst is printed the only line that is outputted is the last one
Charles doesn't like bob.
Any help would really be appreciated.

Notice that when you create a node with newNode, you store a copy of the pointer passed into it, rather than a copy of the string being pointed at. This means that every time you insert a value into the tree, it stores a pointer to the str buffer in main. In other words, after you do your first insertion, things look like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | b | o | b | | i | | 0 |
+------------+ +---+---+---+---+---+...+---+
When you then read the next line of the file, you're overwriting str with the contents of that line, so the picture looks like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | d | a | v | i | d | | 0 |
+------------+ +---+---+---+---+---+...+---+
Notice that your BST now acts as though it contains "david is a new hire" even though you never inserted that value. As a result, when you try inserting "david is a new hire" into the BST, nothing happens.
The same thing happens for the next few reads, until eventually you read the final line of the file, when things look like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | c | h | a | r | l | | 0 |
+------------+ +---+---+---+---+---+...+---+
This is why you're only seeing the line about Charlie at the end - the BST is directing you to the single shared copy of the buffer.
To fix this, make your BST store copies of the strings passed into it, or copy the strings before storing them in the tree. For example, you might have the newNode function call strdup to get its own copy of the string to store:
struct node *newNode(char* item)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->key = strdup(item); // <--- here!
/* TODO: Error-handling! */
temp->left = NULL;
temp->right = NULL;
temp->count = 1;
return temp;
};
That should fix your issue. Just make sure to deallocate everything when you're done!

Related

Copy an array to linked List in each data field

First, sorry if my question has already been answered. I found some threads that are (in a way) similiar but I was not able to solve my problem.
Second, I am new to single-linked-list in C so I would be happy if you could answer my question as easy as possible.
I made a simple linke-list, that has characters in it:
#include <stdio.h>
#include <stdlib.h>
// declaration of node
struct _Node_
{
char data_string;
struct _Node_ *next;
};
int main() {
//a simple linked list with 3 Nodes, Create Nodes
struct _Node_* head = NULL;
struct _Node_* second = NULL;
struct _Node_* third = NULL;
//allocate 3 Nodes in the heap
head = (struct _Node_*)malloc(sizeof(struct _Node_));
second = (struct _Node_*)malloc(sizeof(struct _Node_));
third = (struct _Node_*)malloc(sizeof(struct _Node_));
// assign data for head
head->data_string = 'H'; //assign value according struct
head->next = second; //points to the next node
// assign data for second
second->data_string = 'E';
second->next = third;
third->data_string = 'Y';
third->next = NULL;
return 0;
}
The linked list does now look like this:
/* Linked list _Node_
head second third
| | |
| | |
+---+---+ +---+---+ +----+------+
| 1 | o-----> | 2| o-------> | 3 | NULL |
+---+---+ +---+---+ +----+------+
*/
Let's assume I have 3 arrays with the following:
char name1[] = "Joe";
char name2[] = "Eve";
char name3[] = "Brad";
And my goal is to copy this array into each data field, so the result looks like this:
/* Linked list _Node_
head second third
| | |
| | |
+-----+---+ +-------+---+ +-------+------+
| Joe | o-----> | Eve | o-----> | Brad | NULL |
+-----+---+ +-------+---+ +-------+------+
*/
How can I achieve this? I already tried adding/changing the following:
...
struct _Node_
{
char data_string[8];
struct _Node_ *next;
};
...
...
char name1[] = "Joe";
char name2[] = "Eve";
char name3[] = "Brad";
// assign data for head
head->data_string = name1; //assign value according struct
head->next = second; //points to the next node
// assign data for second
second->data_string = name2;
second->next = third;
third->data_string = name3;
third->next = NULL;
...
But all I get after compiling is:
stack_overflow.c:27:23: error: array type 'char [8]' is not assignable
head->data_string = name1; //assign value according struct
~~~~~~~~~~~~~~~~~ ^
stack_overflow.c:31:25: error: array type 'char [8]' is not assignable
second->data_string = name2;
~~~~~~~~~~~~~~~~~~~ ^
stack_overflow.c:34:24: error: array type 'char [8]' is not assignable
third->data_string = name3;
~~~~~~~~~~~~~~~~~~ ^
3 errors generated.
Maybe someone could help, I appreciate any help.
Again, sorry if this is a duplicate but I am not able to solve this with other threads..
You asked for a code example:
struct Node
{
char *data_string;
struct Node *next;
};
struct Node *newNode (char *s)
{
struct Node *node;
if (!s) return 0; // error: no string
if (!(node= malloc(sizeof(struct Node)))) return 0; // no more memory
node->data_string= malloc(strlen(s)+1);
if (!node->data_string) {
free(node);
return 0;
}
strcpy(node->data_string,s);
node->next= 0;
return(node);
}
void freeNode(struct Node *node)
{
if (!node) return;
if (node->data_string) free(node->data_string);
free(node);
}
Notes:
you alocate the memory for the string 1 more than the length because a string in C has a null terminating character.
do not use underscores before an identifier name - those are reserved for the compiler.
do not cast the result of malloc. It returns a void pointer, which is compatible with any pointer type.
this example includes all required error checking.

How does head connected to tail when deleting the list

I have a function which creates a list based on a given array,
this is the function:
typedef struct Item
{
int num;
struct Item* next;
}*PItem;
int main()
{
int Arr[N] = { 3, 4, 1, 0, 8 }, i;
PItem list = NULL, tail = NULL;
CreateListFromArray(&list, &tail, Arr);
}
void CreateListFromArray(PItem* head, PItem* tail, int *Arr)
{
int i;
PItem temp;
for (i = 0; i<N; i++)
{
temp = (PItem)malloc(sizeof(struct Item));
if (temp == NULL)
{
DeleteList(head);
Error_Msg("Memmory!");
}
temp->num = Arr[i];
temp->next = NULL;
if (*head == NULL)
*head = temp;
else
(*tail)->next = temp;
*tail = temp;
}
}
I understand that if List is empty, then head's null is initialized to the first allocated temp (arr[0]). But after that, for these arrays arr[1],..,arr[N], I update only the tail, meaning that all the tails from arr[1] to arr[N] are connected. but how does the head (arr[0]) POINTS/connected to arr[1]?
I ask this because, when I try to print the list, I use temp = head, and advance head until temp is null, but when I advance head, how does it know that it has to advance to arr[1]?
Here's the full code: http://pastebin.com/VPCfMU4X
After the first iteration of the loop, head and tail point to the same element which contains arr[0]. After the second iteration, (*tail)->next (which is the same as (*head)->next) point to the new element that contains arr[1], and tail is moved up to this value. Subsequent iterations keep appending to the end of the list.
So after one iteration, you have this:
head tail
| |
v v
---------------
| 3 | NULL |
---------------
After the second iteration, you have this:
head tail
| |
v v
--------------- ---------------
| 3 | .-----|--->| 4 | NULL |
--------------- ---------------
And the third:
head tail
| |
v v
--------------- --------------- ---------------
| 3 | .-----|--->| 4 | .-----|--->| 1 | NULL |
--------------- --------------- ---------------

Reverse direction of pointers in doubly linked list

I have a circular doubly linked list and I want to change the direction of all the next and prev pointers. I can't really figure out what the source of the error is. When I print the reversed list, it gets the first two numbers correct but past that point the links list stops printing.
struct Link
{
TYPE value;
struct Link * next;
struct Link * prev;
};
struct CircularList
{
int size;
struct Link* sentinel;
};
static void init(struct CircularList* list)
{
list->sentinel = (struct Link *) malloc(sizeof(struct Link));
list->sentinel->next = list->sentinel;
list->sentinel->prev = list->sentinel;
list->size = 0;
}
struct CircularList* circularListCreate()
{
struct CircularList* list = malloc(sizeof(struct CircularList));
init(list);
return list;
}
void circularListAddFront(struct CircularList* list, TYPE value)
{
struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
newLink->value = value;
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next = newLink;
if(circularListIsEmpty(list)) {
list->sentinel->prev = newLink;
}
list->size++;
}
void circularListRemoveFront(struct CircularList* list)
{
struct Link *temp = list->sentinel->next;
temp->next->prev = list->sentinel;
list->sentinel->next = temp->next;
free(temp);
list->size--;
}
void circularListRemoveBack(struct CircularList* list)
{
struct Link *temp = list->sentinel->prev;
temp->prev->next = list->sentinel;
list->sentinel->prev = temp->prev;
free(temp);
list->size--;
}
void circularListReverse(struct CircularList* list)
{
struct Link *link = list->sentinel->next;
while(link != list->sentinel) {
struct Link *nextTemp = link->next;
struct Link *prevTemp = link->prev;
link->prev = link->next;
link->next = prevTemp;
link = nextTemp;
}
struct Link *temp = list->sentinel->next;
list->sentinel->next = list->sentinel->prev;
list->sentinel->prev = temp;
}
If I run the following to test this I get the output 5 4 1 2 2 1 and then terminates with no errors.
struct CircularList *deque = circularListCreate();
circularListAddBack(deque, 1);
circularListAddBack(deque, 2);
circularListAddBack(deque, 3);
circularListAddFront(deque, 4);
circularListAddFront(deque, 5);
circularListAddFront(deque, 6);
circularListRemoveFront(deque);
circularListRemoveBack(deque);
circularListPrint(deque);
circularListReverse(deque);
circularListPrint(deque);
There's a bug in your circularListAddFront function, and (though not shown) probably also in circularListAddBack:
Assume this state of the list:
p+SENTINEL+n
| A |
-----|------
Now, let's say you add 42 to the front. You first allocate a new node and set its value and pointers. Also you set the sentinel next pointer:
struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
newLink->value = value;
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next = newLink;
This leads to the following state:
p+SENTINEL+n
| A |
-----| |
| |
------ |
| | |
p+42+n |
A |
| |
---------
Which is not fine, because the prev pointer of the sentinel still points to itself. You fix that directly after that:
if(circularListIsEmpty(list)) {
list->sentinel->prev = newLink;
}
list->size++;
This gives the desired result:
p+SENTINEL+n
--| A |
| | |
| ------ |
| | | |
| p+42+n |
| A |
| | |
--------------
This is fine. Now let's add a 21 to the glorious list:
----------
| |
| V
| p+SENTINEL+n
| --| A |
| | | |
| | ------ |
| | | | |
| | p+42+n |
| | A |
| | | |
| -----| |
| | |
| p+21+n |
--| A |
| |
-----------
That's the state right before that if, and it has the same issue as before: There's one prev pointer wrong, this time it's not sentinels but the one of node 42: It should point to its previous node, which is now 21, and not to the sentinel.
Since the if is not taken, the sate remains. You don't notice it until reversing the list because you don't use the prev pointers until then.
To fix that, get rid of the if and correct the logic unconditionally:
When you insert a new node to the front ("after the sentinel"), then you need to change the prev pointer of the node that was at the front before and point it to the new node:
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next->prev = newLink; // ADDITION
list->sentinel->next = newLink;
The code for reversing the list seems fine, though. And for now, I'm done with "line art ASCII graphics" :D

C - How to Iterate through sub-nodes in a linked list?

I have the following program which I'm developing:
...
typedef struct node_tag{
int id;
char pLabel[10];
struct node_tag *pNext;
struct node_tag *pInner;
}NODE;
...
int main(int argc, char** argv)
{
NODE *list = create_node("start");
add_node(&list, "MUSIC");
add_node(&list, "VIDEOS");
add_node(&list, "PICTURES");
create_sub_node( &list, "2015" ); // sub node of PICTURES
create_sub_node( &list, "Trip" ); // sub node of 2015
print_nodes(list);
return (EXIT_SUCCESS);
}
Output:
|
|-> [ID:4] PICTURES
| |-> [ID:40] 2015
| | |-> [ID:400] Trip
|
|-> [ID:3] VIDEOS
|
|-> [ID:2] MUSIC
|
|-> [ID:1] start
|
Everything works as I want so far, as can be seen on the output. However I want to implement different methodology of creating sub nodes. What I've got now is very limited as it can only create the depth of 2 sub nodes but I want to have unlimited depth:
void create_sub_node( NODE **handle, char* label )
{
NODE *new = malloc( sizeof(NODE) );
new->pNext = NULL;
new->pInner = NULL;
strncpy( new->pLabel , label , strlen(label) +1 );
if( (*handle)->pInner == NULL )
{
new->id = (*handle)->id * 10;
(*handle)->pInner = new;
}
else if( (*handle)->pInner->pInner == NULL )
{
new->id = (*handle)->pInner->id * 10;
(*handle)->pInner->pInner = new;
}
}
I tried implementing while loops that could iterate through inner nodes until they found NULL one and then creating new node. The problem I'm having is that as I iterate through the nodes, the pointer addresses change and I'm left with one big mess that's no longer working.
I tried making a copy of all the addresses of inner nodes, but then I wasn't able to re-assign them again.
The thing is that I have to add the sub node to the list so I'll be changing various pointer addresses BUT to do that It looks like I need a copy of the list where I could play with it so that the original addresses don't change.
How do I iterate through the sub nodes and create new ones so that I don't have to hard-code bunch of IF statements ?
My C is a bit rusty but:
NODE* tail(NODE* list) {
if (list == NULL) return NULL;
NODE* current = list;
while (current->pInner != NULL) { current = current->pInner; }
return current;
}
Then your function becomes:
void create_sub_node( NODE **handle, char* label )
{
NODE *new = malloc( sizeof(NODE) );
new->pNext = NULL;
new->pInner = NULL;
strncpy( new->pLabel , label , strlen(label) +1 );
NODE* last = tail((*handle));
new->id = last->id * 10;
last->pInner = new;
}
Your linked list is more like a tree:
|-> MUSIC
| |-> Punk
| |-> Funk
|-> VIDEOS
| |-> Cats
| |-> Cars
| |-> Parties
|-> PICTURES
| |-> 2014
| | |-> Skiing
| | |-> Trip
| | |-> Thksgvg
| |-> 2015
| | |-> Birthday
| | |-> Wedding
You go to the next node on the vertical line (the next-oldest sibling) via pNext and you go one level (the eldest child) deeper via pInner. All younger siblings and all children of a node are reachable via the node pointers. You could also kee a pointer to the parant, so that you could walk up, not just down.
You can construct such a tree easily if you have the functions to create nodes and subnodes return the new node:
int main(int argc, char **argv)
{
NODE *list = NULL; // list head
NODE *p; // first-generation child
NODE *q; // second-generation child
p = add_node(&list, "MUSIC");
create_sub_node(p, "Punk");
create_sub_node(p, "Funk");
p = add_node(&list, "VIDEOS");
create_sub_node(p, "Cats");
create_sub_node(p, "Cars");
create_sub_node(p, "Parties");
p = add_node(&list, "PICTURES");
q = create_sub_node(p, "2014");
create_sub_node(q, "Skiing");
create_sub_node(q, "Trip");
create_sub_node(q, "Thksgvg");
q = create_sub_node(p, "2015");
create_sub_node(q, "Birthday");
create_sub_node(q, "Wedding");
print_nodes(list);
return (EXIT_SUCCESS);
}
When you construct the tree, you must change pNext for the youngest sibling to the new node, whose pNext is NULL. Make sure to alter the head of the list only if you append the first node. Likewise, change the pInner of a node only when you add the first child.
You usually have to distinguish two cases: first node and subsequent nodes. One technique to combine these cases is to iterate through the list with a pointer to node pointer. That pointer points to the list's or sublist's head first and to the nodes' pNext after that, f there are any nodes, that is.
Here are two functions that work with the above main:
NODE *add_node(NODE **head, const char *label)
{
NODE **p = head;
// walk to the end
while (*p) p = &(*p)->pNext;
// append new node
*p = malloc(sizeof(**p));
(*p)->pInner = NULL;
(*p)->pNext = NULL;
snprintf((*p)->pLabel, sizeof((*p)->pLabel), "%s", label);
return (*p);
}
NODE *create_sub_node(NODE *node, const char *label)
{
NODE **p = &node->pInner;
// walk to the end
while (*p) p = &(*p)->pNext;
// append new node
*p = malloc(sizeof(**p));
(*p)->pInner = NULL;
(*p)->pNext = NULL;
snprintf((*p)->pLabel, sizeof((*p)->pLabel), "%s", label);
return *p;
}

Remove nodes of a linked list on condition (C)

I am doing an exercise with a linked list, in which I need to remove some nodes according to a condition. The condition is ''remove the nodes that have a data stored that is less or equal to 'avg''.
I should consider three cases:
- removing the head node
- removing a node in the middle
- removing last node
I used three pointers, but this doesn't seem to work. What am I doing wrong? Am I accidentally missing some pointers? Thank you in advance!
void checkAvg(int avg, struct list* head_node){
struct list* prev;
struct list* curr;
struct list* next;
prev = head;
curr = prev->link;
next = curr->link;
while (curr!=NULL) {
if (prev->data <= avg) {
head = curr;
}
if (curr->data <= avg) {
prev->link = curr->link;
}
if (next->data <= avg) {
curr->link = next->link;
}
prev = prev->link;
curr = curr->link;
next = next->link;
}
}
EDIT:
I am sorry, as you told me, I wasn't specific. The program has to do this:
1) Read a linked list
2) Generate an output average of the values I read (sum of values / # of values)
3) remove from the list the nodes that have a data that is <= to the average
Free the memory of those nodes.
About the free() part, I have some difficulties with that, so I thought I first had to learn how to properly use pointers. As you may have noticed, I am not really good at that, I am starter.
Thank you for everyone who has replied, I am checking the replies right now
If your linked list does not have some sentinel head-node (and I strongly advise that it does not, as NULL is a damn fine value to indicate "I'm empty"), removal traversal is not overtly complicated. The places in your code where you seem to go astray are:
Passing the head pointer by-address and declaring the parameter as a pointer-to-pointer OR returning the new head pointer if the old one was disposed.
Maintaining consistency in your local pointer variables. You have to know for sure what everything points to at all times.
You can use pointer values, or you can use the actual pointers themselves (by address). I prefer the latter. In either case, the head node pointer must be passed by-address to allow potential modification of the caller's variable (like everything else in C) or the function can return the potentially new head node address. I prefer the former of those methods, as it leaves you the option of using the function return value for communicating error states to your caller. You're not doing that right now, but you should (hint).
void checkAvg(int avg, struct list** pp)
{
while (*pp)
{
if ((*pp)->data <= avg)
{
struct list *victim = *pp;
*pp = victim->link;
free(victim);
}
else
{ // advance to address of next "link" pointer
pp = &(*pp)->link;
}
}
}
It is worth noting this can be significantly simpler if the list is maintained as sorted in ascending order. If that is the case, the entire checkAvg function becomes substantially simpler. You can exit the loop as soon as you detect a value that no longer fits your condition:
void checkAvg(int avg, struct list** pp)
{
while (*pp && (*pp)->data <= avg)
{
struct list *victim = *pp;
*pp = victim->link;
free(victim)
}
}
In either case, the function is invoked by passing the head pointer on the caller-side by-address:
struct list *head = NULL;
//... populate list....
checkAvg(value, &head);
How it Works
A linked list is just something that looks like this:
-------- -------- --------
head ---> | link | ---> | link | ---> | link | ---> NULL
| val1 | | val2 | | val3 |
-------- -------- --------
Using the methods posted, traversing the list uses a pointer-to-pointer, which does something like this:
pp --:
: -------- -------- --------
head ---> | link | ---> | link | ---> | link | ---> NULL
| val1 | | val2 | | val3 |
-------- -------- --------
pp points to a pointer; not a node. Initially pp holds the address of the head pointer (was passed in by-address as a parameter).
So what happens if the first node matches your criteria? Ultimately, this is the result
pp --:
: -------- --------
head ---> | link | ---> | link | ---> NULL
| val2 | | val3 |
-------- --------
--------
victim ---> | link |
| val1 |
--------
and the victim node is summarily discarded (the link of victim actually still references the second node, but is meaningless in this context after the detachment happens.
So, what about if the second node was the one that needed removal (i.e. we skipped the first node). That gets a little more complicated:
pp -----:
:
---:---- --------
head ---> | link | ---> | link | ---> NULL
| val1 | | val3 |
-------- --------
--------
victim ---> | link |
| val2 |
--------
What this is trying to show (admittedly poorly) is that the pp pointer-to-pointer always holds the address of the pointer that we may be modifying. If we don't need to modify that pointer, we change the address held in pp to point to the next link pointer in the list (obtained through pp = &(*pp)->link
The latter case doesn't happen when the list is already sorted , thus the reason its iterative loop is simpler. We just enumerate the list, throwing out nodes until we find one that no longer meets our condition.
But no matter what, pp always holds the address of the pointer that points to the node we're working with.. Initially, that address is the address of the caller's head pointer.
Ok. I can only hope that makes it clearer. Some debugging with printf("pp=%p, *pp=%p\n", pp, *pp) in the loop makes what is actually happening most-educational. Walking through the algorithms by-hand in a debugger would be highly informative.
It's a lot easier than you think.
You're walking and modifying a linked list, so set up a current and previous.
void checkAvg(int avg, struct list** head_node){ //when calling, use checkAvg(avg, &head_node);
struct list* prev = NULL;
struct list* curr = *head_node;
Starting at the head...
while(curr != NULL){
if(curr->data <= avg){
if(prev == NULL){
*head_node = curr->next; //updates the head node
} else {
prev->next = curr->next; //removes the unwanted node
}
}
curr = curr->next;
}
You really don't need a special end case because the while loop terminates when curr is NULL; for the last item in the list, curr->next is NULL so when it get set it will end the loop. You also don't need to check if the list is empty, because the loop will end if it curr == NULL and you assign the head to curr at first.
I want some recursive magic tonight
Node* deleteBad(Node *head, int(*pred)(int)) {
if (head == NULL) {
return NULL;
}
if (pred(head->value)) {
head->next = deleteBad(head->next, pred);
return head;
}
else {
Node *next = head->next;
free(head);
return deleteBad(next, pred);
}
}
And accumulators
void deleteBad2(Node *head, int(*pred)(int), Node *out) {
if (head) {
if (pred(head->value)) {
out->next = head;
deleteBad2(head->next, pred, out->next);
} else {
out->next = head->next;
deleteBad2(head->next, pred, out);
}
}
}
And for those coxcombs who dislike recursion optimized version
void deleteBad3(Node *head, int(*pred)(int), Node *out) {
begin:
if (head) {
if (pred(head->value)) {
out->next = head;
out = out->next;
head = head->next;
goto begin;
}
else {
out->next = head->next;
head = head->next;
goto begin;
}
}
}
and if someone dislike gotos
void deleteBad3nogoto(Node *head, int(*pred)(int), Node *out) {
while (1) {
if (head) {
if (pred(head->value)) {
out->next = head;
out = out->next;
head = head->next;
}
else {
out->next = head->next;
head = head->next;
}
}
else {
break;
}
}
}
You're checking each node three times in each iteration, which leads to some weird behavior. Check the head before entering the loop, and only compare the current node each time:
void checkAvg(int avg, struct list* head_node){
struct list* prev;
struct list* curr;
while (head!=NULL) {
if (head->data <= avg) {
head = head->link;
} else {
break;
}
}
prev = head;
curr = prev->link;
while (curr!=NULL) {
if (curr->data <= avg) {
prev->link = curr->link;
}
prev = prev->link;
curr = prev->link;
}
}
Rather than checking the data of prev, curr and next, just check for one single data in the loop.
You also need to return the new head in case it changes.
I'd suggest something like that (tested):
#include <stdio.h>
#include <malloc.h>
typedef struct list_ {
struct list_ *link;
int data;
} list;
list* RemoveElementsBelow(int avg, list* head_node) {
while (head_node != NULL && head_node->data <= avg) {
// Remove the first.
list* new_head = head_node->link;
free(head_node);
head_node = new_head;
}
if (head_node == NULL) {
return NULL;
}
list* prev;
list* curr;
prev = head_node;
curr = prev->link;
while (curr != NULL) {
if (curr->data <= avg) {
prev->link = curr->link; // Will be NULL at the end of the list.
free(curr);
curr = prev->link;
} else {
prev = curr;
curr = curr->link;
}
}
return head_node;
}
list* AddToHead(int value, list* head_node) {
list* new_node = malloc(sizeof(list));
new_node->link = head_node;
new_node->data = value;
return new_node;
}
list* PrintAndDeleteList(list* head_node) {
while (head_node != NULL) {
list* new_head = head_node->link;
printf("%d ", head_node->data);
free(head_node);
head_node = new_head;
}
printf("\n");
}
int main(int argc, char **argv) {
list* my_list = NULL;
int i;
int sum = 0;
for (i = 1; i < argc; ++i) {
int value = atoi(argv[i]);
sum += value;
my_list = AddToHead(value, my_list);
}
if (argc == 1) {
return 1;
}
int avg = sum / (argc - 1);
printf("Average value: %d\n", avg);
my_list = RemoveElementsBelow(avg, my_list);
PrintAndDeleteList(my_list);
return 0;
}
Compiled:
gcc -o test test.c
Tested:
./test 10 20 30 40 50
Average value: 30
50 40
./test 50 40 30 20 10
Average value: 30
40 50

Resources