Note: I already got the intended function to work with my own code, but I saw a tutorial on another website and am wondering why it doesn't work.
https://www.eskimo.com/~scs/cclass/int/sx8.html
The premise is as follows:
I'm playing around with a very basic linked list:
typedef struct node {
int val;
struct node * next;
} node_t;
I am trying to have a function remove an entry by value. It is as follows:
int remove_by_value(node_t ** head, int val) {
for(head = &node_t; *head != NULL; head = &(*head)->next){
if ((*head)->val == val) {
*head = (*head)->next;
break;
}
}
}
However, I'm getting an error when calling this function, namely:
"prog.c:35:17: error: expected expression before 'node_t'
for(head = &node_t; *head != NULL; head = &(*head)->next){
^"
Any ideas? Is this just a simple syntax error that I'm not seeing? Thanks!
the root of the problem is that node_t is a type, not a variable and cannot take the address of a type.
The following code cleanly compiles.
be sure to check the logic,
for first iteration of the loop when head = NULL or only one struct in linked list
check logic for when desired struct is either last or next to last in the linked list
here is the code:
typedef struct node
{
int val;
struct node * next;
} node_t;
int remove_by_value(node_t ** head, int val)
{
int retVal = -1; // initialize to failed
node_t *previousNode = *head;
node_t *currentNode = *head;
for(;
previousNode && currentNode; // assure something to test
previousNode = currentNode, // update the pointers
currentNode = currentNode->next )
{
if (currentNode->val == val)
{
previousNode->next = currentNode->next;
retVal = 0; // indicate success
break;
}
}
return retVal;
} // end function: remove_by_value
Since I cannot comment on the accepted answer written by #user3629249:
That code is even worse than the original (except that it would compile).
I'd suggest something like this:
node_t *remove_by_value(node_t **head, int val)
{
node_t *ret = NULL;
for (; *head; head = &((*head)->next))
{
if ((*head)->val == val)
{
ret = *head;
*head = (*head)->next;
break;
}
}
return ret;
}
This code correctly removes the element from the beginning, middle and end of the list. In addition it gives the caller the chance to free the unlinked node.
1) The error you are getting was pointed out by iharob already.
2) I can understand that out of this head =&t_node you want head to point at the head of your list. a static variable may be needed in your file to be able to use this then you can point head correctly
Related
Here is the function which getting me into troubles and I actually can't understand why.
This function supposes to removes all the odd elements from a given linked-list and also returns an address of a new linked list of the odd elements removed.
typedef struct node {
int data;
struct node* next;
} Node;
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *even;
Node *even_curr;
Node *odd;
Node *odd_curr;
Node *next;
even->next=NULL;
odd->next=NULL;
even_curr = even;
odd_curr = odd;
while(curr)
{
next = curr->next;
curr->next = NULL;
if(curr->data % 2!=0)// odd//
odd_curr = odd_curr->next = curr;//node add to last//
else //even//
even_curr = even_curr->next = curr;
curr = next;
}
*source= even->next;//update source//
return odd->next; //the new list of odd elements removed//
}
When I try to compile it, I get the following error:
warning C4700: uninitialized local variable 'even' used
warning C4700: uninitialized local variable 'odd' used
Two things:
First, you get warnings (and your program contains undefined behaviour and would probably crash) because you access/dereference uninitialised variables:
Node *even;
Node *odd;
even->next=NULL; // even has not been initialised
odd->next=NULL; // odd has not been initialised
Second, your code does not "remember" the roots of the new lists, i.e. you manage odd_curr and even_curr, each pointing to the last node of the respective list, but you do not have something like odd_root and even_root.
The following code shows how this could work. The logic for appending a node at the end while additionally considering a root node is the same for both lists, odd and even, and therefore factored out into a separate function:
void appendNode(Node **root, Node** lastNode, Node *curr) {
if (!*root) { // root not yet assigned?
*root = curr;
*lastNode = curr;
} else {
(*lastNode)->next = curr; // append curr after lastNode
*lastNode = curr; // let curr become the lastNode
}
(*lastNode)->next = NULL; // terminate the list at lastNode
}
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *evenRoot = NULL;
Node *oddRoot = NULL;
Node *evenLast = NULL;
Node *oddLast = NULL;
while(curr)
{
Node *next = curr->next;
if(curr->data % 2!=0) {
appendNode(&oddRoot, &oddLast, curr);
}
else {
appendNode(&evenRoot, &evenLast, curr);
}
curr = next;
}
*source= evenRoot;
return oddRoot;
}
curr = next;
Gives you the first warning, because next is not initialized.
odd_curr = odd;
Gives you the second warning, because odd is not initialized.
You should consider using malloc to allocate structures, because you are just allocating pointers, not the actual nodes. You can start learning more about linked lists from this interactive guide. Even if you somehow fix these two warnings, it still won't work.
The simplest case, using only two variables. The even nodes stay in the original list; the odd nodes are removed from the chain and returned as a linked list.
#include <stdio.h>
struct llist {
struct llist * next;
int data;
};
struct llist *chop_odds(struct llist **source)
{
struct llist *odd = NULL;
struct llist **target = &odd;
while ( *source) {
if((*source)->data %2) { /* odd */
*target = *source; // steal the pointer
*source = (*source)->next; // source skips this node
target = &(*target)->next; // advance target
}
else source = &(*source)->next; /* even */
}
*target = NULL;
return odd;
}
EDIT: I think my question is completely different from the proposed duplicate. It's asking about the general case whereas my question is asking for a very specific case where the reason for the weird behavior should be traceable given how specific it is.
I have some really weird behavior in my doubly LL implementation.
Basically, if I pop() (from the head) an element and then inject() (add at the tail) some other element, that last tail element now points to the head of the list for seemingly no reason (I guess instead of NULL by default or at least a random address).
I figured out how to fix the problem. When injecting, I wasn't pointing the new node's "next" to NULL.
However, I would still like to understand why the injected node would choose to point to the head without specific direction of where to point.
The effect is that if I travel the list starting from the head (but not starting from the tail), I keep looping forever as the last tail element points back to the head of the list.
EDIT: So I tried printing out the address that the pointer is pointing to just after the call to malloc in inject(), and for some crazy reason the pointer is created already pointing to the head's address; but this only happens if I call pop() before calling inject(). Incredibly weird...
int pop()
{
node* temp = head;
int value = temp->value;
head = temp->next;
free(temp);
head->previous = NULL;
size--;
return value;
}
void inject(int value)
{
if (tail == NULL)
{
tail = malloc(sizeof(node));
tail->value = value;
tail->next = NULL;
tail->previous = NULL;
head = tail;
size++;
}
else
{
node* new_node = malloc(sizeof(node));
printf("pointing to: %p\n", new_node->next);// points to head after pop() call
new_node->value = value;
tail->next = new_node;
new_node->previous = tail;
tail = new_node;
//new_node->next = NULL;
size++;
}
}
The commented out line in inject() solves the problem but still doesn't explain why the tail would point back to the head if I inject after a pop.
Below is the code before main() in case:
typedef struct node{
int value;
struct node* next;
struct node* previous;
}node;
node* head = NULL;
node* tail = NULL;
int head_value();
int tail_value();
void push(int);
int pop();
void inject(int);
int eject();
int size = 0;
node* new_node = malloc(sizeof(node));
printf("pointing to: %p\n", new_node->next);// points to head after pop() call
new_node->next will contain whatever garbage malloc wants to put in there. It might happen to point to head, but you never initialized it, so that printf is trying to find meaning in garbage.
Your code scatters memory management all over the place. Rather than try to fix it, let's rewrite it using my stock advice about structs: always write functions to initialize and destroy them. Always, even if it seems silly and trivial. It avoids scattering that code all over the place, doing it slightly differently every time. It allows you to unit test the basic functions of the struct before trying to use it.It lets you focus on the algorithm, not the memory management.
First, let's make a tweak to your struct. node is a very bad name for a type. It's likely you (or somebody else) is going to want to call a variable node and cause a conflict. I've called it Node, capitalized to avoid confusion with variables and builtins.
typedef struct Node {
int value;
struct Node* next;
struct Node* previous;
} Node;
Now we can write Node_new and Node_destroy.
Node *Node_new() {
Node *node = malloc(sizeof(Node));
node->value = 0;
node->next = NULL;
node->previous = NULL;
return node;
}
void Node_destroy( Node *node ) {
free(node);
}
Node_destroy might seem silly, but it frees you (or anyone else) from having to remember how to destroy a Node. And it lets you change the internal structure of Node without changing the rest of the code (which happened while writing this).
You're using globals. Globals make everything more complicated and restrict what you can do with the code. Instead, wrap things like head, tail, and size into its own structure and pass that around.
typedef struct {
Node *head;
Node *tail;
size_t size;
} LinkedList;
And it needs its own create and destroy functions.
LinkedList *LinkedList_new() {
LinkedList *list = malloc(sizeof(LinkedList));
list->head = NULL;
list->tail = NULL;
list->size = 0;
return list;
}
void LinkedList_destroy( LinkedList *list ) {
for( Node *node = list->head; node != NULL; node = node->next ) {
Node_destroy(list->head);
}
free(list);
}
Note that LinkedList_destroy takes responsibility for cleaning up all its nodes, its one less thing for the user of LinkedList to worry about and potentially screw up.
LinkedList_destroy can call Node_destroy without knowing anything about how Node works. This is how we immediately benefit from the encapsulation and abstraction of Node. But don't use recursion, the list can be arbitrarily long and recursion risks a stack overflow.
Now we can write push and pop assured that things are properly created and destroyed. Note that they take a LinkedList rather than using globals.
void LinkedList_push(LinkedList *list, int value)
{
Node *node = Node_new();
node->value = value;
switch( list->size ) {
/* The list is empty, this is the first node */
case 0:
list->head = list->tail = node;
break;
default:
list->tail->next = node;
node->previous = list->tail;
list->tail = node;
break;
}
list->size++;
}
int LinkedList_pop( LinkedList *list ) {
Node *popped = list->tail;
switch( list->size ) {
/* The list is empty, nothing to pop */
case 0:
fprintf(stderr, "LinkedList was empty when popped.\n");
exit(1);
break;
/* Popped the last node */
case 1:
list->head = list->tail = NULL;
break;
/* Only one node left, it's both the head and tail */
case 2:
list->tail = list->head;
list->tail->previous = list->tail->next = NULL;
break;
default:
list->tail = popped->previous;
list->tail->next = NULL;
break;
}
/* Have to do this at the end because size_t is unsigned
it can't go negative */
list->size--;
int value = popped->value;
Node_destroy(popped);
return value;
}
I've used a switch so I can clearly demarcate all the special cases.
I'm not saying this is the best implementation of push and pop, or that it's even bug free, but they can be written without worrying about whether the structs have been properly initialized or freed. You can focus on the logic, not the memory management.
And then to demonstrate it all works...
void LinkedList_print( LinkedList *list ) {
for( Node *node = list->head; node != NULL; node = node->next) {
printf("%d\n", node->value);
}
}
int main() {
LinkedList *list = LinkedList_new();
for( int i = 0; i < 3; i++ ) {
LinkedList_push(list, i);
}
while( list->size != 0 ) {
printf("list->size: %zu\n", list->size);
LinkedList_print(list);
LinkedList_pop(list);
}
LinkedList_destroy(list);
}
$ ./test
list->size: 3
0
1
2
list->size: 2
0
1
list->size: 1
0
I'm very new to coding in C (and therefore the silly exercise I am working on). I tried looking at this other solution to a similar question, but it seems like my coding strategy is different, and ultimately I would like to understand what is the problem with my code. I would greatly appreciate your input.
I have a linked list, a function that inserts a new node at the beginning of my list, a function that prints my linked list, and main function.
Unfortunately my knowledge of C is not good enough to understand why my function is not inserting at the beginning of the list. What is even more unfortunate is that this code does not crash.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} *Node_t;
void print_list(Node_t root) {
while (root) {
printf("%d ", root->data);
root = root->next;
}
printf("\n");
}
void add_to_list(Node_t *list, Node_t temp){
// check if list is empty
if ((*list)->next == NULL) {
// insert first element
(*list) = temp;
}
else {
temp->next = (*list);
(*list) = temp;
}
}
int main () {
int val1 = 4;
int val2 = 8;
int val3 = 15;
Node_t list = malloc(sizeof(struct Node));
Node_t temp1 = malloc(sizeof(struct Node));
Node_t temp2 = malloc(sizeof(struct Node));
Node_t temp3 = malloc(sizeof(struct Node));
temp1->data = val1;
temp1->next = NULL;
temp2->data = val2;
temp2->next = NULL;
temp3->data = val3;
temp3->next = NULL;
//Initialize list with some values
list->data = 0;
list->next = NULL;
/* add values to list */
add_to_list(&list,temp1);
add_to_list(&list,temp2);
add_to_list(&list,temp3);
print_list(list);
}
This code will only ever print the last node I have attempted to add to the list, therefore overwriting the previous nodes.
For example:
Running…
15
Debugger stopped.
Program exited with status value:0.
A single mistake in add_to_list() function:
if ((*list)->next == NULL) { // checks next of first is NULL not list is NULL
// to insert at first
should be just:
if ((*list) == NULL){ // You need to check list is NULL
Check working code
Why you were getting only 15 the last node (temp3) value?
Because in main you creates three temp nodes and initialized next of every node to NULL, including list node so in add_to_list() function if condition ((*list)->next == NULL) always evaluates true and list always initialized with temp node.
I have, for a large portion of the day, been trying to write a simple program with linked lists. My main issue seems to be not understanding why the memory I am accessing is not what I think it is. I am printf crazy and outputting every possible form of data I can and still am having trouble understanding why it will not work.
For example when I pass the &head to a function which takes node **location and I want to check whether the value inside location (and therefore head) is NULL or not, should I use if(!*location) return; or should I use if(!location) return;, It seems the later is correct, but why?
And when I want to create a node *current inside a function to keep track of things, should I start with node* current = *head or node* current = head, and most importantly, why? I have noticed that the later is better, but I cannot make sense of it still. Warnings go away when I typecast the statements, but it seems to fix nothing.
Here is some functions I have been writing, can you please give me hints on where I am not making sense in the code. Preferably, I hope to understand why the output seems to be a memory location and then accessing bad memory.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_struct
{
int val;
struct node *next;
} node;
node* return_create_neck(node **head, int value)
{
node* ptr;
*head = ptr = (node *)malloc(sizeof(node));
(*head)->val = value;
(*head)->next = NULL;
return ptr;
}
node* return_append_tail(node **location, int value)
{
node* ptr;
*location = ptr = (node *)malloc(sizeof(node));
(*location)->val = value;
(*location)->next = NULL;
return ptr;
}
void print_linked_list(node **head)
{
if(!head)
return;
node *current = head;
while(current)
{
printf("%d ", current->val);
current = current->next;
}
printf("\n");
return;
}
int main(void)
{
node *head=NULL, *current=NULL;
int i=0;
for( current = return_create_neck(&head, 1);
i < 4;
current = return_append_tail(¤t, i+1))
{ ++i; }
printf("Pritning...\n");
print_linked_list(&head);
return 0;
}
Your return_append_tail function doesn't actually append anything, unless called with the correct location, which you do not.
You should call it with ¤t->next from the main function.
I need to remove a node from a singly linked list. I know this is a simple thing to do, but my mind is blank and I've searched both Google and Stackoverflow, but I seriously haven't found anything that will help me.
basically the list of nodes is contained in a bucket; like this:
struct node{
unsigned char id[20];
struct node *next;
};
struct bucket{
unsigned char id;
struct node *nodes;
};
and I have a function
struct bucket *dht_bucketfind(unsigned char *id); // return bucket with id[20]
to find the correct bucket. So I know how to find the correct bucket, but I don't know how to remove a given node. I would like to remove the node by nodeid (I think, I haven't really written the code that will call the remove function yet ;) but I think I'll be able to modify the code if necessary). I think that's all that's needed to solve this. Thanks in advance.
If you know the item you want to remove, you must do two things:
Change all pointers that point to the target item to point to the target item's next member. This will be the preceding item's next pointer, or the head of the list bucket.nodes.
Free the node you just made unreachable.
The code for manipulating a linked list is really not that tricky, once you understand what you are doing.
Your nodes don't have any payload other than an id, so, depending on the data payload of a node, you might not actually need to iterate the list in the standard way. This is useful if deleters are going to know the address of only the node they want to delete.
If your payload is a pointer to other data:
struct _node {
void *data;
unsigned char id[20];
struct _node *next
}
Then you could "delete" a node by stealing the payload of the next node, and then delinking the next node:
int delete (struct _node *node)
{
struct _node *temp;
memcpy(node->id, node->next->id, 20);
free_function(node->data);
node->data = node->next->data;
temp = node->next;
node->next = node->next->next);
free(temp);
return 0;
}
/* define your two pointers, prev and cur */
prev=NULL;
cur=head;
/* traverse the list until you find your target */
while (cur != NULL && cur->id != search_id) {
prev=cur;
cur=cur->next;
}
/* if a result is found */
if (cur != NULL) {
/* check for the head of the list */
if (prev == NULL)
head=cur->next;
else
prev->next=cur->next;
/* release the old memory structure */
free(cur);
}
public void Remove(T data)
{
if (this.Head.Data.Equals(data))
{
this.Head = this.Head.Next;
this.Count = this.Count - 1;
}
else
{
LinkedListNode<T> node = this.Head;
bool found = false;
while (node.Next != null && !found)
{
if (node.Next.Data.Equals(data))
{
found = true;
node.Next = node.Next.Next;
this.Count = Count - 1;
}
else
{
node = node.Next;
}
}
}
}
Its been a long time ago since I worked with C, but this should be compile clean.
Basically, you need to keep track of the previous pointer while you iterate through the linked list. When you find the node to delete, just change the previous pointer to skip the delete node.
This function deletes all nodes with id (find). If you want to delete only the first occurrence, then put a return after the free statement.
void delete(struct bucket *thisBucket, unsigned char find[20]) {
struct node *prev = null;
struct node *curr = thisBucket->nodes;
while (curr != null) {
if (!strcmp(curr->id, find)) { // found the node?
if (prev == null) { // going to delete the first node (header)?
thisBucket->nodes = curr->next; // set the new header to the second node
} else {
prev->next = curr->next;
}
free(curr);
// if deleted the first node, then current is now the new header,
// else jump to the next
curr = prev == null? thisBucket->nodes : prev->next;
} else { // not found, keep going
prev = curr;
curr = curr->next;
}
}
}
The following does not contain any error checking and only removes the current node from the list ...
pPrev->next = pCurrent->next;
Your preferences may vary, but I tend to put my linked list node at the start of the structure (whenever practical).
struct node{
struct node *next;
unsigned char id[20];
};
struct bucket{
struct node *nodes;
unsigned char id;
};
I find this generally helps to simplify pointer arithmetic and allows simple typecasting when needed.
This removes a node given its address; you can modify it to remove a node given its id, but you haven't specified the form of an id -- is it a NUL-terminated string, or is it 20 bytes?
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
for( ;; ){
struct node* pnode = *ppnode;
if( pnode == NULL ) return 0;
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
ppnode = &pnode->next;
}
}
Or, more compactly,
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
struct node* pnode;
for( ; (pnode = *ppnode); ppnode = &pnode->next )
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
return 0;
}
typedef struct node
{
int id;
struct node* next;
}Node;
void delete_element(void)
{
int i;
Node* current=head;
Node* brev=NULL;
if(i==head->id){
head=current->next;
free(current);}
else{
while(NULL!=current->next)
{
if(i==current->next->id){
brev=current;
current=current->next;
break;}
else
current=current->next;
}
if(i==current->id)
{
if(NULL==head->next){
head=NULL;
free(current);}
else
brev->next=current->next;
free(current);
}
else
printf("this id does not exist\n");
}
}