I am working on a queue implementation and something weird is happening. The Enqueue seems to work but the changes are not being registered (the size stays the same at 0). From what I can tell, the code will enqueue an element but immediately forget about it. The output is:
Data passed: a34
Back befor:(null)
Back a:a34
Data passed: bg
Back befor:(null)
Back a:bg
Print (null)
Print 0
Based on this I'm guessing it's something to do with memory and scope, but I'm not sure how to resolve it.Below is the code.
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
typedef struct node_s{
void* data;
struct node_s* next;
} node;
// queue structure
typedef struct queue_s{
node* back;
node* front;
int size;
} queue_t;
//helpers
node *newNode(void *data)
{
//create a new node* with data->data. #return: a node*
node *temp = (node *)malloc(sizeof(node));
temp->data = data;
temp->next = NULL;
return temp;
}
//deep copy a n2
node* copy(node* n2){
node *temp = (node *)malloc(sizeof(node));
temp->data=n2->data;
temp->next=n2->next;
return temp;
}
queue_t que_create(void)
{
queue_t new;
new.size = 0;
node *front = (node *)malloc(sizeof(node));
node *back = (node *)malloc(sizeof(node));
new.front=front;
new.back=back;
return new;
}
void que_destroy(queue_t queue)
{
while (queue.size > 0)
{
que_dequeue(queue);
}
}
void que_clear(queue_t queue)
{
while (que_size(queue) != 0)
{
que_dequeue(queue);
}
}
void que_enqueue(queue_t queue, void *data)
{
// Create a new LL node
printf("Data passed: %s\n",data);
node *temp = newNode(data);
// If queue is empty, then new node is front and back
if (queue.size == 0){
printf("Back befor:%s\n",queue.back->data);
queue.front = copy(temp);
queue.back = copy(temp);
queue.size=queue.size+1;
free(temp);
printf("Back a:%s\n",queue.back->data);
return;
}
// Add the new node at the end of queue
queue.back->next = copy(temp);
queue.back = temp;
printf("Back2:%s\n",queue.back->data);
if (data != NULL){
queue.size=queue.size+1;
}
//free(temp);
}
void que_dequeue(queue_t queue)
{
if (queue.size == 0)
{
printf("Deq on an empty q");
return; //break here
}
else if (queue.size == 1)
{
//only 1 element
queue.front = NULL;
queue.back = NULL;
}
else
{
node* temp = newNode(NULL);
temp=queue.front->next;
queue.front = copy(temp);
free(temp);
}
queue.size=queue.size-1;
}
const void *que_front(const queue_t queue)
{
//return queue.front->data;
return queue.front;
}
size_t que_size(queue_t queue)
{
return (size_t)queue.size;
}
int main(void){
queue_t q=que_create();
que_enqueue(q,"a34");
que_enqueue(q,"bg");
node* f=(node *)que_front(q);
printf("Print %s\n",f->data);
printf("Print %d\n",q.size);
return 0;
}
The question was answered in the comments by #Paul Ogilvie. C is not "pass by value", so the code will edit a copy of the queue not the actual thing. This is fixed by passing a pointer that will change the value at the address
Related
I want to delete the front node in delete_first.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef int element;
typedef struct DListNode {
element data;
struct DListNode *llink;
struct DListNode *rlink;
} DlistNode;
void init(DListNode *phead) {
phead->llink = phead;
phead->rlink = phead;
}
An error occurs in the part below when I debug.
void print_dlist(DListNode *phead) {
DListNode *p;
for (p = phead->rlink; p != phead; p = p->rlink) {
printf("<-| |%d| |->", p->data);
}
printf("\n");
}
This is my insert code and I think it is not problem
void dinsert(DListNode *before, element data) {
DListNode *newnode = (DListNode *)malloc(sizeof(DListNode));
newnode->data = data;
newnode->llink = before;
newnode->rlink = before->rlink;
before->rlink->llink = newnode;
before->rlink = newnode;
}
I want to fix some error in that delete_first code but I don't know what is the problem and how to fix it.
void delete_first(DListNode *head) {
head = head->rlink;
if (head != NULL) {
head->llink = NULL;
}
free(head);
}
int main() {
DListNode *head = (DListNode *)malloc(sizeof(DListNode));
init(head);
printf("insert\n");
for (int i = 0; i < 5; i++) {
dinsert(head, i);
print_dlist(head);
}
printf("\n delete \n");
delete_first(head);
print_dlist(head);
free(head);
return 0;
}
How can I delete my front node using the head node?
To delete the first node of the doubly linked list, you must free the node pointed to by head->rlink unless head->rlink points to head itself, which is the case if the list is empty:
void delete_first(DListNode *head) {
DListNode *p = head->rlink;
if (p != head) {
p->llink->rlink = p->rlink;
p->rlink->llink = p->llink;
free(head);
}
}
Below is a Minimal Reproducible Example from my code. What I am doing is that I am inserting data in a list of structs and printing them on the console.
I want to print from each link only the first element that is inserted into each list of structs.
But how is that possible when instead of data in my struct I have:
typedef struct Node
{
int rollnumber, src, dst;
double gentime;
struct Node *next;
} Node;
(rollnumber, src, dst,gentime are the information I am reading from text files, but the reading code is not nessacary, so I wrote it with testdata.)
MINIMAL REPRODUCIBLE EXAMPLE
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef struct Node
{
int data;
struct Node* next;
} Node;
int push_front(Node** head, int data)
{
Node* new_node = malloc(sizeof(Node));
int success = new_node != NULL;
if (success)
{
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
return success;
}
void output(Node* head)
{
for (Node* current = head; current != NULL; current = current->next)
{
printf("%d ", current->data);
}
}
void display(Node** set, int i)
{
output(set[i]);
putchar('\n');
}
int main(void)
{
int testdata = 1;
Node* link[N] = { 0 };
struct Node* head = NULL;
for (int i = 0; i < N; i++) {
push_front(&link[i], testdata++);
push_front(&link[i], testdata++);
}
for (int i = 0; i < N; i++) {
printf("link[%d]:", i);
display(link, i);
}
}
If you only want to print the first element of each link list, just do not loop in output:
void output(Node* head)
{
printf("%d ", head->data);
}
If I am right you want the first element of the list right ??
If so than the way you are working you are pushing the new node in front of old node, so your first node is now the last in the line, so all you need to do is to iterate the list till Node* next == null, and that node will be your answer
Node *getLastInLine( Node *Head){
Node *ptr;
ptr = Head;
if( ptr == NULL) return NULL;
while(ptr-> next != NULL){
ptr = ptr->next;
}
return ptr;
}
I have looked at my code several times but couldn't find the problem. please tell me what I need to replace to get my code working.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int x)
{
struct node *temp=(struct node *)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
if (head == NULL)
{
temp->next = head;
head = temp;
return;
}
struct node *temp1 = head;
while(temp1 != NULL)
{
temp1 = temp1->next;
}
temp1->next = temp;
}
void display()
{
struct node *temp = head;
if (head == NULL)
{
printf("list is empty");
return;
}
else{
while(temp!=NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
}
int main()
{
head = NULL;
insert(3);
insert(5);
insert(6);
display();
}
The problem is in this code:
struct node *temp1=head;
while(temp1!=NULL)
{
temp1=temp1->next;
}
temp1->next=temp;
... the while loop won't end until temp1 is NULL, so after the loop ends, it is guaranteed that temp1 is a NULL pointer ... and then you dereference that NULL pointer (via temp1->next), which causes a crash. Probably what you want to do instead is while(temp1->next != NULL) {...}
while(temp1!=NULL)
{
temp1=temp1->next;
}
temp1->next=temp;
The only way out of this loop is for temp1 to be NULL. Then the next line attempts to used temp1 as a pointer. This is likely causing your issue. You need to instead check if the next is NULL and break leaving temp1 as the last in the list not it's next.
Pro tip for linked lists like this, they are a lot easier to modify with double pointers. Example code:
void append(struct node **list, int a) {
// skip to the end of the list:
while (*list != NULL) {
list = &(*list)->next;
}
*list = malloc(sizeof(struct node));
(*list)->data = a;
(*list)->next = NULL;
}
void display(struct node *list) {
while (list) {
printf("%d\n", list->data);
list = list->next;
}
}
void remove(struct node **list, int index) {
while (*list) {
if (--index == 0) {
struct node *temp = *list;
*list = temp->next;
free(temp);
break;
}
}
}
int main() {
struct list *mylist;
append(&mylist, 3);
append(&mylist, 4);
append(&mylist, 5);
display(mylist); // prints 3 4 5
remove(&mylist, 1);
display(mylist); // prints 3 5
remove(&mylist, 0);
remove(&mylist, 0);
// mylist is NULL again, all memory free'd
}
Note that this code needs no special cases for "is the list empty?", which makes it less complex than yours.
I have the following linked list implementation:
struct _node {
char *string;
struct _node *next;
}
struct _list {
struct _node *head;
struct _node *tail;
}
I want to make the following function:
void deleteList(struct _list *list, int from, int to) {
int i;
assert(list != NULL);
// I skipped error checking for out of range parameters for brevity of code
for (i = from; i <= to; i++) {
deleteNode(list->head, i);
}
}
// I ran this function with this linked list: [First]->[Second]->NULL
like this deleteNodes(list, 1, 1) to delete the second line and got
[First]->[Second]->NULL but when I run it like this deleteList(list, 0, 1) with this input [First]->[Second]->[Third]->NULL I get a seg fault.
Here is my deleteNode function
void deleteNode(struct _node *head, int index) {
if (head == NULL) {
return;
}
int i;
struct _node *temp = head;
if (index == 0) {
if (head->next == NULL) {
return;
}
else {
head = head->next;
free(head);
return;
}
}
for (i = 0; temp!=NULL && i<index-1; i++) {
temp = temp->next;
}
if (temp == NULL || temp->next == NULL) {
return;
}
Link next = temp->next->next;
free(temp->next);
temp->next = next;
}
I wrote a separate function to delete the head of the linked list if from or to = 0:
void pop(struct _node *head) {
if (head == NULL) {
return;
}
struct _node *temp = head;
head = head->next;
free(temp);
}
but it gives me seg fault or memory error Abort trapL 6.
It's all good to use just one struct, a node for your purpose.
struct node {
char *string;
struct node *next;
};
Then your loop for removing elements between two indices will not delete the right elements if you don't adjust the index according to the changing length of the list. And you must also return the new head of the list.
struct node *deleteList(struct node *head, unsigned from, unsigned to) {
unsigned i;
unsigned count = 0;
for (i = from; i <= to; i++) {
head = delete_at_index(head, i - count);
count++;
}
return head;
}
The help function delete_at_index looks as follows.
struct node *delete_at_index(struct node *head, unsigned i) {
struct node *next;
if (head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next) /* If i == 0, the first element needs to die. Do it. */
: (head->next = delete_at_index(next, i -
1), head); /* If it isn't the first element, we recursively check the rest. */
}
Complete program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *string;
struct node *next;
};
void freeList(struct node *head) {
struct node *tmp;
while (head != NULL) {
tmp = head;
head = head->next;
free(tmp->string);
free(tmp);
}
}
struct node *delete_at_index(struct node *head, unsigned i) {
struct node *next;
if (head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next) /* If i == 0, the first element needs to die. Do it. */
: (head->next = delete_at_index(next, i -
1), head); /* If it isn't the first element, we recursively check the rest. */
}
struct node *deleteList(struct node *head, unsigned from, unsigned to) {
unsigned i;
unsigned count = 0;
for (i = from; i <= to; i++) {
head = delete_at_index(head, i - count);
count++;
}
return head;
}
void pushvar1(struct node **head_ref, char *new_data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->string = strdup(new_data);
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void printListvar1(struct node *node) {
while (node != NULL) {
printf(" %s ", node->string);
node = node->next;
}
printf("\n");
}
int main(int argc, char **argv) {
struct node *head = NULL;
for (int i = 0; i < 5; i++) {
char str[2];
sprintf(str, "node%d", i);
pushvar1(&head, str);
}
puts("Created Linked List: ");
printListvar1(head);
head = deleteList(head, 0, 2);
puts("Linked list after deleted nodes from index 0 to index 2: ");
printListvar1(head);
freeList(head);
return 0;
}
Test
Created Linked List:
node4 node3 node2 node1 node0
Linked list after deleted nodes from index 0 to index 2:
node1 node0
every programming problem can be solved by adding an extra level of indirection: use a pointer to pointer ...
unsigned deletefromto(struct node **head, unsigned from, unsigned to)
{
unsigned pos,ret;
struct node *this;
for (pos=ret=0; this = *head;pos++) {
if (pos < from) { head = &(*head)->next; continue; }
if (pos > to) break;
*head = this->next;
free(this);
ret++;
}
return ret; /* nuber of deleted nodes */
}
So here's the code I have at the moment.
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
struct cake {
char name;
int waitTime;
int prepTime;
int bakeTime;
int turnTime;
};
struct cake redVelvet(){
struct cake c;
c.name = "R";
c.waitTime = 0;
c.prepTime = 60;
c.bakeTime = 30;
c.turnTime = 0;
return c;
};
struct Node {
struct cake cake;
struct Node* next;
};
// Two glboal variables to store address of front and rear nodes.
struct Node* front = NULL;
struct Node* rear = NULL;
// To Enqueue an integer
void Enqueue(struct cake x) {
struct Node* temp =
(struct Node*)malloc(sizeof(struct Node));
temp->cake = x;
temp->next = NULL;
if (front == NULL && rear == NULL){
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
// To Dequeue an integer.
void Dequeue() {
struct Node* temp = front;
if (front == NULL) {
printf("Queue is Empty\n");
return;
}
if (front == rear) {
front = rear = NULL;
}
else {
front = front->next;
}
free(temp);
}
struct cake Front() {
if (front == NULL) {
printf("Queue is empty\n");
return;
}
return front->cake;
}
void Print() {
struct Node* temp = front;
while (temp != NULL) {
printf("%d ", temp->cake.name);
temp = temp->next;
}
printf("\n");
}
int main(void){
Enqueue(redVelvet());
Enqueue(redVelvet());
Print();
getchar();
}
So In reality I'm going to have many different cakes, and if certain conditions are meant they are going to be inputted into the queue of LinkedList. However as a sample I created one type of cake (Red Velvet) And added it into the queue via my enqueue function and then tried to print it, However my out put is "88 88"
I want it to print the name of the Cake instead.
Following 2 line of code change needed
c.name = 'R';
Inside print function formatter type should match the type of variable
printf("%c ", temp->cake.name);