C programming linked list and queue with an array [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I need to enqueue a whole struct customer in the queue - I think. This is my homework. I am not asking for an answer. I need a mentor to explain what I am missing and what I have right per the assignment. I am very new. This is my second program. see below... thanks btw.
A store is having customers queue in several lines. After the cashier finishes helping a customer, he will survey all of the lines that are currently queued. Of all of the customers at the front of those lines, he’ll take the customer who has the fewest number of items. If there are two customers with the same number of items, he’ll take the customer who comes from the smaller line number. The lines are numbered 1 through 12. It’s possible that some of these lines will be empty, in which case these lines are ignored. The number of seconds the store clerk takes to check out a customer is 30 plus 5 times the number of items. Thus, if a customer has 8 times, the clerk would check her out in 30 + 8*5 = 70 seconds.
The Problem
You will write a program that reads in information about customers: which line they go to the back of (1 through 12), at what time (in seconds) they enter that line, and the number of items they have, and determines at what time each customer will check out.
Sample Input:
2
5
10 1 STEVEN 12
12 6 AHMAD 8
13 1 JENNY 40
22 6 JERMAINE 39
100000 12 AMALIA 53
6
100 1 A 100
200 2 B 99
300 3 C 98
400 4 D 97
500 5 E 96
600 6 F 95
Sample Output:
STEVEN from line 1 checks out at time 100.
AHMAD from line 6 checks out at time 170.
JERMAINE from line 6 checks out at time 395.
JENNY from line 1 checks out at time 625.
AMALIA from line 12 checks out at time 100295.
A from line 1 checks out at time 630.
F from line 6 checks out at time 1135.
E from line 5 checks out at time 1645.
D from line 4 checks out at time 2160.
C from line 3 checks out at time 2680.
B from line 2 checks out at time 3205.
Implementation Restrictions:
You must create a struct that stores information about a customer (name, number of items, line number, time entering line). Note that the storage of the line number is redundant, but is designed to ease implementation.
You must create a node struct for a linked list of customers. This struct should have a pointer to a customer struct, and a pointer to a node struct.
You must create a struct to store a queue of customers. This struct should have two pointers – one to the front of the queue and one to the back.
You must implement all of the lines that form as an array of size 12 (stored as a constant) of queues.
You must dynamically allocate memory as appropriate for linked lists.
Your queue must support the following operations:
a. Enqueue
b. Dequeue
c. Return the front of the queue WITHOUT dequeing d. Empty (returns 1 if the queue is empty, 0 if it is not)
You must free memory appropriately. Namely, when you dequeue, you’ll free memory for a node, but you will NOT free memory for the customer. You will free this memory a bit later right after you calculate when that customer will finish checking out.
Due to the nature of the problem, when you process the input, you can add everyone into their appropriate lines right at the beginning, before checking anyone out.
This wouldn’t work in all simulations (some of which you have to do in time order), but because there is ONLY one check out line, you can get away with it. The only thing you have to be cognizant about is that when you select a line, if the current time is, 100 for example, and three lines have customers who arrived before time 100 and the other lines have customers in the front who arrived AFTER time 100, you have to ignore the customers in those lines who arrived after time 100. In the case that all the lines have customers who arrived after time 100, you would take the line which has a customer who arrived first. You are guaranteed no ties for arrival time so this would be unique.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TRUE 1
#define FALSE 0
typedef char customerName[9];
typedef struct node
{
int data;
struct node *next;
}node;
typedef struct queue
{
int size;
int front;
int back;
int *array;
unsigned capacity;
}queue;
typedef struct customer
{
customerName name;//1-9 upper case letters
int lineNumber;
int time;
int numberItems;
} customer;
int isEmpty(queue *q);
void initialize(queue *q);
void initialize(queue *q)
{
q->size = 0;
q->front = -1;
q->back = -1;
}
int isEmpty(queue *q){
return (q->size == 0);//returns 1 if empty or 0 if false
}
int isFull(queue *q)
{ return (q->size == q->capacity); }
void enqueue(queue *q, int item)
{
if (isFull(q))
return;
q->back = (q->back + 1)%q->capacity;
q->array[q->back] = item;
q->size = q->size + 1;
}
int dequeue(queue *q)
{
if (isEmpty(q))
return 0;
int item = q->array[q->front];
q->front = (q->front + 1)%q->capacity;
q->size = q->size - 1;
return item;
}
int front(queue* q){
if(isEmpty(q)){
return 0;
}
return q->array[q->front];
}
int main(int argc, const char * argv[]) {
int testCases = 0;
scanf("%d", &testCases);
if(testCases > 0 && testCases <= 25){//shortcircuiting???
while (testCases--){
queue *q;
q = malloc(sizeof(queue));
initialize(q);// starting new queue
int numCustomers;
scanf("%d", &numCustomers);
if(numCustomers < 0 || numCustomers > 11){
return 0;
}
struct customer newCustomer[1];
for ( int i = 0; i < numCustomers; i++){
scanf("%d", &newCustomer[i].time);
scanf("%d", &newCustomer[i].lineNumber);
scanf("%s", newCustomer[i].name);
scanf("%d", &newCustomer[i].numberItems);
enqueue(q, newCustomer[i].time);
enqueue(q, newCustomer[i].lineNumber);
}
for ( int i = 0; i < numCustomers; i++){
printf("%d %d %s %d\n", newCustomer[i].time, newCustomer[i].lineNumber, newCustomer[i].name, newCustomer[i].numberItems);
}
}
}
return 0;
}
Here is my latest code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TRUE 1
#define FALSE 0
#define NUMLINES 12
int currtime = 0;
typedef char customerName[9];
typedef struct node
{
int data;
struct customer* data;
struct node* next;
}node;
typedef struct queue
{
node* front;
node* back;
}queue;
typedef struct customer
{
customerName name;//1-9 upper case letters
int lineNumber;
int time;
int numberItems;
} customer;
typedef struct node *newNode;//define a node pointer
node createNode()
{
newNode temp;//declare node
temp = (newNode)malloc(sizeof(struct node));//allocate memory
temp->next = NULL;//next point to null
return *temp;// return the new node
}
struct queue* createQueue()
{
struct queue* q = (struct queue*)malloc(sizeof(struct queue));
q->front = q->back = NULL;
return q;
}
int isEmpty(queue *q){
return (q->back == NULL);//returns 1 if empty or 0 if false
}
void enqueue(queue *q, customer* data)
{
// Create a new LL node
struct node* temp = createNode(data);
// If queue is empty, then new node is front and back both
if (q->back == NULL) {
q->front = q->back = temp;
return;
}
// Add the new node at the end of queue and change back
q->back->next = temp;
q->back = temp;
}
void dequeue(queue *q)
{
if (q->front == NULL)
return;
// Store previous front and move front one node ahead
struct node* temp = q->front;
q->front = q->front->next;
// If front becomes NULL, then change rear also as NULL
if (q->front == NULL)
q->back = NULL;
free(temp);
}
int front(queue* q){
if(isEmpty(q)){
return 0;
}
return q->front;
}
int main(int argc, const char * argv[]) {
int testCases = 0;
scanf("%d", &testCases);
if(testCases > 0 && testCases <= 25){//shortcircuiting???
while (testCases--){
queue *q;
q = malloc(sizeof(queue));
initialize(q);// starting new queue
int numCustomers;
scanf("%d", &numCustomers);
if(numCustomers < 0 || numCustomers > 11){
return 0;
}
struct customer newCustomer[11];
for ( int i = 0; i < numCustomers; i++){
scanf("%d", &newCustomer[i].time);
scanf("%d", &newCustomer[i].lineNumber);
scanf("%s", newCustomer[i].name);
scanf("%d", &newCustomer[i].numberItems);
enqueue(q, newCustomer[i].time);
enqueue(q, newCustomer[i].lineNumber);
}
for ( int i = 0; i < numCustomers; i++){
printf("%d %d %s %d\n", newCustomer[i].time, newCustomer[i].lineNumber, newCustomer[i].name, newCustomer[i].numberItems);
}
}
}
return 0;
}
int main(int argc, const char * argv[]) {
int testCases = 0;
scanf("%d", &testCases);
if(testCases > 0 && testCases <= 25){//shortcircuiting???
while (testCases--){
queue *q;
q = malloc(sizeof(queue));
qinit(q);// starting new queue
int numCustomers;
scanf("%d", &numCustomers);
if(numCustomers < 0 || numCustomers > 11){
return 0;
}
queue* customerArray = (queue*) malloc(sizeof(queue) * 12);
for ( int i = 0; i < numCustomers; i++){
customer* newCustomer = (customer*) malloc(sizeof(customer));
scanf("%d", &(newCustomer->time));
scanf("%d", &(newCustomer->lineNumber));
scanf("%s", newCustomer->name);
scanf("%d", &(newCustomer->numberItems));
enqueue(&customerArray[newCustomer->lineNumber - 1], newCustomer);
}
int totalTime = INT_MAX;
for(int i=0;i<12;i++)
{
customer* frontCustomer = qfront(&customerArray[i]);
if(totalTime < frontCustomer->time)
{
totalTime = frontCustomer->time;
}
free(frontCustomer);
}
while(numCustomers--) {
int customerToCheckOutLine = 0; int minNumberOfItems = INT_MAX;
for( int j=11 ; j>=0; j--){
customer* frontCustomer = qfront(&customerArray[j]);
if(frontCustomer->time <= totalTime)
{
if(frontCustomer->numberItems < minNumberOfItems)
{
customerToCheckOutLine = frontCustomer->lineNumber;
minNumberOfItems = frontCustomer->numberItems;
}
free(frontCustomer);
}
}
customer* customerToCheckOut = qfront(&customerArray[customerToCheckOutLine -1 ]);
totalTime += 30;
totalTime += (customerToCheckOut->numberItems) * 5;
dequeue(&customerArray[customerToCheckOutLine - 1]);
}
free(customerArray);
}
}
return 0;
}

Your queue related functions look okay.
But, there are some bugs and the code needs refactoring to handle more things.
Your queue element array should be of type node * instead of int *.
You need the newCustomer array to be of length numCustomers (i.e. not 1).
At present, you have a single queue. But, you need an array of queues, one for each line, so an array length of 12.
When you queue a customer, you must select the queue [from the array of queues] based on the line number the customer is getting on.
Here's a biggie:
You can't queue two separate entries, one being time and the other being lineNumber. Well, you can I guess, but it's messy.
The way I'd do it is to change the data element of the node struct to be a pointer to the customer record. That way, every bit of data you need to determine the servicing order is [already] in the customer struct.
Anyway, here's some refactored code.
Per your request, it's not a solution, but some sample code as a basis for implementing the above fixes/suggestions.
You still have to change the queue struct and all queue related functions (if you decide to change the struct as I've suggested).
And, you still have to implement the selection/ordering process. And, the cleanup/deallocation.
This won't compile as is, because it's a "suggestion", but here it is:
typedef char customerName[9];
typedef struct customer {
customerName name; // 1-9 upper case letters
int lineNumber;
int time;
int numberItems;
} customer;
typedef struct node {
#if 0
int data;
#else
customer *data;
#endif
struct node *next;
} node;
typedef struct queue {
int size;
int front;
int back;
#if 0
int *array;
#else
node *array;
#endif
unsigned capacity;
} queue;
#if 1
#define NUMLINES 12
queue queue_list[NUMLINES];
#endif
int isEmpty(queue *q);
void initialize(queue * q);
void
initialize(queue *q)
{
q->size = 0;
q->front = -1;
q->back = -1;
}
int
isEmpty(queue *q)
{
return (q->size == 0); // returns 1 if empty or 0 if false
}
int
isFull(queue *q)
{
return (q->size == q->capacity);
}
void
enqueue(queue *q, int item)
{
if (isFull(q))
return;
q->back = (q->back + 1) % q->capacity;
q->array[q->back] = item;
q->size = q->size + 1;
}
int
dequeue(queue *q)
{
if (isEmpty(q))
return 0;
int item = q->array[q->front];
q->front = (q->front + 1) % q->capacity;
q->size = q->size - 1;
return item;
}
int
front(queue *q)
{
if (isEmpty(q)) {
return 0;
}
return q->array[q->front];
}
int
main(int argc, const char *argv[])
{
queue *q;
int testCases = 0;
scanf(" %d", &testCases);
// NOTE/BUG: you need a separate queue for each line
for (int qidx = 0; qidx < NUMLINES; ++qidx) {
q = &queue_list[qidx];
initialize(q);
}
// shortcircuiting???
if (testCases > 0 && testCases <= 25) {
while (testCases--) {
#if 0
queue *q;
#endif
#if 0
q = malloc(sizeof(queue));
initialize(q); // starting new queue
#endif
int numCustomers;
scanf(" %d", &numCustomers);
if (numCustomers < 0 || numCustomers > 11) {
return 0;
}
// NOTE/BUG: you need a larger array of customers
#if 0
struct customer newCustomer[1];
#else
struct customer newCustomer[numCustomers];
#endif
for (int i = 0; i < numCustomers; i++) {
customer *cust = &newCustomer[i];
scanf(" %d", &cust->time);
scanf(" %d", &cust->lineNumber);
scanf(" %s", cust->name);
scanf(" %d", &cust->numberItems);
// NOTE/BUG: customer must be queued to the queue for the
// line number they're on
// NOTE/BUG: queue a single entry for each customer
#if 0
enqueue(q, cust->time);
enqueue(q, cust->lineNumber);
#else
q = &queue_list[cust->lineNumber - 1];
enqueue(q,cust);
#endif
}
for (int i = 0; i < numCustomers; i++) {
printf("%d %d %s %d\n",
newCustomer[i].time,
newCustomer[i].lineNumber,
newCustomer[i].name,
newCustomer[i].numberItems);
}
}
}
return 0;
}
UPDATE:
woah, this is amaze balls. thank you so much. I think the assignment is confusing because he says the assignment is queues with linked list not an array but like you said it needs to be an array of queues. that would suggest multiple entries into a single line. so in a sense this is both an queues with linked lists and array?
You need an array of queues, indexed by linenumber. This is not to be confused with the q->array element within the queue, which is different.
I just completed a working and tested version [for myself, because I'm crazy that way :-)]. I had the same confusion.
The queue is a ring queue [with array]. If the array pointer is a customer *, I couldn't find a good way to use node. The only way to do it would be to convert queue into a linked list header struct. That would require queue to be restructured [along will all the access functions for it ;-)].
But, before doing that, if we keep the array/ring method, then initialize needs to take a capacity arg (called with initialize(q,numCustomer);). And, it needs to do (e.g.) q->array = realloc(q->array,sizeof(customer *) * capacity);
And, enqueue needs a fix: the increment of q->back needs to be moved after the q->array[q->back] = item;. Currently, there is an off by one gap.
To convert to a linked list:
The structs change a bit:
typedef struct node {
customer *data;
struct node *next;
} node;
typedef struct queue {
node *front;
} queue;
You have an isFull function. That's not part of the requirements. If we switch queue into a linked list header for a list of node, it isn't even relevant/meaningful since, now, there is no maximum [as there was with q->capacity].
Now, when doing enqueue(q,cust);, the function would malloc a new node and append it to the end of the linked list. And, setup of (e.g.) newnode->next and newnode->data = cust;
When doing dequeue, it pops off the front element (a node), does cust = curnode->data;, then free(curnode), and returns cust.
Based on my rereading the requirements, I believe that this is what's required, and actually makes sense of all of them.
In other words, you can implement a queue with just a linked list (vs. what you did which was a ring queue with array--which I've also done in the past).
the ordering process is part of the reason I am so confused. I don't know where to do this. The list is already ordered by time the customer went to check out. I just need to calculate the total cashier time.there is only one cashier so all the people are served in order of entering the queue.
This is a bit tricky. You have to have a curtime global to keep track of the current time. Initially, this has to be set to the minimum of all cust->time values.
As you loop through all queues [i.e. waiting lines] to look at the first customer on the line, you have to do the following:
You skip the queue if it's empty.
You skip any customer if they have an arrival date in the future (i.e. cust->time > curtime).
Now you can "select" the customer. You need the find "best" customer [for the next one to be serviced]. That is, the one with the smallest order. The 2nd criteria of: with a tie, the customer with the lowest line number wins is handled automatically if you only update the "best" value if (cust->numberItems < best->numberItems) because we're traversing the queue_list array from low to high.
Then, service the "best" customer (i.e. print the message). Then, increment curtime by the elapsed time it takes to service the customer.
Repeat this until all queues are empty.
But, there is one gotcha. It happens with AMALIA.
The arrival time for this customer is so far in the future that the customer selection will fail to find any "best" customer because amalia->time is greater than curtime. Thus, it seems like AMALIA is not ready to be serviced.
So, if the selection fails (i.e. best is null), we have to loop through all front customers [again] and set curtime to the minimum of all their arrival times.
Then, we rescan/reselect for "best". Now, AMALIA will be selected
UPDATE #2:
in your example I don't understand what the #elseif etc. what are those? other than the obvious, I have never seen this
The lines starting with #if are preprocessor statements [just like #include, #ifdef, #else, #endif
The preprocessor is used to include/exclude code at compile time (vs using a real if language statement). You can think of the preprocessor as a separate pass before compilation that performs the conditional actions before passing the resultant file to the compile stage.
In my examples, I'm using them to show old code [yours] vs. new code [mine]:
#if 0
// old code ...
x = 1;
#else
// new code ...
x = 2;
#endif
When compiled, the old code is excluded, the new code is included as if we had done:
// new code ...
x = 2;
This is a useful technique in general. It allows you to "comment out" code that you suspect might be a bug. Or, for debug printf code. Or, you have working code (the "old" code), but you want to try something possibly cleaner or more efficient (the "new" code). You can flip back and forth during development just by changing #if 0 to #if 1 or vice versa
You can see the intermediate file by doing:
cc -E -P -o myfile.i myfile.c
Later on, when your code is [fully ;-)] debugged, you could hand edit out the #if cases you don't need/want.
can you do that same kind of example but for the linked list only implementation? or is that asking too much? :) why is there only a *front and no back of the list?
For a simple singly linked list, we only truly need a head/front pointer.
We don't need size because the empty case is: q->front == NULL. size is primarily useful if we had to sort the linked list (it saves a pass on the list to get the number of elements).
Using q->back adds a slight degree of complexity. It's a speedup when appending to the queue/list. If we don't have it, we find the last element in the list by traversing it. If we have back, that is the last element.
A singly linked list is sufficient for your use case. But, just for completeness, I've added doubly linked list support. We add a prev element to node [the backwards link].
Below, I've coded up the linked list structs and functions. To allow you to see the various modes, each optional element is wrapped in preprocessor #if/#endif pairs to include/exclude code, based on setting the given option on/off
DLINK [doubly linked list] is off by default
To enable it on a one time basis, you could do:
cc -DDLINK=1 -c myfile.c
Likewise for other options.
Anyway, here's the queue code based on a linked list:
// customer record
typedef char customerName[9];
typedef struct customer {
customerName name; // 1-9 upper case letters
int lineNumber; // line number customer gets on
int time; // arrival time at line
int numberItems; // number of items customer has
} customer;
// 1=use queue q->back
// need this for _doubly_ linked list
// speedup for append to end of queue for singly linked
#ifndef QBACK
#define QBACK 1
#endif
// 1=use queue q->size
#ifndef QSIZE
#define QSIZE 1
#endif
// 1=use doubly linked list
#ifndef DLINK
#define DLINK 0
#endif
// force QBACK on if doing doubly linked list
#if DLINK
#undef QBACK
#define QBACK 1
#endif
// [singly linked] queue element
typedef customer *qitem;
typedef struct node {
qitem data; // pointer to actual data
struct node *next; // forward pointer to next item
#if DLINK
struct node *prev; // backward pointer to previous item
#endif
} node;
// queue definition (singly linked list)
// NOTE:
typedef struct queue {
node *front; // pointer to first node in list
#if QBACK
node *back; // pointer to last node in list
#endif
#if QSIZE
int size; // current number of elements in list
#endif
} queue;
// list of queues (indexed by lineNumber - 1)
#define NUMLINES 12
queue queue_list[NUMLINES];
// qinit -- initialize/reset queue
void
qinit(queue *q)
{
q->front = NULL;
#if QSIZE
q->size = 0;
#endif
#if QBACK
q->back = NULL;
#endif
}
// qempty -- returns 1 if empty or 0 if false
int
qempty(queue *q)
{
// NOTE: size really isn't needed
#if 0
return (q->size == 0);
#else
return (q->front == NULL);
#endif
}
// enqueue -- append element to end of queue
void
enqueue(queue *q, qitem data)
{
node *newnode;
node *prev;
newnode = malloc(sizeof(node));
newnode->next = NULL;
newnode->data = data;
// NOTE: this is the only place where back is a speedup
#if QBACK
prev = q->back;
#else
// what we have to do find the back of the queue with only a front pointer
prev = NULL;
for (node *cur = q->front; cur != NULL; cur = cur->next)
prev = cur;
#endif
// append to tail of list
if (prev != NULL)
prev->next = newnode;
// add to end of empty list
else
q->front = newnode;
#if DLINK
newnode->prev = prev;
#endif
#if QBACK
q->back = newnode;
#endif
#if QSIZE
q->size += 1;
#endif
}
// dequeue -- dequeue from the front of the queue
qitem
dequeue(queue *q)
{
node *curnode;
qitem data;
do {
curnode = q->front;
// bug out if list is empty
if (curnode == NULL) {
data = NULL;
break;
}
// get node's data value (e.g. pointer to customer struct)
data = curnode->data;
#if QBACK
node *back = q->back;
#if DLINK
curnode->prev = back;
#endif
if (curnode == back)
q->back = curnode->next;
#endif
q->front = curnode->next;
#if QSIZE
q->size -= 1;
#endif
// release the node's storage back to the heap
free(curnode);
} while (0);
return data;
}
// qfront -- peek at front of queue
qitem
qfront(queue *q)
{
node *curnode;
qitem data;
curnode = q->front;
if (curnode != NULL)
data = curnode->data;
else
data = NULL;
return data;
}
UPDATE #3:
so my main function has a memory leak and I cannot find it. I am trying to learn Valgrind and gdb but there is a learning curve. My Valgrind outran is like 90,000 characters for some reason and doesn't say hey I have a memory leak. I don't even know what line. I appended my new main to the bottom of the above code.
A few issues:
You malloc the q pointer at the top of the outer while (testCases--) loop but do not free it.
But, as I mentioned, you need an array of queues [which can be a fixed array] and you've already done that.
But, q was your original/legacy code. The rest of your code no longer uses q. You just forgot to remove it.
You are now using customerArray instead. But, you are not calling qinit on each array element, so you could have a random data in each.
In the problem definition, the number of customer lines is fixed at 12, so you really don't need to malloc and free it. That's why I used a global array instead.
You have a bug in your totalTime calculation loop. You're doing a free of the customer record. So, the record is no longer valid in the loop below it.
And, in that second loop, you're doing a second free of the same struct. So, at present, this is a "double free" bug. The second loop is actually the correct place for the free [not the first loop]
This program is ambitious for a second ever assignment, so you're "being thrown out into the middle of the lake and being asked to swim to shore".
I would have expected a few more intermediate steps/programs before trying to code up this one.
When starting out, as you are, sometimes it's as important to study working code as it is to write it from scratch.
So, spoiler alert, here's my final, fully working code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TIME_PAST -1 // infinite time in the past
#define TIME_FUTURE INT_MAX // infinite time in the future
int curtime; // current time
// customer record
typedef char customerName[9];
typedef struct customer {
customerName name; // 1-9 upper case letters
int lineNumber; // line number customer gets on
int time; // arrival time at line
int numberItems; // number of items customer has
} customer;
// 1=use queue q->back
// need this for _doubly_ linked list
// speedup for append to end of queue for singly linked
#ifndef QBACK
#define QBACK 1
#endif
// 1=use queue q->size
#ifndef QSIZE
#define QSIZE 1
#endif
// 1=use doubly linked list
#ifndef DLINK
#define DLINK 0
#endif
// force QBACK on if doing doubly linked list
#if DLINK
#undef QBACK
#define QBACK 1
#endif
// [singly linked] queue element
typedef customer *qitem;
typedef struct node {
qitem data; // pointer to actual data
struct node *next; // forward pointer to next item
#if DLINK
struct node *prev; // backward pointer to previous item
#endif
} node;
// queue definition (singly linked list)
// NOTE:
typedef struct queue {
node *front; // pointer to first node in list
#if QBACK
node *back; // pointer to last node in list
#endif
#if QSIZE
int size; // current number of elements in list
#endif
} queue;
// list of queues (indexed by lineNumber - 1)
#define NUMLINES 12
queue queue_list[NUMLINES];
// qinit -- initialize/reset queue
void
qinit(queue *q)
{
q->front = NULL;
#if QSIZE
q->size = 0;
#endif
#if QBACK
q->back = NULL;
#endif
}
// qempty -- returns 1 if empty or 0 if false
int
qempty(queue *q)
{
// NOTE: size really isn't needed
#if 0
return (q->size == 0);
#else
return (q->front == NULL);
#endif
}
// enqueue -- append element to end of queue
void
enqueue(queue *q, qitem data)
{
node *newnode;
node *prev;
newnode = malloc(sizeof(node));
newnode->next = NULL;
newnode->data = data;
// NOTE: this is the only place where back is a speedup
#if QBACK
prev = q->back;
#else
// what we have to do find the back of the queue with only a front pointer
prev = NULL;
for (node *cur = q->front; cur != NULL; cur = cur->next)
prev = cur;
#endif
if (prev != NULL)
prev->next = newnode;
else
q->front = newnode;
#if DLINK
newnode->prev = prev;
#endif
#if QBACK
q->back = newnode;
#endif
#if QSIZE
q->size += 1;
#endif
}
// dequeue -- dequeue from the front of the queue
qitem
dequeue(queue *q)
{
node *curnode;
node *nextnode;
qitem data;
do {
// get the first node
curnode = q->front;
// if none, return null data
if (curnode == NULL) {
data = NULL;
break;
}
// get the data payload
data = curnode->data;
// point to the next node (i.e. second node)
nextnode = curnode->next;
#if QBACK
node *back = q->back;
#if DLINK
curnode->prev = back;
#endif
if (curnode == back)
q->back = nextnode;
#endif
q->front = nextnode;
#if QSIZE
q->size -= 1;
#endif
free(curnode);
} while (0);
return data;
}
// qfront -- peek at front of queue
qitem
qfront(queue *q)
{
node *curnode;
qitem data;
curnode = q->front;
if (curnode != NULL)
data = curnode->data;
else
data = NULL;
return data;
}
// custfind -- find next customer to serve
customer *
custfind(void)
{
int pass;
int qidx;
queue *q;
int mintime;
int moreflg;
customer *cust;
customer *best;
// pass 1:
// - remember the minimum time
// - find best using curtime
for (pass = 1; pass <= 2; ++pass) {
best = NULL;
mintime = TIME_FUTURE;
moreflg = 0;
// scan all queues -- examine _first_ customer on each line
for (qidx = 0; qidx < NUMLINES; ++qidx) {
q = &queue_list[qidx];
// get first customer on current line
cust = qfront(q);
if (cust == NULL)
continue;
// remember that there is at least _one_ customer waiting
moreflg = 1;
// remember the minimum time
if (cust->time < mintime)
mintime = cust->time;
// has the customer actually arrived yet? -- skip if not
if (cust->time > curtime)
continue;
// no previous "best" customer -- set from current
if (best == NULL) {
best = cust;
continue;
}
// get better customer (has fewer items to check out)
if (cust->numberItems < best->numberItems) {
best = cust;
continue;
}
}
// no more customers
if (! moreflg)
break;
// found a best match
// dequeue and free node
if (best != NULL) {
q = &queue_list[best->lineNumber - 1];
dequeue(q);
break;
}
// no best match found
// all customers are in the future [based on curtime]
// set new current time based on minimum time of all remaining customers
// the second pass _will_ find at least one after we do this
curtime = mintime;
}
return best;
}
// custdo -- check out customer
void
custdo(customer *cust)
{
int elap;
// current time has to be _at least_ the arrival time
if (curtime < cust->time)
curtime = cust->time;
// get amount of time it takes to service this customer
elap = 0;
elap += 30;
elap += cust->numberItems * 5;
// set current time after servicing the customer
curtime += elap;
printf("%s from line %d checks out at time %d.\n",
cust->name,cust->lineNumber,curtime);
// release the customer record storage
free(cust);
}
// testcase -- process a test case
void
testcase(FILE *fi)
{
queue *q;
customer *cust;
// reset all queues
// NOTE: probably not required
for (int qidx = 0; qidx < NUMLINES; ++qidx) {
q = &queue_list[qidx];
qinit(q);
}
// get number of customers for this case
int numCustomers;
fscanf(fi," %d", &numCustomers);
// read in all customer records for this test case
for (int icust = 0; icust < numCustomers; ++icust) {
cust = malloc(sizeof(*cust));
fscanf(fi," %d", &cust->time);
fscanf(fi," %d", &cust->lineNumber);
fscanf(fi," %s", cust->name);
fscanf(fi," %d", &cust->numberItems);
// add customer to appropriate line/queue
q = &queue_list[cust->lineNumber - 1];
enqueue(q,cust);
}
// set current time to [way in the] past
curtime = TIME_PAST;
while (1) {
// find the next customer
cust = custfind();
// no more customers
if (cust == NULL)
break;
// service customer
custdo(cust);
}
}
int
main(int argc, char **argv)
{
char *ifile;
FILE *fi;
--argc;
++argv;
// open the input file
if (argc > 0)
ifile = *argv;
else
ifile = "input.txt";
fi = fopen(ifile,"r");
if (fi == NULL) {
perror(ifile);
exit(1);
}
// get number of test cases
int testCases;
fscanf(fi," %d", &testCases);
// process all test cases
for (; testCases > 0; --testCases)
testcase(fi);
fclose(fi);
return 0;
}

Related

How do I fix these conflicting types error when passing linked list in C?

I am very new to C and have not had much experience with linked lists. I am trying to create a disk scheduling program in FCFS and add the track requests to a queue (a linked list) for an assignment and am getting a plethora of warnings and a couple errors when trying to compile and I cannot figure out why. the errors I'm getting are on lines 86 and 101: conflicting types for 'AddToList' and 'RemoveFromList'. If someone could help me figure out what the issue is and how to fix it, it will be much appreciated. Thanks!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <values.h>
#include <time.h>
#include <stdbool.h>
/* function declarations */
int trackReqs(void);
int numTrack(void);
void AddToList(struct Queue_Struct *req_queue, int trackNum);
int RemoveFromList(struct Queue_Struct *req_queue);
// global variable declarations/initializations
unsigned seed;
int fileReqs;
bool first = true;
struct Queue_Node{
int trackNumber;
struct Queue_Node *next;
};
struct Queue_Struct{
struct Queue_Node *q_head;
struct Queue_Node *q_tail;
};
struct Queue_Struct fcfs;
void main(){
fcfs.q_head = NULL;
fcfs.q_tail = NULL;
printf("Seed for the random number generator: ");
scanf("%d", &seed);
srand(seed);
//printf("\n");
printf("Number of file requests: ");
scanf("%d", &fileReqs);
//printf("\n");
// local variable declarations/initializations
int totalReqs = 0;
int numFileReqs = 0;
float totalHeadMove = 0;
int currTrack = 0;
float diff;
float average;
do { // do this...
int numTrackReqs = trackReqs(); // call function to get a random number between 1 and 5 to represent the number of track requests for the current file request
for (int i = 0; i < numTrackReqs; i++) { // for each track request for the current file request...
int trackNum = numTrack(); // call function to get a random number between 0 and 799 to represent the number of the track requested
AddToList(&fcfs, trackNum); // call function to add the track request to the queue
first = false;
}
int nextTrack = RemoveFromList(&fcfs); // call function to remove the next (first) track request from the queue (signifying that the disk head will be moved to that track) and have that track returned
diff = abs((float)nextTrack - (float)currTrack); // calculate the head movement for the current file request
totalHeadMove += diff; // add the head movement for the current file request to the total head movement
totalReqs++; // increase number of total requests by 1
currTrack = nextTrack; // make the current track now the next track
numFileReqs++; // increase number of file requests by 1
} while(numFileReqs <= fileReqs); // ...for each file request
average = totalHeadMove / (float) numFileReqs; // calculate the average total head movement for each file request and print the result
printf("Average head movement: %5.2f\n", average);
}
int trackReqs(void){
int rand_num = (rand() % (5 - 1 + 1)) + 1; // generate random number from 1 to 5 representing number of track requests for the current file request
return rand_num;
}
int numTrack(void){
int rand_num = rand() % 800; // generate random number from 0 to 799 representing
return rand_num;
}
void AddToList(struct Queue_Struct *req_queue, int trackNum){
struct Queue_Node *newnode;
newnode = (struct Queue_Node *) malloc(sizeof(struct Queue_Node));
newnode->next = NULL;
newnode->trackNumber = trackNum;
if(req_queue->q_tail == NULL){
req_queue->q_head = newnode;
req_queue->q_tail = newnode;
return;
}
req_queue->q_tail->next = newnode;
req_queue->q_tail = newnode;
return;
}
int RemoveFromList(struct Queue_Struct *req_queue){
struct Queue_Node *loc;
int first_req;
if(req_queue->q_head == NULL){
printf("***Error - Queue is Empty***\n");
return(NULL);
}
loc = req_queue->q_head;
first_req = loc->trackNumber;
if(req_queue->q_head == req_queue->q_tail){
req_queue->q_tail = NULL;
req_queue->q_head = NULL;
return first_req;
}
req_queue->q_head = loc->next;
free(loc);
return first_req;
}
Posting the comment as an answer: the problem was the forward declarations for the functions in question referred to the struct types before those types were defined.
I don’t recall the exact rules for this, and there are times when you do need to mention a struct type in advance of defining it, but this is not one of those.

C: Queue and Memory Limit Excedeed

I'm a C beginner and decided to participate in a small online contest in order to practice.
In the current problem I'm asked to write a queue with a struct that responds to the commands PushBack and PopFront.
The input consists of
A number n (n <= 1000000) indicating the number of commands inputs.
n lines. Each line consists of two integer numbers a and b:
a is 2 for executing PopFront, in which case b is the expected popped value.
a is 3 for PushBack, in which case b is the value to be enqueued.
If we try to pop from an empty queue then the value returned is -1.
The task is to print YES or NO after executing the last command if the value returned by any PushBack during the program execution coincide or not with the expected value.
I implemented a version of this, but after submitting my answer the online judge gives Maximum-Limit-Excedeed (in the last test out of 27).
I was reading about it and this issue may be related to some of these:
Using an array or data structure too big.
There is an infinite (or too big) recursion in the program.
An incorrect usage of pointers (diagnosed as MLE).
I'm not sure what is the problem. It seems to me that in some of the tests the number of addition of nodes is way greater than that of deletions (which means that 1. takes place in my code) which, in turn, causes the while loop in EmptyQueue to be too big (2. also takes place). I'm not able to spot whether there is an incorrect usage of pointers.
My questions are:
What am I'm doing wrong here?
What should I do to fix this?
Code:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
//===================
//Definitions:
typedef int Item;
typedef struct node
{
Item item;
struct node * next;
} Node;
typedef struct queue
{
Node * front;
Node * rear;
long counter;
} Queue;
//===================
//Function Prototypes:
void InitializeQueue(Queue * pq);
bool PushBack(Queue * pq, Item item);
int PopFront(Queue * pq);
void EmptyQueue(Queue * pq);
int main(void)
{
Queue line;
long n, i;
int command, expected, received;
bool check = true;
scanf("%ld", &n);
InitializeQueue(&line);
i = 0;
while (i < n)
{
scanf("%d %d", &command, &expected);
switch (command)
{
case 2:
received = PopFront(&line);
if (received != expected)
check = false;
break;
case 3:
PushBack(&line, expected);
break;
}
i++;
}
if (check == true)
printf("YES\n");
else
printf("NO\n");
// free memory used by all nodes
EmptyQueue(&line);
return 0;
}
void InitializeQueue(Queue * pq)
{
pq->front = NULL;
pq->rear = NULL;
pq->counter = 0;
}
bool PushBack(Queue * pq, Item item)
{
Node * pnode;
//Create node
pnode = (Node *)malloc(sizeof(Node));
if (pnode == NULL)
{
fputs("Impossible to allocate memory", stderr);
return false;
}
else
{
pnode->item = item;
pnode->next = NULL;
}
//Connect to Queue
if (pq->front == NULL)
{
pq->front = pnode;
pq->rear = pnode;
}
else
{
pq->rear->next = pnode;
pq->rear = pnode;
}
pq->counter++;
return true;
}
int PopFront(Queue * pq)
{
int popped;
Node * temp;
temp = pq->front;
if (pq->counter == 0)
return -1;
else
{
popped = pq->front->item;
pq->front = pq->front->next;
free(temp);
pq->counter--;
return popped;
}
}
void EmptyQueue(Queue * pq)
{
int dummy;
while (pq->counter != 0)
dummy = PopFront(pq);
}
Thanks.
I don't think there's actually anything wrong with that code functionally, though it could do with some formatting improvements :-)
I will mention one thing:
The task is to check whether the returned value after executing PopFront coincides with the expected one. If so, then print YES. Print NO, otherwise.
I would read this as a requirement on each PopFront. You appear to be storing the fault condition and only printing YES or NO once at the end.
I'd suggest fixing that as a start and see what the online judge comes back with.
This all ignores the fact that it's actually rather difficult to debug code unless you can reproduce the problem. If you can't get the data set from the online contest, it may be worth generating your own (large) one to see if you can get you code to fail.
Once you have a repeatable failure, debugging becomes massively easier.
Although it's unlikely, you may (as mch points out in a comment) be running afoul of limited memory. I consider this unlikely as your own comments indicate only 5meg of space is being used at the end, which is not onerous. However, if that is the case, it's probably due to the fact that every single integer has the overhead of a pointer carried along with it.
If you wanted to investigate that avenue, you could slightly adjust the structures as follows (getting rid of the unnecessary counter as well):
#define ITEMS_PER_NODE 1000
typedef struct node {
Item item[ITEMS_PER_NODE]; // array of items.
int startIndex; // start index (one to pop from).
int nextIndex; // next index (one to push at).
struct node *next; // next node.
} Node;
typedef struct queue {
Node *front; // first multi-item node.
Node *rear; // last multi-item node.
} Queue;
The idea is to store many items per node so that the overhead of the next pointer is greatly reduced (one pointer per thousand items rather than one per item).
The code for queue manipulation would then become slightly more complex but still understandable. First off, a helper function for creating a new node, ready for adding data to:
// Helper to allocate a new node and prep it for appending.
// Returns node or NULL (and prints error) if out of memory.
Node *GetNewNode(void) {
Node *pnode = malloc (sizeof(Node));
if (pnode == NULL)
fputs ("Impossible to allocate memory", stderr);
else
pnode->startIndex = pnode->nextIndex = 0;
return pnode;
}
Next, the mostly unchanged queue initialisation:
void InitializeQueue (Queue *pq) {
pq->front = pq->rear = NULL;
}
The pushback is slightly more complex in that it first adds a new multi-item node if the queue is empty or current last node has reached the end. Whether that happens or not, an item is added to the final node:
bool PushBack (Queue *pq, Item item) {
// Default to adding to rear node (assuming space for now).
Node *pnode = pq->rear;
// Make sure queue has space at end for new item.
if (pq->front == NULL) {
// Handle empty queue first, add single node.
if ((pnode = GetNewNode()) == NULL)
return false;
pq->front = pq->rear = pnode;
} else if (pq->rear->nextItem == ITEMS_PER_NODE) {
// Handle new node needed in non-empty queue, add to rear of queue.
if ((pnode = GetNewNode()) == NULL)
return false;
pq->rear->next = pnode;
pq->rear = pnode;
}
// Guaranteed space in (possibly new) rear node now, just add item.
pq->rear->item[pq->rear->nextIndex++] = item;
}
Popping is also a bit more complex - it gets the value to return then deletes the first node if it's now exhausted. That may also entail clearing the queue if the node it deletes was the only one:
int PopFront (Queue * pq) {
// Capture empty queue.
if (pq->first == NULL)
return -1;
// Get value to pop.
Node *currFront = pq->front;
int valuePopped = currFront->item[currFront->startIndex++];
// Detect current node now empty, delete it.
if (currFront->startItem == currFront->endIndex) {
// Detect last node in queue, just free and empty entire queue.
if (currFront == pq->rear) {
free (currFront);
pq->front = pq->rear = NULL;
} else {
// Otherwise remove front node, leaving others.
pq->front = currFront->next;
free (currFront);
}
}
// Regardless of queue manipulation, return popped value.
return valuePopped;
}
Emptying the queue is largely unchanged other than the fact we clear nodes rather than items:
void EmptyQueue (Queue * pq) {
// Can empty node at a time rather than item at a time.
while (pq->front != NULL) {
Node *currentFront = pq->front;
pq->front = pq->front->next;
free (currentFront);
}
}
I think is better to use a more simple approach like that in the code I post here.
The code in the following lines doesn't match the input/output required by the contest, but contains a functional and simple approach to solve the problem: A simple stack manager! (if I correctly understood).
#include <stdio.h>
#include <malloc.h>
int * stack;
int * base;
int cnt;
/* To emulate input file */
struct stFile {
int n;
struct stCmd {
int a;
int b;
} cmd[200]; // 200 is an arbitrary value.
} fdata = {
20,
{
{2,0},
{2,0},
{2,0},
{3,35},
{2,0},
{3,4},
{2,0},
{2,0},
{2,0},
{3,12},
{3,15},
{3,8},{3,18},
{2,0},
{2,0},
{3,111},
{2,0},
{2,0},
{2,0},
{2,0},
{3,8},{3,18},{3,8},{3,18},{3,8},{3,18},{3,8},{3,18},{3,8},{3,18},
{3,11},{3,13},{3,11},{3,11},{3,11},{3,11},{3,11},{3,11},
{3,11},{3,13},{3,11},{3,11},{3,11},{3,11},{3,11},{3,11},
{2,0},
{2,0},
{2,0},
{2,0},
{2,0},
{2,0},
{2,0},
{2,0},
{0,0}
}
};
int push(int item)
{
if (cnt) {
*stack = item;
stack++;
cnt--;
return 0;
} else {
return 1;
}
}
int pop(int *empty)
{
if (stack!=base) {
stack--;
cnt++;
if (empty)
*empty = 0;
} else {
if (empty)
*empty = 1;
}
return *stack;
}
int main(void)
{
int i=0,e=0;
cnt = fdata.n;
base = stack = malloc(cnt*sizeof(int));
if (!base) {
puts("Not enough memory!");
return 1;
}
while(fdata.cmd[i].a!=0) {
switch(fdata.cmd[i].a) {
case 2:
printf("popping ...: %d ",pop(&e));
printf("empty: %d\n",e);
break;
case 3:
e = push(fdata.cmd[i].b);
printf("pushing ...: %d %s\n",fdata.cmd[i].b,(e)?"not pushed":"pushed");
break;
default:
break;
};
i++;
}
if (base)
free(base);
return 0;
}

How to set size of circular queue

I am trying to implement a generic circular buffer (queue) in C. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h>
CIRCLEQ_HEAD(circleq, entry) head;
struct circleq *headp; /* Circular queue head. */
struct entry {
CIRCLEQ_ENTRY(entry) entries; /* Circular queue. */
int number;
};
int main()
{
CIRCLEQ_INIT(&head);
// Add some numbers to the queue
int i;
for (i = 0; i < 10; i++) {
struct entry* n = malloc(sizeof(struct entry));
n->number = i;
CIRCLEQ_INSERT_HEAD(&head, n, entries);
printf("Added %d to the queue\n", n->number);
}
// Remove a number from the queue
struct entry *n;
n = CIRCLEQ_FIRST(&head);
CIRCLEQ_REMOVE(&head, head.cqh_first, entries);
printf("Removed %d from the queue\n", n->number);
return 0;
}
Which produces the following output:
Added 0 to the queue
Added 1 to the queue
Added 2 to the queue
Added 3 to the queue
Added 4 to the queue
Added 5 to the queue
Added 6 to the queue
Added 7 to the queue
Added 8 to the queue
Added 9 to the queue
Removed 9 from the queue
I am not very experienced with C, and my questions are:
How can I set a limit on the queue, so, for example, only 5 numbers
can fit into the buffer at a time? If another item is attempted to
be added after this, I should be able to detect it and do something
about it (ignore it, wait, exit program, etc.).
It seems my code removed the last item from the buffer - how can I
make it remove items from the tail (number 0 instead of 9, in my
example)?
I've read through http://linux.die.net/man/3/queue, but it doesn't seem clear how I can accomplish the above two things.
If you look at the description of circular-buffer, one of the main benefits of this kind of buffer is that it uses a single fixed allocation, whereas yours is basically just a circularly linked list. The fixed size used at creation specifies the limit of the number of elements the ring buffer can hold.
If you have a properly implemented circular buffer, removing an item involves simply advancing the tail pointer, wrapping back to the front if necessary.
An example struct representing a circular buffer might look like the following:
struct circleq
{
int* buf;
int head;
int tail;
int size;
};
void init(struct circleq* q, int size)
{
q->buf = malloc(sizeof(int) * size);
q->head = 0;
q->tail = size - 1;
q->size = size;
}
void insert(struct circleq* q, int val)
{
if(q->head == q->tail) { } // queue full, error
else
{
q->buf[q->head] = val;
q->head = (q->head + 1) % q->size;
}
}
int remove(struct circleq* q)
{
if((q->tail + 1) % q->size == q->head) { return 0; } // queue empty, error
else
{
int val = q->buf[q->tail];
q->tail = (q->tail + 1) % q->size;
return val;
}
}
void destroy(struct circleq* q)
{
free(q->buf);
}

Bubble Sort method not working with Linked List in C

I am trying to implement a bubble sort method into a linked list data structure, but when running it through a test harness, it doesn't do anything. Any suggestions?
Here is my source code:
void set_sort (set_t * the_set)
{
assert (the_set);
set_node_t *current;
current = the_set->head;
int sorted = 1;
int x;
for (x = 0; x < the_set->set_size; x++) {
//we dont do it if this is the last value
if (x + 1 == the_set->set_size) {
continue;
}
if (current->data > current->next->data) {
sorted = 0;
int temp = &current->next->data;
current->next->data = current->data;
current->data = temp;
}
current = current->next;
}
if (!sorted) {
set_sort (the_set);
}
}
EDIT WITH HEADER FILE
#ifndef _set_h_
#define _set_h_
#include <stdbool.h>
#include "common.h"
/* Create a basic singly-linked list.*/
/*This code has been sourced from Mike Mcallistar, Assignment 5 Solutions*/
typedef struct _set_node_t {
test_type_t *data;
struct _set_node_t *next;
struct _set_node_t *below;
} set_node_t;
/* the set itself keeps track of the head and the tail of the linked list */
typedef struct {
int set_size;
bool ready;
set_node_t *head;
set_node_t *tail;
int set_level;
} set_t;
bool set_init(set_t *the_set);
void set_destroy(set_t *the_set);
bool set_add(set_t *the_set, test_type_t *item_to_add);
bool set_delete(set_t *the_set, test_type_t *item_to_remove);
bool set_find( set_t *the_set, test_type_t *item_to_find);
void set_sort(set_t *the_set);
void set_enumerate(set_t *the_set);
#endif
Something seems very wrong with this.
int temp = &current->next->data; // Assignes a pointer into temp
current->next->data = current->data; // Copies current into next
current->data = temp; // Copies the pointer into data
This is unlikely to do nothing. It's quite likely to corrupt your data.
Could it be as simple as to change the first of these lines to:
int temp = current->next->data;
Edit
Cleaning up your code a little I get to this:
void set_sort(set_t *the_set)
{
assert(the_set);
int sorted;
int x;
do {
set_node_t *current = the_set->head;
sorted = 1;
for( x = 0; x < the_set->set_size - 1; x++){
if(current->data > current->next->data){
sorted = 0;
int temp = current->next->data;
current->next->data = current->data;
current->data = temp;
}
current = current->next;
}
}
while (!sorted);
}
Removing the use of unnecessary recursion removes the risk of causing a stack overflow. Removing the continue makes the code marginally quicker (I believe). Removing the spurious use of the pointer should fix your code.
If your code isn't fixed by this then then you will need to post the definition of set_node_t, its possible your comparison is not working (if (current->data > current->next->data)).
Edit 2
As comments and updated question has now pointed out you need to perform your comparison on the data itself and not the pointer to the data.
if(*(current->data) > *(current->next->data)){

Linked list in C - first node data incorrect and can't figure it out

I have a multithreaded C program, where one thread creates random times and numbers, and stores them in a sorted linked list, and the second thread compares the the time in the first node to the current system time and deletes the node whenever the times are equal. However, 0 0 gets added to the linked list first, and I can't find where. It's not being added in the insert function as far as I can tell. Any help would be greatly appreciated. Here is the relevant code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
pthread_mutex_t count_mutex;
/* Link list node */
struct node
{
int roomNo;
time_t time;
struct node* next;
};
void printList(struct node *node)
{
while(node!=NULL)
{
printf("%d ", node->roomNo);
printf("%d\n ", node->time);
node = node->next;
}
}
/* Function to insert a node at the beginging of the linked list */
void insert(struct node** head_ref, int new_room, time_t new_time)
{
/* allocate node */
struct node* new_node =
(struct node*) malloc(sizeof(struct node));
/* put in the data */
new_node->roomNo = new_room;
new_node->time = new_time;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
MergeSort(&(*head_ref));
}
/* sorts the linked list by changing next pointers (not data) */
void MergeSort(struct node** headRef)
{
struct node* head = *headRef;
struct node* a;
struct node* b;
/* Base case -- length 0 or 1 */
if ((head == NULL) || (head->next == NULL))
{
return;
}
/* Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);
/* Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);
/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}
struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;
/* Base cases */
if (a == NULL)
return(b);
else if (b==NULL)
return(a);
/* Pick either a or b, and recur */
if (a->time <= b->time)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return(result);
}
void FrontBackSplit(struct node* source,
struct node** frontRef, struct node** backRef)
{
struct node* fast;
struct node* slow;
if (source==NULL || source->next==NULL)
{
/* length < 2 cases */
*frontRef = source;
*backRef = NULL;
}
else
{
slow = source;
fast = source->next;
/* Advance 'fast' two nodes, and advance 'slow' one node */
while (fast != NULL)
{
fast = fast->next;
if (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}
/* 'slow' is before the midpoint in the list, so split it in two
at that point. */
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
}
void * addThread(void *n)
{
struct node *llnode = n;
int i;
for(i = 0; i <4; i++)
{
pthread_mutex_lock(&count_mutex);
printf("Adding node.\n");
insert(&llnode, getRandRoom(), getRandTime());
sleep(1);
printf("the list is...\n");
printList(llnode);
pthread_mutex_unlock(&count_mutex);
}
}
struct node* head;
int main()
{
signal(SIGINT, ctrlc_catch);
pthread_t addWakeup, makeWakeup;
pthread_create(&addWakeup, NULL, addThread, (void*)&head);
pthread_create(&makeWakeup, NULL, wakeThread, (void*)&head);
pthread_join(addWakeup, NULL);
pthread_join(makeWakeup, NULL);
return 0;
}
Example output is:
Adding node.
the list is...
0 0
4000 1323882918
Adding node.
the list is...
0 0
809 1323882890
4000 1323882918
Adding node.
the list is...
0 0
809 1323882890
7617 1323882908
4000 1323882918
Adding node.
the list is...
0 0
809 1323882890
7617 1323882908
4000 1323882918
4426 1323882926
You problem is most likely due to passing address of head (i.e. ~struct node**) instead of head(i.e. struct node*) to the thread function where void * is typecast to struct node*. Change this call pthread_create(&addWakeup, NULL, addThread, (void*)&head); to pthread_create(&addWakeup, NULL, addThread, (void*)head); & next call also on similar lines. Unfortunately you were not seeing a crash in the current case. On my system I observed that initializing head to NULL was crashing the program. Similar suggestion has already been provided by #wildplasser. Try this change out and check the list printed.
Hope this helps!
Your function addthread creates a local copy llnode of its argument n, and uses a pointer to llnode to call insert(). Insert can alter llnode, but that change will only affect the local copy.
You should change addThread to take an argument of type struct node**, instead of struct node*.
While it may exist in code not shown, the code may need a call to pthread_mutex_init to initialize the mutex. It is possible that the contents of the variable count_mutex are initialized "by chance" to values that will actually work, but it would not be good to rely on that.

Resources