We are trying to add nodes to a linked list in one thread, and delete nodes from the linked list in the other thread.
We believe the following line is our problem: if(time(NULL) == llnode->time)
.We are trying to access the time in the head node of the list. I'm not sure if we are passing the correct arguments to the functions. The thread to create nodes is working correctly, but the thread to delete nodes isn't. It's resulting in a segmentation fault. It'd be greatly appreciated if anyone could point me in the right direction, as I've been stuck on this for a while.
/* Link list node */
struct node
{
int roomNo;
time_t time;
struct node* next;
};
void * addThread(void *n)
{
struct node *llnode = n;
time_t date;
int room;
struct tm * timeptr;
pthread_mutex_lock(&lock);
while (pending < 5)
{
printf("Adding node.\n");
insert(&llnode, getRandRoom(), getRandTime());
date = getRandTime();
room = getRandRoom();
timeptr = localtime(&date);
printf("Registered: %d %s", room, asctime(timeptr));
sleep(1);
pending++;
}
pthread_mutex_unlock(&lock);
}
void * wakeThread(void *n)
{
struct node *llnode = n;
while(1)
{
if(time(NULL) == llnode->time)
{
printf("Deleting head node.\n");
pthread_mutex_lock(&lock);
deleteNode(&llnode);
pending--;
expired++;
pthread_mutex_unlock(&lock);
}
}
}
int main()
{
struct node* head;
head = NULL;
signal(SIGINT, ctrlc_catch);
pthread_t addWakeup, makeWakeup;
pthread_create(&addWakeup, NULL, addThread, (void*)head);
sleep(6);
pthread_create(&makeWakeup, NULL, wakeThread, (void*)head);
pthread_join(addWakeup, NULL);
pthread_join(makeWakeup, NULL);
return 0;
}
Here are the prototypes for our functions that aren't shown in the code(functions have been tested outside the threads and are fully functional):
void insert(struct node** head_ref, int new_room, time_t new_time);
void deleteNode(struct node** head_ref);
Essentially, head starts off as NULL and remains NULL for the lifetime of your program. The NULL pointer gets passed to wakeThread, which proceeds to dereference it (llnode->time). This is what triggers the segfault.
To fix, you need to make sure that any changes that the addThread makes to head are visible to the wakeThread. One way to do it is by passing a pointer to head to both threads. If you do this, make sure you get the locking right!
head in main() is a pointer to struct node. It's initialized to NULL and passed to the thread functions. They both receive a NULL pointer. Then addThread() might be able to grow its own node list with insert(), but wakeThread() is definitely not going to delete any of it with deleteNode(), because it just doesn't have the right pointer, all it has is a NULL pointer, which it tries to dereference and crashes.
Related
I am given these structure declarations in order to implement a queue collection that uses a circular linked list.
typedef struct intnode {
int value;
struct intnode *next;
} intnode_t;
typedef struct {
intnode_t *rear; // Points to the node at the tail of the
// queue's linked list
int size; // The # of nodes in the queue's linked list
} intqueue_t;
intnode_t *intnode_construct(int value, intnode_t *next)
{
intnode_t *p = malloc(sizeof(intnode_t));
assert (p != NULL);
p->value = value;
p->next = next;
return p;
}
/* Return a pointer to a new, empty queue.
* Terminate (via assert) if memory for the queue cannot be allocated.
*/
intqueue_t *intqueue_construct(void)
{
intqueue_t *queue = malloc(sizeof(intqueue_t));
assert(queue != NULL);
queue->rear = NULL;
queue->size = 0;
return queue;
}
I'm trying to create a function that will enqueue at a specified value (append it to the rear of the queue), and I need to consider the two cases in which the queue is empty and when the queue has one or more elements. This is the code I have so far:
void intqueue_enqueue(intqueue_t *queue, int value)
{
intnode_t *p = intnode_construct(value, NULL);
if(queue->rear->next == NULL) {
//the queue is empty
queue->rear->next =p;
} else {
//the queue is not empty
queue->rear=p;
}
queue->rear=p;
queue->size++;
}
This code gives me a runtime error so I'm not sure whats wrong. In the code, I'm assuming queue->rear->next is the front, however I think this is where the problem might be. All help is greatly appreciated. Thanks!
Your problem occurs on this line:
if(queue->rear->next == NULL) {
The first time you call the function, queue->rear is NULL. Thus when you try to dereference it to get queue->rear->next you get the runtime error.
To fix this code, update intqueue_enqueue to just check if queue->size==0, and if so then you need to initialize it by setting queue->rear=p and p->next=p. Then update the else clause so that it inserts the element between the two existing elements. Hint: you'll need to store queue->rear->next in p.
Edit
To address your comment, here's how to graphically think about a list with three elements:
<element1: next==element2> <element2: next==element3> <element3: next==element1>
And queue->rear points to element3. So, to insert a fourth element, you need to make it so that queue->rear points to element4 and element4->rear needs to point to element1. Remember that the location of element is stored in rear->next.
#include<stdio.h>
#include<malloc.h>
typedef struct nde{
int data;
struct nde *next;
}node,*pnode;
void inst_beg(node *,int);
void inst_end(node *,int);
void inst_any(node *,int,int);
int del_begin(node *);
int del_end(node *);
int del_any(node*,int);
void display(node *);
main()
{
pnode head= (node *)malloc(1*sizeof(node));
head->data=0;
head->next=NULL;
inst_any(head,1,1);
inst_any(head,2,2);
// inst_any(head,3,3);
display(head);
}
void inst_any(node *head,int pos, int data){
pnode nd=(node *)malloc(1*sizeof(node));
nd->data=data;
//pnode count=(node *)malloc(1*sizeof(node));
pnode count;
count=head;
printf("head: %p",head);
printf("count: %p",count);
int i=0;
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
nd->next=count->next;
count->next=nd;
//printf("done");
}
void display(node * head){
pnode count=head;
while(count->next!=NULL){
printf("%d",count->data);
count=count->next;
}
}
Value of count is becoming null inside loop so we are not able to deference it when it is coming second time when inst_any(head,2,2) is being called. Checked with gdb that first time count is successfully being pointed to head. And same is happening for second time also. After count=head it is giving correct value for second time. Dont know what is happening after that. Why when its coming inside the loop count's value is becoming zero.
Look at this code:
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
That's the whole loop. So either your condition i<pos-1 is false right away .... or it is true and stays true, as you never modify i nor pos in your loop.
In the latter case, you walk a linked list. Eventually, you'll find the end (count->next is NULL) and still assign this NULL to count. In the next iteration, you try to dereference NULL to access ->next. Trying to dereference NULL is undefined behavior, a segmentation fault is a typical consequence.
Go and rethink your program (e.g., check whether count->next is still not NULL in your loop condition).
I have corrected your code with comments below. Please read my comments in the codes else you can not realize your mistakes. Hope this will help you.
typedef struct nde{
int data;
struct nde *next;
}node,*pnode;
void inst_beg(node *,int);
void inst_end(node *,int);
void inst_any(node *,int,int);
int del_begin(node *);
int del_end(node *);
int del_any(node*,int);
void display(node *);
void main()
{
pnode head= (node *)malloc(sizeof(node)); //No need to multiply by one
head->data=0;
head->next=NULL;
inst_any(head,1,1);
inst_any(head,2,2);
inst_any(head,3,3);
display(head);
inst_any(head,4,4); //I am adding this statement so that you can better understand where it going to be inserted
display(head);
inst_any(head,7,7);
}
void inst_any(node *head,int pos, int data){
pnode nd=(node *)malloc(sizeof(node));
nd->data=data;
//pnode count=(node *)malloc(1*sizeof(node));
pnode count;
count=head;
printf("head: %p\n",head);
printf("count: %p\n",count);
int i=0;
while(i < (pos-1)){
if(count == NULL){
printf("No position available for request pos =%d\n", pos);
return;//This condition is important. If your position is not exist in the list and count reached the end of the list just return with a error message
}
count=count->next; //Problem is here for inst_any(phead,2,2)
i++;//you must increment i
}
nd->next=count->next;
count->next=nd;//Here count must not be null, else it will create Segmentation fault. Therefore inside from while loop above we have checked whether it is null or not. If null return from this method.
//printf("done\n");
}
void display(node * head){
pnode count=head;
while(count!=NULL){//You have to correct it to print last node of the list
printf("%d\n",count->data);
count=count->next;
}
}
the posted code for the function: inst_any() initializes the data field, but fails to initialize the next field.
Suggest:
nd->data=data;
nd->next = NULL;
Then this loop:
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
fails to update the counter i so the loop never exits. Also, when the linked list does not contain enough entries this loop will run right off the end of the list. So the loop also needs to be checking that the count->next is not NULL.
I was trying to implement circular queue functionality. I am a C++ coder and I found it surprising that in C, struct cannot have member functions. Anyway this is my implementation:-
#include <stdio.h>
#include <stdlib.h>
struct node
{
int nvalue;
struct node *next;
};
struct CLlist
{
struct node* head;
struct node* tail;
int size;
};
void insert(struct CLlist *l,int num)
{
struct node *n=malloc(sizeof(struct node));
n->nvalue=num;
n->next=NULL;
if((l->head==l->tail)==NULL)
{
l->head=l->tail=n;
}
else if(l->head==l->tail && l->head!=NULL)
{
l->head->next=n;
l->tail=n;
l->tail->next=l->head;
}
else
{
l->tail->next=n;
l->tail=n;
l->tail->next=l->head;
}
l->size++;
}
void print(struct CLlist *l)
{
int idno=1;
printf("printing the linked list with size as %d\n",l->size);
struct node *cptr;
for(cptr=(l->head);cptr!=(l->tail);cptr=cptr->next)
{
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
idno++;
}
//this is to print the last node in circular list : the tail node
idno++;
cptr=cptr->next;
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
}
int main()
{
struct CLlist a;
struct CLlist *l;
l=&a;
insert(l,2);
insert(l,5);
insert(l,7);
insert(l,10);
insert(l,12);
print(l);
return 0;
}
I get segmentation fault in the line
printf("The idno is %d and the number is %d\n",idno,cptr->nvalue);
why does the error occur? I guess I am not passing l by pointer by value (passing pointers as by value) properly. could somebody help me in pointing out where I am going wrong?
Thanks
You never initialize the variable a in the main function, so its contents is indeterminate and using the members of that structure will lead to undefined behavior.
Your code has two issues, the first one more serious.
Your first issue is that the head and tail members of your CLlist structure are not being initialized to NULL, which can (non-deterministically) keep any real data from being stored in your structure. This can be fixed by adding the following 2 lines in main just before the first insert call:
l->head = NULL;
l->tail = NULL;
Your second problem is in this line:
if((l->head==l->tail)==NULL)
While it looks like this is comparing both l->head and l->tail to NULL, it's actually comparing l->head to l->tail, and then comparing that boolean result to NULL, which is effectively 0. The line should be changed to:
if((l->head == NULL) && (l->tail == NULL))
This will individually test both the head and tail pointers, and will only take that branch if they are both NULL.
You have a pointer
struct node *cptr;
// You're probably trying to access an unassigned pointer head in the next step
for(cptr=(l->head);cptr!=(l->tail);cptr=cptr->next)
As per the standards, there is no requirement that
a->head & a->tail are initialized to NULL
when you did
struct CLlist a;
Standard ISO/IEC 9899:201x clause 6.7.9->10 states
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
In fact you're:
struct CLlist a;
// missing something here.
struct CLlist *l;
l=&a;
This question already has answers here:
Explanation of code (linked list C)
(7 answers)
Closed 6 years ago.
Been given some functions, but cant seem to get main method working (the master list). What i thought would happen is you 1 master list and insert_at_front would add to it, but it only prints out the first list (10). Anyone know how i can get a linked list going? Thanks in advance :)
#include <stdlib.h>
#include "week1.h"
void insert_at_front(List *self, int data)
{
List newNode = (List)malloc(sizeof(struct node));
newNode->data = data;
newNode->next = *self;
*self = newNode;
}
void print_list(List *self)
{
List current = *self;
while (current != NULL)
{
printf("%d\n", current->data);
current = current->next;
}
printf("\n");
}
int main(void)
{
List *master;
insert_at_front(&master, 10);
insert_at_front(&master, 20);
print_list(&master);
return 0;
}
header:
typedef struct node
{
int data;
struct node *next;
} *List;
void print_list(List *self);
void insert_at_front(List *self, int data);
You typedefed List as a pointer to your struct node so the declaration of List *master is actually a pointer to a ponter to a node. When getting the address of master (&master) your getting a pointer to a pointer to a pointer to a node. Not quite what you want :)
You need to change the declaration of master to a pointer to a node and then getting the address of it
List master; // before: List* master
insert_at_front(&master, 10);
insert_at_front(&master, 20);
print_list(&master);
Edit:
Also include <stdio.h> for using printf.
At the moment you're also creating a memory leak since you're allocating memory by calling malloc but never calling free.
Usually the best thing you can do is to write a cleanup function for freeing memory right after you wrote something which allocated memory in the first place. A cleanup could look like this:
void delete_list(List* self)
{
while ((*self)->next)
{
List tmp = *self;
List last;
while ( tmp->next != NULL)
{
last = tmp;
tmp = tmp->next;
}
free(last->next); // delete the last node in the list
last->next = NULL;
}
free(*self); // now delete the only existing node
}
I want to create a circular queue using linked list,also i want to create instance of that data structure(queue) not just one queue, many queues without repeating the code. this is what i came up with...
#include <stdio.h>
#include <stdlib.h>
struct queue
{
int info;
struct queue *next;
struct queue *front;
struct queue *rear;
};
void create(struct queue **q)
{
(*q)->next = 0;
(*q)->front = 0;
(*q)->rear = 0;
}
struct queue* makenode(int item){
struct queue* p = (struct queue*)malloc(sizeof (struct queue));
if (p) p->info = item;
return p;
}
void addLast(struct queue **q, int item){
struct queue* p = makenode(item);
if ((*q)->front == NULL){
(*q)->front = (*q)->rear = p;
(*q)->front->next = (*q)->front;
(*q)->rear->next = (*q)->rear;
}
else
{
(*q)->rear->next = p;
p->next = (*q)->front;
(*q)->rear = p;
}
}
int delFirst(struct queue **q){
struct queue *p = (*q)->front;
if ((*q)->front == 0)
printf("\nEmpty Queue\n");
else
{
int temp = (*q)->front->info;
if (((*q)->front->next) != ((*q)->front))
{
(*q)->front = (*q)->front->next;
(*q)->rear->next = (*q)->front;
}
else
{
(*q)->front = 0;
}
return temp;
}
free(p);
}
void main()
{
struct queue *premium, *normal;
create(&premium);
create(&normal);
addLast(&premium, 5);
addLast(&premium, 10);
addLast(&normal, 20);
addLast(&normal, 30);
printf("%i\n", delFirst(&premium));
printf("%i\n", delFirst(&premium));
delFirst(&premium);
printf("%i\n", delFirst(&normal));
printf("%i\n", delFirst(&normal));
delFirst(&normal);
getch();
}
Is there any good way to do this? I kinda feel my code is complicated. I am new to C programming and I only learned basics about queues and linked list.so i don't know even my code is 100% right or an elegant code. I compiled this code using DevC++ works fine, but when I compile it using MS Visual Studio 2013, it gave me an exception "Access violation writing location....”. so i am very sure my code is not that good. Please help me out. Thanks
Problem 1: data structure
You have one structure that contains both the linked list item (info and next element) and the queue structure (front and rear, which should be the same for all elements.
I'd suggest to use:
struct queue_item
{
int info;
struct queue_item *next;
};
struct queue
{
struct queue_item *front;
struct queue_item *rear;
};
Problem 2: queue creation
When you call create(), the pointer which address you pass (for example premium) is not yet initialized. It can point anywhere ! Most certainly to an invalid location. It doesn't point to a queue yet. So when you do things like (*q)->next = 0;, you try to overwrite an illegal location.
With the data structure proposed above, I propose the following :
struct queue* create (struct queue *q) /* q points to a queue already allocated, or it is NULL */
{
if (q==NULL)
q = malloc(sizeof (struct queue));
if (q) {
q->front = 0;
q->rear = 0;
}
return q;
}
In main() you'd then have the choice:
struct queue *premium, normal;
premium = create(NULL); /* allocate the queue structure */
create(&normal); /* use an allocated structure */
Problem 3: Node pointers not initialized at node creation
malloc() does not initialize the memory it returns. If you do'nt initialize the link pointer(s), these may in fact contain something else than NULL.
struct queue_item* makenode(int item){
struct queue* p = (struct queue_item*)malloc(sizeof (struct queue_item));
if (p) {
p->info = item;
p->next = NULL; /* There is no link yet, so make it clear to avoid any surprises later. */
}
return p;
}
Problem 4: Inconsistencies when adding/deleting items
With the new data structure, you'll have to adapt your addLast() and delFirst(). But it'll be clearer, because front and rear are at the level of the queue, and next is only at the level of the item.
From the signature, it'll be posible to avoid double indirection because the pointer to the queue will never be changed by these operations:
void addLast(struct queue *q, int item);
int delFirst(struct queue *q);
Your first problem is that you invoke create() on uninitialized pointers:
void create(struct queue **q)
{
(*q)->next = 0;
…
}
int main()
{
struct queue *premium, *normal;
create(&premium);
create(&normal);
Either you need to call makenode() inside the create() function or in main(), or you need to provide structures for premium and normal to point at.
Option A:
void create(struct queue **q)
{
*q = makenode(0);
if (*q != 0)
{
(*q)->next = 0;
…
}
}
Option B:
int main()
{
struct queue q_premium, q_normal;
struct queue *premium = &q_premium;
struct queue *normal = &q_normal;
create(&premium);
create(&normal);
Either technique can be made to work, but Option B requires care because the structures q_premium and q_normal are not allocated (though they could be if that was necessary). However, the signature of create() suggests that Option A is what was intended because Option B really doesn't require the double pointer in create().
I'm not clear what, if any, benefit the mix of three pointers — front, rear, next — provides to your structure. I implemented a circular DLL for my own benefit, just to see what might be involved, and I only needed a data pointer and next and previous pointers. From any element in the list, you can reach every other element in the list. You can insert before or after a given node, remove a given node, apply a function to all nodes, or find the first node that matches a predicate provided by a function (and get the next node, previous node or the data), or destroy the entire list.
My impression is that your code would be simpler without one of the pointers.
With the Option A change, the code compiles and seems to work, producing:
5
10
Empty Queue
20
30
Empty Queue