如何按字母顺序对多个“人”字符串进行排序,而不会将它们移动到不同的“座位”?

How do I alphabetically sort multiple 'people' strings without them moving to different 'seats'?

提问人:stephanp 提问时间:11/10/2023 最后编辑:Allan Windstephanp 更新时间:11/10/2023 访问量:60

问:

我正在用 C 语言编写一个座位预订程序,其中包含一个选项,其中分配给其座位的乘员可以按字母顺序排序。当我选择对它们进行排序的选项时,该函数确实按字母顺序对姓氏和名字进行排序,但是,在此过程中,会获取姓氏和名字参数并将它们移动到不同的席位。

我目前正在使用 qsort 函数对存储在名为“SEAT”的结构中的名称进行排序,该结构包含名字和姓氏字符以及席位 ID 和分配的整数。

SEAT结构:

typedef struct seat { // struct used to hold all SEAT variables

    int seatID;

    int occupied;

    char lastname[MAXNAME];

    char firstname[MAXNAME];

} SEAT;

qsort 函数位于名为“alphasortSeat”的较大函数中,并使用另外两个名为“lastnameCompare”和“firstnameCompare”的函数作为其 CompareFuncion 参数。

我希望这个函数在调用时按名字或姓氏按字母顺序对姓名进行排序,而不会将数据移动到看似随机的座位分配中。

例如: 1号座位分配给:鲍勃·詹金斯,2号座位分配给:习近平。

调用并执行函数后,名称按字母顺序排序,但现在会打印:

座位 1 分配给 Bob Jenkins

7号座位分配给习

(实际上,这两个名字现在已分别移至11号座位和12号座位。

这是我目前使用的代码:

main.c:

scanf_s(" %c", &choice[0], MAXCHOICELEN);

switch (choice[0]) {

//.....

case 'c':
    alphasortSeat(seats, MAXSEAT); // sorting the occupants by alphabetical order

    break;

//.....

library.c:

//.....

功能比较:

int lastnameCompare(const void* a, const void* b) { // function that compares lastname(s) in order to properly sort them later on alphabetically 

    const SEAT* seatA = (const SEAT*)a;

    const SEAT* seatB = (const SEAT*)b;

    return strcmp(seatA->lastname, seatB->lastname);

}

int firstnameCompare(const void* a, const void* b) { // function that compares firstname(s) in order to properly sort them later on alphabetically 

    const SEAT* seatA = (const SEAT*)a;

    const SEAT* seatB = (const SEAT*)b;

    return strcmp(seatA->firstname, seatB->firstname);

}

按字母顺序排序功能:

void alphasortSeat(SEAT seats[], int seatNum) { // alphabetically sort names function

    char alphaChoice;

    printf("Sort by first or last name (f or l): ");
    scanf_s(" %c", &alphaChoice, MAXCHOICELEN);

    if (alphaChoice == 'f') {

qsort(seats, seatNum, sizeof(SEAT), firstnameCompare); // qsort functions used to order the letters
                                                               // qsort_s not used, "context" parameter (MAXSEAT) caused warnings (not needed).
    for(int i = 0; i < seatNum; i++){
    
        if (seats[i].occupied) {

printf("\n %s %s is assigned to seat %d.", seats[i].firstname, seats[i].lastname, seats[i].seatID);

            }
        }   
    }
    else if (alphaChoice == 'l') {

        qsort(seats, seatNum, sizeof(SEAT), lastnameCompare);

        for (int i = 0; i < seatNum; i++) {

            if (seats[i].occupied) {

printf("\n %s %s is assigned to seat %d.", seats[i].lastname, seats[i].firstname, seats[i].seatID);

            }
        }
    }
    else {

fprintf(stderr, "\n\nERROR: Invalid character entered.\n\n"); // error statement for invalid character

        return;
    }
}

//.....

library.h:

int lastnameCompare(const void* a, const void* b);

int firstnameCompare(const void* a, const void* b);

void alphasortSeat(SEAT seats[], int seatNum);

我觉得主要问题是我没有正确使用 qsort,或者我的比较函数没有像它们应该的那样完成它们的工作。我只是 C 语言的初学者,我很好奇为什么我的代码会产生如此奇怪的错误。

c 排序 结构 strcmp qsort

评论

2赞 Retired Ninja 11/10/2023
考虑将一个专注于特定问题的最小可重现示例放在一起。对数组中的几个项目进行硬编码,并显示如何对其进行排序,并解释哪些项目无法正常工作。根据你所显示的片段,对数组进行排序时,应保留结构的所有内容。
0赞 Retired Ninja 11/10/2023
下面是一个适用于按名字排序的示例:godbolt.org/z/b365999e6

答:

2赞 Allan Wind 11/10/2023 #1

我无法重现您的问题。由于您是这里的新手,下面将是一个最小的非交互式代码示例,可以轻松为您提供帮助。如果您不需要同时使用 firstname 和 lastname 排序来演示问题,请省略其中一个。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAME 42

typedef struct seat {
    int seatID;
    int occupied;
    char lastname[MAXNAME];
    char firstname[MAXNAME];
} SEAT;

#define genFieldCompare(field) \
    int field ## Compare(const void *a, const void *b) {\
        const SEAT *seatA = a;\
        const SEAT *seatB = b;\
        return strcmp(seatA->field, seatB->field);\
    }
genFieldCompare(firstname);
genFieldCompare(lastname);
#undef genFieldCompare

void printSeat(const SEAT seats[], int seatNum) {
    for(int i = 0; i < seatNum; i++)
        if (seats[i].occupied)
            printf("%s %s is assigned to seat %d.\n", seats[i].firstname, seats[i].lastname, seats[i].seatID);
    printf("\n");
}

int main(void) {
    SEAT seats[] = {
        {2, 1, "AXi", "Jinping"},
        {1, 1, "Jenkins", "Bob"}
    };
    const size_t seatNum = sizeof seats / sizeof *seats;
    qsort(seats, seatNum, sizeof *seats, firstnameCompare);
    printSeat(seats, seatNum);
    qsort(seats, seatNum, sizeof *seats, lastnameCompare);
    printSeat(seats, seatNum);
}

按照惯例,所有大写符号 (SEAT) 都是为符号常量(和枚举值)保留的。如果不需要,只需省略并将其用作符号名称即可。struct seatseattypedef

花哨的宏只是为了使代码更短一些,并确保它们以完全相同的方式实现,而不是两个不同的字段名称。genFieldCompare

输出示例:

Bob Jenkins is assigned to seat 1.
Jinping AXi is assigned to seat 2.

Jinping AXi is assigned to seat 2.
Bob Jenkins is assigned to seat 1.

为了重现您的问题,我希望 Bob 不再被分配座位 1,而类似的 Jingping 不再被分配座位 2。

评论

0赞 stephanp 11/10/2023
谢谢你对我的帮助!我真的很感激。
0赞 Allan Wind 11/10/2023
如果它回答了您的原始问题,请单击复选标记接受它,如果没有,请在评论中告诉我原因,以便我修改它。随意使用我的代码修改您的问题。关键是要得到一个失败的测试用例(我得到了 x,但期望 y)。