What am I doing wrong in my pop function (queue) C - c

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);
}
}

Related

Why is this function not deleting nodes?

I'm a beginner programmer just starting to get my hands dirty with linked lists.
I'm currently trying to figure out a function that deletes a song (node) from a "playlist" (linked list.) Each node has 3 data points, 2 strings (artist and title) and 1 integer (release year.) Can anybody help me figure out what I'm doing wrong and how I can fix it?
Function:
struct Node *borrow_song(struct Node *pointer) {
struct Node *temp = pointer;
char response[40];
struct Node *remove;
printf("Which song do you want to borrow? (title): ");
scanf(" %s", response);
while(temp != NULL) {
remove = temp;
if (strcmp(response, temp->title) == 0) {
printf("\nSuccess! %s is in the list. Borrowing..\n", response);
free(remove); // I have a feeling this isn't how you properly free a node.
remove = NULL;
return 0;
}
else
temp = temp->next;
}
printf("%s was not in the list... Try again.", response);
return 0;
}
Driver:
switch....
case 4:
borrow_song(head);
printf("\nNew list:\n\n");
print_list(head);
Node creation function from a generous person on here (creates node from .txt file)
struct Node *read_node(FILE *inputp) {
struct Node *temp = malloc(sizeof(*temp));
if (temp != NULL && fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
}
else {
free(temp);
return NULL;
}
}
And lastly, the driver for that:
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
}
else {
node->prev = tail;
tail = tail->next = node;
}
}
This is the input file:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
This is the console output:
Which song do you want to borrow? (title): Toccatas
Success! Toccatas is in the list. Borrowing..
New list:
Rachmaninov, Concerto_No_2, 1999
Mozart, Symphony_No_41, 2000
Vivaldi, The_Seasons, 2003
Beethoven, Symphony_No_5, 1994
`ĘŁt, Toccatas, 2005
Still working on pointers, I guess we all start somewhere :P
Thank you for any help!
You need to unlink the node by setting the previous node's next pointer to point to the node after the one being removed. If the node to remove is the first node in the list, there is no previous node, so you need to allow for the head of the list to change, probably by always returning the pointer to the head element (which appears to be what was intended if you look at the return type!).
The most uniform way to do this is to keep a Node **next_ptr initially set to &pointer. In the loop, set Node *temp = *next_ptr and see if you want to remove the temp node. If so, set *next_ptr = temp->next, free temp and return pointer. If not, set next_ptr = &temp->next and go around the loop again. If temp == NULL, then you didn't find the node, and should return pointer. In this way, if the node to remove is the first one, you will have updated pointer, otherwise you will have updated the previous node's next. Either way, you always return pointer, which will always be the head element.

Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)

I've tried to look up the solution to this problem through various other threads but my search was unsuccessful. I'm new to C and also new to this site so I apologize in advance if I'm incorrect in phrasing this question. I kinda have an idea of what's going on, but at the same time I might be entirely wrong. I have a linked list and I'm trying to insert at the end of the list. But when Xcode gets to the statement while(ptr->next!=NULL) it throws the error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
I read somewhere before that it was because I'm accessing something that doesn't exist or I'm failing to initialize node->next to NULL but I did in the previous "if statement". I'm pretty new at coding with pointers and linked lists and again I apologize for any weird stuff that might be in my code ):
////LIST AND NODE STRUCTURES
//data nodes
typedef struct node{
int data;
int ID;
struct node* prev;
struct node* next;
} node;
typedef struct ListInfo{
int count; //numnodes
struct node *list; //list of nodes
} ListInfo;
////INSERT FUNCITON
void insert(ListInfo *H, node *n){
if(n == NULL)
return;
node* ptr = H->list;
if(H==NULL){
ptr = n;
ptr->next = NULL;
}
else{
while(ptr->next!=NULL){ //Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
ptr = ptr->next;
}
ptr = n;
ptr->next = NULL;
}
// End of function
return;
}
////MAIN
int main(){ // No Edititng is needed for the main function.
ListInfo H;
H.count =0;
node *n;
int Data = 0,ID =0 ;
do{
printf("Enter an ID and a Value to add to the list, Enter -1 to stop: ");
//Get value from user to store in the new linked list node later.
scanf("%d %d",&ID,&Data);
// Check if the user entered "-1", if so exit the loop.
if(Data == -1||ID == -1)
return 0;
// Allocate memory for a new Node to be added to the Linked List.
n = malloc(sizeof(node));
// Put the Data from the user into the linked list node.
n->data = Data;
n->ID = ID;
//Increment the number of nodes in the list Header.
// If the current node count is zero, this means that this node is the first node
// in this list.
if(H.count++ == 0)
H.list = n;
// Otherwise, just use the insert function to add node to the list.
else insert(&H,n);
}while(Data != -1);
// Display all nodes in the list.
DisplayList(&H);
//Remove a node from the list, and display the list each time.
while(H.count != 0){
Delete(&H,H.list->data);
DisplayList(&H);
}
// Display the list, this should be empty if everything was correct.
DisplayList(&H);
}
When you allocate n you never set n->next. When you pass it to insert() you try to access the bad pointer and crash. When you set n->ID you should set n->next to NULL.

Deleting List With One Node In C

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;

Adding node in Linked List in a specific position in C

I'm trying to add a node to a linked list. The idea is to pass in the pointer, see where new node will go to through a ranked order, in this case G, then D, then M, then S.
Yet, when I compile and run, I'm not actually generating a linked list (this has already been done in the main). I'm more than certain that there's something wrong with my addp() function. Is it that I should pass in double pointers instead?
Sorry for being rather unprofessional and clueless. I'm not the strongest of coders.
Any help would be helpful.
I have attached my method which I have gone through so many times.
typedef struct node {
char fname[1024];
char lname[1024];
char pos;
int val;
int rank;
struct node * next;
} player;
struct node* addp (player* newnode, struct node* list){
player* templist = list;
player* templist1;
// if the list is non empty.
if (list!=NULL){
if(newnode->pos == GOALKEEPER){ //insert if G.
newnode->next = list;
}
if(newnode->pos == DEFENDER){// after G bef M.
// iterate through templist.
while (templist->next != NULL && (templist->next)->rank < 1) { // go to end of G.
// when the list isn't empty next node rank is less than one, keep going
templist = templist -> next;
}
// when finally rank == or > 1, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == MIDFIELDER){ //after G and M but before S
while (templist->next != NULL && (templist->next)->rank <2 && (templist->next)->rank> 2){
templist = templist -> next;
}
// when stopped, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == STRIKER){ // at the end.
while (templist->next != NULL && (templist->next)->rank <3){
templist = templist -> next;
}
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
return list;
printf("player added");
}
// if list is empty
else{
newnode->next = list;
return 0;
}
}
The following is the list function I've come up with. It keeps saying that my linked list is empty. Maybe it's something wrong with this function.
int print(struct player* list){
// create temp list so non modify origin.
struct player* temp = list;
if (list == NULL && temp == NULL)
printf("linked list is empty");
while (temp != NULL){
printf("%s \n", temp->lname);
printf("%s \n", temp->fname);
printf("%c \n", temp->pos);
printf("d \n", temp->val);
temp = temp->next;
}
return 0;
}
Without knowing the player typedef this is hard to analyze, but I think you can make it much easier on yourself by simplifying the signature of the function to only use player.
void addp(player* newnode, player* firstnode)
The return is unnecessary since you're just returning the 2nd argument, which the caller already has. The 2nd argument should be a pointer to a player node, which is the first element in your linked list. If you can call the function without the compiler complaining about implicitly casting pointers then I don't see anything wrong with your algorithm, although it could certainly be simplified.
Ok so what I understood is that your player structure contains a variable pos that will indicate in which place insert the player in the list. Am I right ?
In that case the best thing you can do is to sorted the list by the rank variable. Then modify your pos variable (in the player structure) to match with the rank variable of your list.
Then you will just have to add it with a classic "add in sorted list" function : C++ Add to linked list in sorted orderenter link description here

Linkedlist not looping properly

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, &current);
// 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;
}

Resources