2017-04-02 79 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()的輸入,因此是罕見的不可避免的例外之一。

相關問題