I have a linked list of particles. I would like to make these particles move one-by-one. So in order to do that I need to loop through every particle in my linked list, and when it reaches the last particle, I would like it to go back to the first particle. but my program is not doing that.
int particle_update(struct particle **head ){
struct particle *current = *head;
struct particle *next;
printf("particle_update\n");
while(current != NULL){
while(current != NULL && current->lifespan >=0){
current->lifespan --;
current->pos.y = current->pos.y + (current->spd.y * current->dir.y);
current->pos.x = current->pos.x + (current->spd.x * current->dir.x);
current->pos.z = current->pos.z + (current->spd.z * current->dir.z);
current = current->next;
if (current == NULL)
current = *head;
}
}
particle_destroy(head);
return 0;
}
I got a feeling there's a number of problems....
one.... this is strange...
while(current->lifespan >= 0 && current != NULL){
it should be while(current != NULL && current->lifespan >= 0){
this means it will check its not null first, and only if it is not null, it will try and see what current->lifespan is. The way you have it, it will likely crash
also, I'm not sure if you want to move to the next as the first thing? I think it might be the last thing you want to do inthe loop
also, the outer loop will loop forever once you get the inner loop doing what you want.
I suspect what is going on here is that to destroy the particle you need to modify the particle before it, and improper handling of this case is what is tripping you up.
First, as soon as you hit the last node in your linked list, you call current = current -> next at the beginning of your while loop whereas you should be calling it at the end.
As a result, current is now null so you are going to hit BAD_EXEC errors when you call current->position as you are de-referencing a null pointer. Instead, increment current at the end of the while loop so that you never de-reference a null pointer.
Next, pointing current to head means that you never get to exit your loop except via particles expiring, which I assume is not what you want (otherwise you would have a while(1)).
So here is a better alternative for handling the surgery:
int particle_update(struct particle **head ){
struct particle * current = *head;
struct particle * prev = NULL;
while (current != NULL) {
// lifespan check
current->lifespan = (current -> lifespan > 0) ? current->lifespan-1:particle_destroy(&prev, ¤t);
// update position of current
...
// increment counter at end of while loop
prev = current;
current = current -> next; //now current is always one node ahead of previous.
}
return 0;
}
Then, your particle destroy function would be:
void particle_destroy(struct particle ** prev, struct particle ** current) {
if (*current = NULL) return; //nothing to do
struct particle * tmp = *current;
if (*prev != NULL) { /* need to modify previous node */
(*prev) -> next = current -> next;
} else { /* head has expired, so change head ptr to next node */
(*current) = (*current) -> next;
}
/* free resources */
// do other clean-up, if necessary.
free(tmp);
return;
}
Related
I have a function here that will remove a node from a sorted list of any type.
I am having difficulties with one specific case: when there is 1 node in the list and you want to delete it.
In this case, I want to make the list empty, so when the list is printed out, no data is printed to the screen, but I can't seem to get that result. Just say, for example, the list is of type double, and the list consists of just one node 2.0. If this node is the target for deletion, the proceeding output should be an empty list. Instead my code prints out 0.0.
I am not sure how to handle this error. I have found the specific part of the function where this is to be taken care of, but its implementation escapes me. I first check if the previous node is null, and then check if the list length is equal to 1.
The function returns 1 if it was successful and 0 if it failed.
int SLRemove(SortedListPtr list, void *newObj) {
Node ptr, iterptr, prev = NULL;
if(list==NULL || newObj ==NULL) {
return 0;
}
int size= listlength(list);
for(ptr=list->start; ptr!=NULL; ptr=ptr->next) {
if(list->cf(newObj, ptr->info)==0){//found matching entry in list
//deleting first node;
if(prev==NULL) {
if(size == 1) {
printf("attempting to delete list with 1 node\n");
/*code to delete node where it's the only element in the ist, should make the list empty.*/
return 1;
}
list->start = ptr->next;
destroyNode(ptr);
return 1;
} else {
prev->next = ptr->next;
destroyNode(ptr);
return 1;
}
}
prev = ptr;
}
return 0;
}
Any help you can provide would be much appreciated. Thank you.
The first check should be:
if(list==NULL || list->start == NULL || newObj ==NULL) {
return 0;
}
Once past this check, there's at least one node in the list. If prev == NULL, then you need to set list->start = list->start->next to delete the first node. It doesn't matter if there is one node or more than one node.
The other functions you have need to check for list->start == NULL (or size == 0) to avoid printing garbage.
Using a double pointer can eliminate checking for prev == NULL, but I can't explain for your code since I don't know how node is defined, and it's not really needed, since checking for prev == NULL is just as good. As an example:
typedef struct Node_{
struct Node_ *next;
...
}Node;
/* in the delete function */
Node **ppNode = &list->start; /* ptr to list->start or ...->next */
/* to advance ppNode */
ppNode = &(*ppNode->next);
/* to remove a node from the list */
*ppNode = (*ppNode)->next;
I have created a linked list of 5 nodes of type:
typedef struct node
{
int i;
struct node* link;
}node;
node* head = NULL;
When printing out, this gives:
4 3 2 1 0
The head pointer is set to point at 4. I have then written a function to bubble sort the linked list as follows:
void sort(void)
{
node* cur = head;
node* next = cur->link;
node* prev = NULL;
while(cur->i > next->i)
{
printf("cur is greater than next\n");
while(prev != head)
{
cur->link = next->link;
next->link = cur;
head = next;
next = cur->link;
prev = head;
}
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
printf("second while loop exited\n");
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
printf("%d", ptr->i);
}
cur = head;
next = cur->link;
}
}
There are various printf statements to check that the program is working. What I find is that after the first run-through, 4 is successfully bubbled up as follows:
3 2 1 0 4
However, after re-setting the cur pointer to 3 and next to 2, the next run-through provides the following:
2 1 0 4 3
Ultimately, we finish with
0 4 3 2 1
So as can be seen "3", "2" and "1" are being bubbled up too far. I have tried various conditonals in place of the third while loop to correct this but in the majority of cases this leads to seg faults. Of course, the other thing here is that my logic could be completely wrong and there may be a better way to implement this. Could you get away with just swapping the contents of nodes and not pointers themselves? Any help would be much appreciated. Thanks in advance
Ordinary bubble-sort implementations for sorting arrays make use of the direct addressing and a known size of the array: they naturally use indices, that is ordinal numbers of items, so they can easily shrink the area sorted as the work progresses, because they know how many items are already on their final places.
A linked list is processed purely sequentially, so it doesn't allow such simple optimization without adding artificial 'index', incremented along the list iteration. That's why it's easiest to iterate always through the whole list and terminate when no more items were swapped, hence the list is sorted:
void sort(void)
{
int swapped = 1;
while(swapped)
{
node **prev = &head, *curr, *next;
swapped = 0;
for(curr = head; curr; prev = & curr->link, curr = curr->link)
{
next = curr->link;
if(next && curr->i > next->i)
{
curr->link = next->link;
next->link = curr;
*prev = next;
swapped = 1;
}
}
}
}
EDIT – some explanations in reply to questions in Matthew2015 comments.
Logical conditions in C expect a numeric or pointer expression which are considered 'true' if they are different from zero or different from NULL, respectively. That means while(swapped) is essentially equivalent to while(swapped != 0) and next && ... is equivalent to next != NULL && .... The condition in while(swapped != 0) means the loop will terminate when some execution of internal for does not set swapped to 1, which happens when no item in the list is greater than its successor – that is, when the list is sorted.
The for loop condition expression is curr alone, equivalent to curr != NULL. That makes the for loop iterate along the list until there is no 'current' node.
The node **prev variable points to a pointer, which points to the current node. When the 'current' and the 'next' node need to be swapped, then the 'previous' link should no longer point to the 'current' node but to the 'next' node instead. Of course one might keep the pointer to the 'previous node' and assign a new value to the (previous node)->link — but that would not work in case of the first node in a list, which has no 'previous node' but is pointed to by the head variable. One must use additional condition to verify if the current node is the first node to resolve this inconsistency. Having a pointer to pointer, which originally points to head and then to 'previous node'.link makes the whole code much simpler, shorter and also a bit faster.
I would look at the third while
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
Here you're always moving elements without testing whether they have to be moved - i.e. cur->i > next->i.
By the way, if it's guard is true, the second while gets executed only once and so it's the same as an if so I would use an if, at least for clarity reasons.
the following is a function that reverses elements of a link list k elements at a time,
My question is whether the function could crash if i were to pass null as head, because, next is never initialized to any value in this case and since it may be pointing to a garbage value, the if(next!= null) may be satisfied, so the statement head->next can be executed, when head is actually null, causing the program to crash?
struct node *reverse (struct node *head, int k)
{
struct node* current = head;
struct node* next;
struct node* prev = NULL;
int count = 0;
/*reverse first k nodes of the linked list */
while (current != NULL && count < k)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
count++;
}
/* next is now a pointer to (k+1)th node
Recursively call for the list starting from current.
And make rest of the list as next of first node */
if(next != NULL)
{ head->next = reverse(next, k); }
/* prev is new head of the input list */
return prev;
}
If you pass head as NULL, you skip the while loop, and the statement if(next != NULL)would compare an uninitialized pointer to NULL, which is undefined behavior.
So yes, your program could crash.
What an unitialized pointer contains is not specified, and is implementation dependent.
The strict answer to your quesion is: no, not likely.
Given head == 0 and k > 0, you'll end up at line 21 in your function with next != 0 (most likely) but with some garbage random value (as you pointed out) that will be used for your recursive call.
Your code may very well not crash the first time through, but it's very likely to crash at some point, or continue to recurse for some unknown time. In any event, you won't get the results you expect.
I have been trying hard to resolve this however yet not succeed I have data structs as follow (which actually is very complex I just simplifies for discussion) :
typedef struct node{
struct node* next;
void* arg;
}node_t;
typedef struct queue{
node_t* head;
node_t* tail;
}queue_t;
addQ(queue_t*ptr , int data)
{
queue_t* q = ptr;
node_t * n = malloc(sizeof(*n));
n->arg = data;
n->next = NULL;
if(NULL == q->head){
q->head = q->tail = n;
return ;
}
q->tail->next = n;
q->tail = q->tail->next;
}
Now I want to delete node of same value ( I have tried couple ways however yet not succeed ) , Just consider this sequence for reference:
addQ(q, 12);
addQ(q, 12);
addQ(q, 4);
addQ(q, 12);
addQ(q, 12);
addQ(q, 14);
addQ(q, 12);
addQ(q, 12);
I want to Delete all the nodes with value 12.
This solution got a bit hairy with the double pointers, but I still like it, as it doesn't have to special case what node (first vs the rest) is being checked. I tried to put enough comments in to describe what's going on, but it's still hard for even me to follow at first glance.
PSEUDOCODE..
Queue * q;
VALUE = 12;
// double pointer so we can treat the queue head and subsequent nodes the same.
// because they are both pointers to Node.
// Otherwise you'd have to have code that says if the one you're removing is the
// first element of the queue, adjust q->head, otherwise adjust node->next.
// This lets you not special case the deletion.
Node ** node_ptr = &(q->head)
while (*node_ptr != null) {
if ((**node_ptr).arg == VALUE) {
// store off the matching node to be freed because otherwise we'd orphan
// it when we move the thing pointing to it and we'd never be able to free it
Node * matched_node = *node_ptr;
// when we find a match, don't move where node_ptr points, just change the value it
// points to to skip the matched node and point to the one after it (or null)
*node_ptr = matched_node->next;
free(matched_node);
} else {
// otherwise, nothing was deleted, so skip over that node to the next one.
// remember, **node_ptr is a double dereference, so we're at the node
// now, so then we grab the address of the non-matching node's next value so it can be
// potentially changed in the next iteration
node_ptr = &((**node_ptr).next);
}
}
Assuming that you already have a function that obtains and removes the next item in the queue, let's call it getQ(q), then you could achieve your goal without even having to know the internals of the queue, by just using the operations you already have, e.g. something like (this won't work because arg is a void, but the logic should be clear):
node_t *n;
queue_t *q2 = initialiseQ();
while (n = getQ(q)) {
if (n->arg != 12) {
addQ(q2,n);
}
}
free(q);
q = q2;
Here's an inline solution that doesn't use double pointers. It has to treat the first element and subsequent elements differently since the pointer to adjust changes from the queue structure to the node structure.
Also, for subsequent nodes, you have to track the trailing node, since that's where you have to make the adjustment as you delete the matching node.
Queue * q;
VALUE = 12;
// handle the case where the first node matches.
// you have to adjust the q's head pointer
// delete from the head and set a new head node until a non-matching head is found
while (q->head != NULL && q->head->arg == VALUE) {
Node * matching_node = q->head;
q->head = q->head->next;
free(matching_node);
}
// if there is more than one node left, need to check the subsequent nodes
if (q->head != NULL && q->head->next != NULL) {
Node * node_ptr = q->head->next;
Node * prev_node_ptr = q->head;
while (node_ptr != NULL) {
if (node_ptr->arg == VALUE) {
Node * matched_node = node_ptr; // don't orphan it before it's freed
// You don't move the prev_node pointer since that doesn't change when a match
// is found. Only the node_ptr, which skips to the next one.
node_ptr = node_ptr->next;
free(matched_node);
} else {
prev_node_ptr = node_ptr;
node_ptr = node_ptr->next;
}
}
}
I have to write a program that implements a queue with all sorts of menu options (which are all done). I'm having trouble with my "pop" function.
My program is a restaurant waiting list for employees. Whenever a customer calls in or comes into the restaurant they are put onto the waiting list. The only way to pop (be seated) is if the customer's status is waiting-in-restaurant. I have correctly written the portion that changes a customer from call-in to waiting in restaurant.
Also, if the group size is bigger than the table size, I'm supposed to go to the next node and check if the next group fits the criteria to be seated.
enum status(WAIT,CALL);
typedef struct restaurant
{
//stuff
}list;
//I call pop in the main as follows:
pop(&head, &tail);
void pop(list** head, list** tail)
{
list* temp = *head;
int tableSize;
if(*head == *tail && *tail == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
if(temp->groupSize > tableSize || temp->waitStatus == CALL)
while(temp->groupSize > tableSize || temp->waitStatus == CALL)
temp = temp->nextNode;
else
*head = (*head)->nextNode;
if(*tail == temp)
*tail = (*tail)->nextNode;
free(temp);
}
When I display my output it doesn't delete the node in the instance if it has to skip the first person in the queue. However, it does work when the first person meets the criteria. Why is this?
First, your pop seems to allow items in the middle of the list to be removed. While this is doable, it requires you remember what was pointing to the node popped to ensure it is set to the node that is after the node being popped. There are a number of ways to do this.
Also, your empty() condition is off. head will always be NULL if the list is empty provided you're doing your job right on setting newly added node nextNode members to NULL. The comparison against tail or checking tail for NULL is not needed.
Finally, perhaps you may want to consider returning the data from the pop if there was any, and a boolean condition of true/false as the function return result to indicate whether something was taken off. Otherwise, how is your program to know data was retrieved successfully, and what that data was?
Regardless, just using your current mantra of deleting something that matches:
void pop(list** head, list** tail)
{
list *temp = NULL, *prior = NULL;
int tableSize = 0;
if(*head == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
temp = *head;
while (temp && (temp->groupSize > tableSize || temp->waitStatus == CALL))
{
prior = temp;
temp = temp->nextNode;
}
if (temp)
{
// only way prior is set is if temp is NOT
// pointing to the first node, therefore *head
// is not changed.
if (prior)
{
prior->nextNode = temp->nextNode;
// if we made it to the tail ptr, then it needs
// to be moved back to the prior node
if (*tail == temp)
*tail = prior;
}
else
{ // first node was removed. so move head to
// the next node (which may be NULL)
*head = temp->nextNode;
}
// release the node
free(temp);
}
}