繁体   English   中英

C编程:使用两个参数对结构进行排序

[英]C programming: Sorting Structures with two parameters

我正在尝试对姓氏和公司名称进行排序。 用户必须输入姓氏或公司名称(仅输入一个)。 这是我现在的代码:

struct store {
unsigned long phone_num;
char *first_name;
char *last_name;
char *company_name;
char *email;
};
typedef struct store store;


void findContact(FILE *fp, long fileEnd)
{
/*variables*/
char fName [100];
char lName [100];
char cName [100];
char email [100];

int i, length;
int count = 1;
int size = sizeof(long);
int usize = sizeof(unsigned long);

unsigned long phone;

long nextPosition = 0;
long fNamePosition = 0;
long lNamePosition = 0;
long cNamePosition = 0;
long emailPosition = 0;

store *list;
list = malloc(sizeof(store));

/*Search for Contact position in file*/
fseek(fp, 0, SEEK_SET); /*Seeks to beginning of file*/
do {
    i = count - 1;

    fread(&phone, usize, 1, fp); /*reads phonenumber of contact*/
    fread(&fNamePosition, size , 1, fp);
    fread(&lNamePosition, size, 1, fp);
    fread(&cNamePosition, size, 1, fp);
    fread(&emailPosition, size, 1, fp);
    fread(&nextPosition, size, 1, fp);

    if(fNamePosition != 0) {

        fseek(fp,fNamePosition,SEEK_SET);
        if(lNamePosition == 0) {
          length = cNamePosition - fNamePosition;
        } else {
          length = lNamePosition - fNamePosition;
        }
        fread(fName,sizeof(char),length,fp);
    } else {
        strcpy(fName," ");
    }

    if(lNamePosition != 0) {
        fseek(fp,lNamePosition,SEEK_SET);
        if (cNamePosition == 0) {
          length = emailPosition - lNamePosition;
        } else {
          length = cNamePosition - lNamePosition;
        }
        fread(lName,sizeof(char), length,fp);
    } else {
        strcpy(lName," ");
    }

    if(cNamePosition != 0) {
        fseek(fp,cNamePosition,SEEK_SET);
        length = emailPosition-cNamePosition;
        fread(cName,sizeof(char), length,fp);
    } else {
        strcpy(cName," ");
    }

    fseek(fp,emailPosition,SEEK_SET);
    length = nextPosition - emailPosition;
    fread(email,sizeof(char),length,fp);

    list = realloc(list, count * sizeof(store));

    list[i].phone_num = phone;
    list[i].first_name = (char *) malloc(strlen(fName) + 1);
    strcpy(list[i].first_name, fName);
    list[i].last_name = (char *) malloc(strlen(lName) + 1);
    strcpy(list[i].last_name, lName);
    list[i].company_name = (char *) malloc(strlen(cName) + 1);
    strcpy(list[i].company_name, cName);
    list[i].email = (char *) malloc(strlen(email) + 1);
    strcpy(list[i].email, email);

    count++;

} while (ftell(fp) != fileEnd);

count--;

qsort(list, count, sizeof(store), compareStore);

/*Prints output*/
for(i=0;i<count;i++) {
    printf("First Name: %s\n", list[i].first_name);
    printf("Last Name: %s\n", list[i].last_name);
    printf("Company Name: %s\n", list[i].company_name);
    printf("Phone Number (enter only numbers): %ld\n", list[i].phone_num);
    printf("Email: %s\n", list[i].email);

    free(list[i].first_name);
    free(list[i].last_name);
    free(list[i].company_name);
    free(list[i].email);
}

free(list);
return;
}


int compareStore (const void*a, const void *b)
{
    const store *aa = a;
    const store *bb = b;

    return (strcmp(bb->last_name, aa->last_name));
}

这是我到目前为止的输出。 它应该将姓氏和公司名称视为相同的参数,然后对其进行排序:

First Name: Andre
Last Name: D'Souza
Company Name:
Phone Number (enter only numbers): 6474000964
Email: adsouz03@mail.com
First Name:
Last Name:
Company Name: University of Guelph
Phone Number (enter only numbers): 5192137299
Email: uog@mail.com
First Name: Raf
Last Name:
Company Name: Raffy Taffy
Phone Number (enter only numbers): 1234567
Email: raf@mail.com

您的比较功能看起来错误。 您将传递指向两个记录a和b的指针。 这些是指向您的商店结构的指针,但是由于某种原因,您将其强制转换为商店**,然后尝试将其取消引用为商店*。 这具有将数据用作指针的效果,这肯定会导致分段错误。

我建议:

int compareStore (const void*a, const void *b)
{
    const store *aa = a;
    const store *bb = b;

    return (strcmp(aa->last_name, bb->last_name)); 
}

请注意, strcmp完全返回qsort期望的int类型。 只需返回strcmp返回的值qsort

为了使compareStore通用compareStore以检查姓氏或公司名称,假设其中一个包含一个字符串,另一个包含NullPtr或Null字符串,则完整的解决方案是:

int compareStore (const void*a, const void *b)
{
    const store *aa = a;
    const store *bb = b;

    // This MACRO retrieve ptr to last_name or company_name based
    // on whether last_name is a NULL ptr or a null "" string.
    // If last_name is either, use company_name insteadof last_name
    #define getKey(x) ((((x)->last_name==NULL)||((x)->last_name[0]==0)) ? (x)->company_name : (x)->last_name)

    // Use the Macro getKey to point to appropriate sort key for each record
    const char* keyA = getKey(aa);  
    const char* keyB = getKey(bb);

    return (strcmp(keyA, keyB));
}

在对qsort本身的调用中发现另一个错误,您在其中传递列表的大小,但是您应该传递要排序的列表中每个记录的大小:

qsort (list, count, sizeof(store), compareStore);

不是一个完整的答案,因为这看起来像功课,但如果你的compareStore()需要比较无论是姓氏公司名称,取其设置,那么它应该包含一个条件。

对于您的情况,您需要一种方法来确定是否设置了last_namecompany_name 您可以将未使用的指针设置为NULL并测试if (a->last_name) 您还可以添加一个enum字段。

如果可以更改struct的定义,则实际上不需要两个将以相同方式使用的char *字段,一次只需要一个。 您可以具有一个字段,但其解释不同。

最后,(对不起的批评,我们深表歉意。)通常,您不应该像使用void*参数那样抑制静态类型检查。 它可以阻止您用脚射击。 但是,在这种情况下,该函数是qsort()的输入,因此是罕见的不可避免的异常之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM