问题
Queue in and out according to clients’type Question
Based on previous implementation, modify the LIST command, so that it will print VIP clients first then ordinary clients in ascending order by queue number. Same as OUT command, VIP will be queued out first then ordinary clients.
Input
IN 1000001 Ordinary
IN 2000003 VIP
IN 2000009 VIP
OUT
OUT
OUT
OUT
IN 1000007 Ordinary
IN 2000005 VIP
LIST
OUT
QUIT
Output
IN:1 1000001 Ordinary 0
IN:2 2000003 VIP 0
IN:3 2000009 VIP 1
OUT:2 2000003 VIP
OUT:3 2000009 VIP
OUT:1 1000001 Ordinary
FAILED:
IN:4 1000007 Ordinary 0
IN:5 2000005 VIP 0
LIST:
5 2000005 VIP
4 1000007 Ordinary
OUT:5 2000005 VIP
GOOD BYE!
I have tried to make two queues one for VIP and one for Ordinary it has error in the Enqueue function it shows weird figures for the card number and client type but the program runs ..........any other solution is welcomed other than the two queue approach.
#include <stdio.h>
#include <malloc.h>
#include<string.h>
int position=0;
int length=1;
typedef struct Node
{
int record;
int CardNum;
char CustomerType[20];
struct Node* next;
}Node;
typedef struct queue
{
Node* front;
Node* rear;
}Queue;
Queue q1,q2;
void Enqueue(Queue *q, char *x, char *y);
void List(Queue *q);
int main()
{
char command[10];
char card[10],*ptrcard;
char client[10],*ptrclient;
while(1)
{
scanf("%s",command);
if(strcmp(command,"IN") == 0)
{
printf("IN:");
scanf("%s",card);
ptrcard=&card[0];
scanf("%s",client);
ptrclient=&client[0];
if(strcmp(client,"VIP")==0)
{
Enqueue(&q1,card,client);
}
else if(strcmp(client,"Ordinary")==0)
{
Enqueue(&q2,card,client);
}
}
else if(strcmp(command,"LIST") == 0)
{
printf("LIST:\n");
List(&q1);
List(&q2);
}
else if(strcmp(command,"QUIT") ==0)
{
printf("GOOD BYE!\n");
break;
}
}
return 0;
}
void Enqueue(Queue *q, char *x, char *y)
{
Node* temp = (Node*)malloc(sizeof(Node));
strcpy(temp->CardNum,x);
strcpy(temp->CardNum,y);
temp->record=length;
temp->next=NULL;
if(q->front == NULL && q->rear == NULL)
{
q->front=q->rear=temp;
}
else
{
q->rear->next=temp;
q->rear=temp;
}
printf("%d %d %s %d\n",temp->record,temp->CardNum,temp->CustomerType,position);
position++;
length++;
}
void List(Queue *q)
{
Node *temp;
if(q->front != NULL)
{
temp = q->front;
while(temp != NULL)
{
printf("%d %d %s\n",temp->record,temp->CardNum,temp->CustomerType);
temp = temp->next;
}
}
}
回答1:
You have a few problems here.
1. Global variables
I don't understand the semantics of your global variables. What is position and
what is length? I mean, you update these values for every Enqueue call
regardless of the queue. You never really use position at all (ignoring the
printf, which I see as debugging code), so there is no point to that.
Similar for length. It is the length of what? You use length in
Node->record, but again, length gets updated every time you enqueue
something regardless of the queue.
For me these values are dependent on the queues, so they should be in struct:
typedef struct queue
{
Node* front;
Node* rear;
int position;
int length;
} Queue;
This is just an observation, this is not what is causing the problems.
2. Global variables (again)
Why do you declare q1 and q2 as global variables? At least in your example
there is no reason for them to be global. I'd put them in the main function.
The only reason I see for that would be that global variables are initialized with 0 hence you don't have to initialize them later on, but I consider that a bad habit. Because if you later have to change your code an put the global variables back into a function, you may forget about the initialization and then your have undefined behaviour. It's better to initialize a new queue when you declare one.
int init_queue(Queue* queue)
{
if(queue == NULL)
return 0;
memset(queue, 0, sizeof *queue);
return 1;
}
And when you want a new queue:
Queue q;
init_queue(&q);
3. Ignoring the compiler warnings/errors (mixing types)
Node->CardNum is declared as int and you do
strcpy(temp->CardNum, x);
strcpy(temp->CardNum, y);
My compiler says:
a.c:81:12: warning: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
strcpy(temp->CardNum,y);
^~~~
I think the second line is a typo of yours, you may have wanted to do
strcpy(temp->CustomerType, y); which is correct.
But:
You are trying to copy a string into an
int, that doesn't work. Don't mix types.What really happens is that
strcpybegins writing in location where you most probably don't have read/write permission, if by some lucky coincidence the integer value oftemp->CarnNumis the same as an address where you can write, then you are overwriting memory that you shouldn't.
A simple fix would be temp->CardNum = atoi(y); or better still you read the
value:
int cardNum;
scanf("%d", &cardNum);
and pass that cardNum integer to Enqueue. You would obviously need to change
the signature of the enqueue function:
void Enqueue(Queue *q, char *x, int y);
But in this case I think the best strategy is to read strings. Sure, your card
numbers seem to be integers, but management may change that later and add letters to
the card numbers or they would want to have padding 0s. For this reason treating
the card number as a string seems to be a better option. You would only need to
change the structure. You would also need to change the printf line in List().
typedef struct Node
{
int record;
char CardNum[20];
char CustomerType[20];
struct Node* next;
} Node;
Making the small fixes I explained here, I was able to compile your code and run it with the input you've provided. That's what I've got:
IN:1 1000001 Ordinary 0
IN:2 2000003 VIP 1
IN:3 2000009 VIP 2
IN:4 1000007 Ordinary 3
IN:5 2000005 VIP 4
LIST:
2 2000003 VIP
3 2000009 VIP
5 2000005 VIP
1 1000001 Ordinary
4 1000007 Ordinary
I have a few suggestions:
Unless 100% necessary, don't use global variables
When declaring a function that takes strings as arguments, and when this function is not going to manipulate the strings, it's best to declare them as
const char*. This way it is clear right away that your function is not going to alter the strings, the user may also pass a string literal.void Enqueue(Queue *q, const char *x, const char *y);Use better names for your variables, it's easier to follow code for everybody:
void Enqueue(Queue *q, const char *cardNumber, const char *customer);When reading from the user, it's always better to check that you buffers have enough space before writing them. For example if the user enters a very long card number, it may overflow the buffer when doing
strcpy. For this reason it's better to use strncpy, but be aware thatstrncpymight not write the'\0'-terminating byte if there is no space left in the buffer.Even in a "trivial" program like yours, please free the memory you've allocated with
malloc& Co. Write afree_queuefunction that does this job and use it before exiting the program.Arrays decay into pointers when passing them to functions or assigning them to pointers.
int array[] = { 1, 3, 5, 7, 9 }; int *ptr1 = array; int *ptr2 = &array[0];Both are equivalent, you don't need the
ptrcardandptrclientvariables. This will do:scanf("%s", card); scanf("%s", client); Enqueue(&q1, card, client);You should check the return value of
scanf. It returns the number of tokens matched. You can control with it when a user inputs something you don't expect. In this case you could clean the buffer and ignore the line.while(1) { if(scanf("%s", card) != 1) { clean_stdin(); printf("Unexpected entry: repeat command\n"); continue; // } if(scanf("%s", client) != 1) { clean_stdin(); printf("Unexpected entry: repeat command\n"); continue; // } Enqueue(&q1, card, client); }A possible implementation for
clean_stdin:void clean_stdin() { int c; while( (c = getchar()) != '\n' && c != EOF)); }
来源:https://stackoverflow.com/questions/48357275/queue-in-and-out-according-to-clients-type