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.
根据之前的实现,修改LIST命令,这样它就会以队列号的方式将VIP客户端按升序打印出来。和OUT命令一样,VIP会先排队,然后是普通客户。
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.
我试着做了两个队列,一个是VIP队列,一个是普通的,它的进站功能有错误,它显示了卡号和客户类型的奇怪数字,但是程序运行…除了两种队列方法之外,任何其他解决方案都是受欢迎的。
#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 个解决方案
#1
0
You have a few problems here.
这里有一些问题。
1. Global variables
1。全局变量
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.
我不理解全局变量的语义。什么是位置,什么是长度?我的意思是,无论队列是什么,都要为每个队列调用更新这些值。您从来没有真正使用过position(忽略printf,我将其视为调试代码),因此没有必要这样做。
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.
类似的长度。它的长度是多少?您可以在Node->记录中使用length,但是同样,无论队列是什么,每次都要更新length。
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)
2。全局变量(再一次)
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.
为什么说q1和q2是全局变量?至少在你的例子中,他们没有理由是全球化的。我把它们放在主函数中。
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.
我看到这种情况的唯一原因是全局变量初始化为0,所以以后不需要初始化它们,但我认为这是一个坏习惯。因为如果以后需要修改代码并将全局变量放回函数中,您可能会忘记初始化,然后就会有未定义的行为。最好在声明一个队列时初始化一个新的队列。
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)
3所示。忽略编译器警告/错误(混合类型)
Node->CardNum
is declared as int
and you do
节点->CardNum被声明为int,您可以。
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.
我认为第二行是你的一个错别字,你可能想做strcpy(temp->CustomerType, y);这是正确的。
But:
但是:
-
You are trying to copy a string into an
int
, that doesn't work. Don't mix types.您正在尝试将一个字符串复制到一个int型,这是行不通的。不要混合类型。
-
What really happens is that
strcpy
begins writing in location where you most probably don't have read/write permission, if by some lucky coincidence the integer value oftemp->CarnNum
is the same as an address where you can write, then you are overwriting memory that you shouldn't.真正发生的情况是,strcpy开始在最可能没有读/写权限的位置进行写入,如果碰巧temp->CarnNum的整数值与可以写入的地址相同,那么就覆盖了不应该写入的内存。
A simple fix would be temp->CardNum = atoi(y);
or better still you read the value:
一个简单的修复方法是temp->CardNum = atoi(y);或者你最好还是读一下它的值:
int cardNum;
scanf("%d", &cardNum);
and pass that cardNum
integer to Enqueue
. You would obviously need to change the signature of the enqueue function:
并将cardNum整数传递给队列。显然需要更改enqueue函数的签名:
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()
.
但在这种情况下,我认为最好的策略是读取字符串。当然,您的卡号看起来是整数,但是管理人员可能会在稍后更改,并将字母添加到卡号中,否则他们会希望填充0。由于这个原因,将卡号作为字符串处理似乎是一个更好的选择。你只需要改变结构。您还需要更改List()中的printf行。
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
除非100%必要,否则不要使用全局变量
-
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.在声明以字符串为参数的函数时,当该函数不打算操纵字符串时,最好将它们声明为const char*。通过这种方式,很明显你的函数不会改变字符串,用户也可以传递一个字符串文字。
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 usestrncpy
, but be aware thatstrncpy
might not write the'\0'
-terminating byte if there is no space left in the buffer.从用户读取数据时,最好检查缓冲区是否有足够的空间。例如,如果用户输入一个很长的卡号,在执行strcpy时可能会溢出缓冲区。出于这个原因,最好使用strncpy,但是要注意,如果缓冲区中没有剩余空间,strncpy可能不会写入'\0'-terminating byte。
-
Even in a "trivial" program like yours, please free the memory you've allocated with
malloc
& Co. Write afree_queue
function that does this job and use it before exiting the program.即使在像您这样的“琐碎”程序中,也请释放您与malloc & Co分配的内存。
-
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
ptrcard
andptrclient
variables. This will do:两者是等价的,您不需要ptrcard和ptrclient变量。这将会做的事:
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.您应该检查scanf的返回值。它返回匹配的令牌数量。当用户输入一些您不希望的东西时,您可以使用它进行控制。在这种情况下,您可以清理缓冲区并忽略该行。
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
:clean_stdin的一个可能实现:
void clean_stdin() { int c; while( (c = getchar()) != '\n' && c != EOF)); }
#1
0
You have a few problems here.
这里有一些问题。
1. Global variables
1。全局变量
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.
我不理解全局变量的语义。什么是位置,什么是长度?我的意思是,无论队列是什么,都要为每个队列调用更新这些值。您从来没有真正使用过position(忽略printf,我将其视为调试代码),因此没有必要这样做。
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.
类似的长度。它的长度是多少?您可以在Node->记录中使用length,但是同样,无论队列是什么,每次都要更新length。
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)
2。全局变量(再一次)
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.
为什么说q1和q2是全局变量?至少在你的例子中,他们没有理由是全球化的。我把它们放在主函数中。
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.
我看到这种情况的唯一原因是全局变量初始化为0,所以以后不需要初始化它们,但我认为这是一个坏习惯。因为如果以后需要修改代码并将全局变量放回函数中,您可能会忘记初始化,然后就会有未定义的行为。最好在声明一个队列时初始化一个新的队列。
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)
3所示。忽略编译器警告/错误(混合类型)
Node->CardNum
is declared as int
and you do
节点->CardNum被声明为int,您可以。
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.
我认为第二行是你的一个错别字,你可能想做strcpy(temp->CustomerType, y);这是正确的。
But:
但是:
-
You are trying to copy a string into an
int
, that doesn't work. Don't mix types.您正在尝试将一个字符串复制到一个int型,这是行不通的。不要混合类型。
-
What really happens is that
strcpy
begins writing in location where you most probably don't have read/write permission, if by some lucky coincidence the integer value oftemp->CarnNum
is the same as an address where you can write, then you are overwriting memory that you shouldn't.真正发生的情况是,strcpy开始在最可能没有读/写权限的位置进行写入,如果碰巧temp->CarnNum的整数值与可以写入的地址相同,那么就覆盖了不应该写入的内存。
A simple fix would be temp->CardNum = atoi(y);
or better still you read the value:
一个简单的修复方法是temp->CardNum = atoi(y);或者你最好还是读一下它的值:
int cardNum;
scanf("%d", &cardNum);
and pass that cardNum
integer to Enqueue
. You would obviously need to change the signature of the enqueue function:
并将cardNum整数传递给队列。显然需要更改enqueue函数的签名:
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()
.
但在这种情况下,我认为最好的策略是读取字符串。当然,您的卡号看起来是整数,但是管理人员可能会在稍后更改,并将字母添加到卡号中,否则他们会希望填充0。由于这个原因,将卡号作为字符串处理似乎是一个更好的选择。你只需要改变结构。您还需要更改List()中的printf行。
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
除非100%必要,否则不要使用全局变量
-
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.在声明以字符串为参数的函数时,当该函数不打算操纵字符串时,最好将它们声明为const char*。通过这种方式,很明显你的函数不会改变字符串,用户也可以传递一个字符串文字。
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 usestrncpy
, but be aware thatstrncpy
might not write the'\0'
-terminating byte if there is no space left in the buffer.从用户读取数据时,最好检查缓冲区是否有足够的空间。例如,如果用户输入一个很长的卡号,在执行strcpy时可能会溢出缓冲区。出于这个原因,最好使用strncpy,但是要注意,如果缓冲区中没有剩余空间,strncpy可能不会写入'\0'-terminating byte。
-
Even in a "trivial" program like yours, please free the memory you've allocated with
malloc
& Co. Write afree_queue
function that does this job and use it before exiting the program.即使在像您这样的“琐碎”程序中,也请释放您与malloc & Co分配的内存。
-
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
ptrcard
andptrclient
variables. This will do:两者是等价的,您不需要ptrcard和ptrclient变量。这将会做的事:
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.您应该检查scanf的返回值。它返回匹配的令牌数量。当用户输入一些您不希望的东西时,您可以使用它进行控制。在这种情况下,您可以清理缓冲区并忽略该行。
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
:clean_stdin的一个可能实现:
void clean_stdin() { int c; while( (c = getchar()) != '\n' && c != EOF)); }