C语言 根据客户端类型排队进出



排队和排队 到客户端类型 问题

根据之前的实现,修改 LIST 命令,使其首先打印 VIP 客户端 然后按队列号升序排列普通客户端。与 OUT 命令相同,VIP 将排队 首先是普通客户。

输入

IN 1000001 Ordinary
IN 2000003 VIP
IN 2000009 VIP
OUT
OUT
OUT
OUT
IN 1000007 Ordinary
IN 2000005 VIP
LIST
OUT
QUIT

输出

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!

我尝试制作两个队列,一个用于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 %dn",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 %sn",temp->record,temp->CardNum,temp->CustomerType);
temp = temp->next;
}
}
}

你在这里有几个问题。

1. 全局变量

我不明白你的全局变量的语义。什么是position和 什么是length?我的意思是,您为每个Enqueue调用更新这些值 不管队列如何。你从来没有真正使用过position(忽略printf,我认为这是调试代码),所以没有意义。

length相似.这是什么长度?您在 中使用lengthNode->record,但同样,每次排队时length都会更新 不管队列如何的东西。

对我来说,这些值取决于队列,因此它们应该在结构中:

typedef struct queue
{
Node* front;
Node* rear;
int position;
int length;
} Queue;

这只是一个观察,这不是导致问题的原因。

2. 全局变量(再次)

为什么要将q1q2声明为全局变量?至少在你的例子中 它们没有理由是全球性的。我会把它们放在main函数中。

我看到的唯一原因是全局变量初始化为 0,因此您 以后不必初始化它们,但我认为这是一个坏习惯。因为 如果您以后必须更改代码,请将全局变量放回 函数,您可能会忘记初始化,然后您有未定义 行为。最好在声明新队列时初始化一个新队列。

int init_queue(Queue* queue)
{
if(queue == NULL)
return 0;
memset(queue, 0, sizeof *queue);
return 1;
}

当您需要一个新队列时:

Queue q;
init_queue(&q);

3. 忽略编译器警告/错误(混合类型)

Node->CardNum被声明为int而您这样做

strcpy(temp->CardNum, x);
strcpy(temp->CardNum, y);

我的编译器说:

a.c:81:12: warning: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
strcpy(temp->CardNum,y);
^~~~

我认为第二行是你的错字,你可能想做strcpy(temp->CustomerType, y);是正确的。

但:

  1. 您正在尝试将字符串复制到int中,这不起作用。不要混合 类型。

  2. 真正发生的事情是strcpy开始在你 很可能没有读/写权限,如果幸运的话temp->CarnNum的整数值与地址相同,您可以在其中 写入,那么你正在覆盖你不应该覆盖的内存。

一个简单的修复将是temp->CardNum = atoi(y);或更好的,你仍然阅读 价值:

int cardNum;
scanf("%d", &cardNum);

并将该cardNum整数传递给Enqueue.你显然需要改变 排队函数的签名:

void Enqueue(Queue *q, char *x, int y);

但在这种情况下,我认为最好的策略是读取字符串。当然,你的卡 数字似乎是整数,但管理层可能会稍后更改它并添加字母 卡号,或者他们想要填充 0。出于这个原因,治疗 字符串形式的卡号似乎是一个更好的选择。你只需要 更改结构。您还需要更改List()中的printf行。

typedef struct Node
{
int record;
char CardNum[20];
char CustomerType[20];
struct Node* next;
} Node;

进行我在这里解释的小修复,我能够编译您的代码并运行 它包含您提供的输入。这就是我得到的:

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

我有几点建议:

  1. 除非 100% 必要,否则不要使用全局变量

  2. 当声明一个将字符串作为参数的函数时,以及当 函数不会操作字符串,最好声明 他们作为const char*.这样就可以立即清楚地知道您的函数是 不打算更改字符串,用户还可以传递字符串文字。

    void Enqueue(Queue *q, const char *x, const char *y);
    
  3. 为您的变量使用更好的名称,更容易遵循代码 大家:

    void Enqueue(Queue *q, const char *cardNumber, const char *customer);
    
  4. 从用户读取时,最好检查缓冲区是否具有 在编写它们之前有足够的空间。例如,如果用户输入很长的 卡号,做strcpy时可能会溢出缓冲区。出于这个原因 最好使用strncpy,但请注意strncpy可能不会 如果缓冲区中没有剩余空间,则写入''终止字节。

  5. 即使在像您这样的"琐碎"程序中,也请释放您的内存 与malloc& Co. 一起分配 编写一个执行此操作的free_queue函数 作业并在退出程序之前使用它。

  6. 数组在传递给函数或赋值它们时衰减为指针 到指针。

    int array[] = { 1, 3, 5, 7, 9 };
    int *ptr1 = array;
    int *ptr2 = &array[0];
    

    两者都是等效的,您不需要ptrcardptrclient变量。 这将可以:

    scanf("%s", card);
    scanf("%s", client);
    Enqueue(&q1, card, client);
    
  7. 您应该检查scanf的返回值。它返回令牌的数量 匹配。当用户输入您不输入的内容时,您可以使用它进行控制 期望。在这种情况下,您可以清理缓冲区并忽略该行。

    while(1)
    {
    if(scanf("%s", card) != 1)
    {
    clean_stdin();
    printf("Unexpected entry: repeat commandn");
    continue; //
    }
    if(scanf("%s", client) != 1)
    {
    clean_stdin();
    printf("Unexpected entry: repeat commandn");
    continue; //
    }
    Enqueue(&q1, card, client);
    }
    

    clean_stdin的可能实现:

    void clean_stdin()
    {
    int c;
    while( (c = getchar()) != 'n' && c != EOF));
    }
    

最新更新