2017-04-02 81 views
0

我正在尝试对姓氏和公司名称进行排序。用户必须输入姓氏或公司名称(只有一个)。这是我现在的代码:C编程:使用两个参数对结构进行排序

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: [email protected] 
First Name: 
Last Name: 
Company Name: University of Guelph 
Phone Number (enter only numbers): 5192137299 
Email: [email protected] 
First Name: Raf 
Last Name: 
Company Name: Raffy Taffy 
Phone Number (enter only numbers): 1234567 
Email: [email protected] 
+0

您可能会从查看[** qsort不会排序动态分配的结构数组**](http:// stackoverflow。com/questions/43163754/qsort-wont-sort-dynamic-allocated-arrays-of-structs) –

回答

2

您的比较函数看起来不对。您将指针传递给两个记录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回报正是一种为int的是qsort期待。只需返回qsortstrcmp返回的值。

要推广compareStore检查或者姓氏或公司名称,假设其中一个包含字符串,另一个是要么NullPtr或空字符串,那么完整的解决方案是:

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)); 
} 

另一个bug在你的电话发现qsort本身,你通过列表​​的大小,但你应该通过每个记录的尺寸列表中进行排序:

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

我改变了我的功能到你描述和改变qsort的方式,但它是通过降序安排它们,它也给我警告警告:初始化从指针目标类型[默认启用]丢弃'const'限定符store * aa = a; ^ 警告:初始化从指针目标类型[默认启用]丢弃'const'限定符 store * bb = b; –

+1

如果数组是一个指针数组,则双*符号将是正确的。正如你所说,这不是,额外的'*'是错误的。 –

+0

@ AndreD'Souza:在aa和bb的定义前添加“const”以摆脱警告。见编辑的答案。 – ScottK

0

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

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

如果您可以更改struct的定义,那么您并不需要两个char *字段,这些字段的使用方式相同,每次只能使用一个。你可以有一个领域,解释不同。

最后,(对不起批评)。你通常不应该像对待void*参数那样禁止静态类型检查。它在那里阻止你在脚下射击自己。但是,在这种情况下,该函数是qsort()的输入,因此是罕见的不可避免的例外之一。

相关问题