2012-10-02 114 views
2

我遵循LCTHW教程,我有一個任務要做。 這是數據結構:C指針數組int的比較器

typedef struct DArray { 
    int end; 
    int max; 
    size_t element_size; 
    size_t expand_rate; 
    void **contents; 
} DArray; 

我宣佈一個typedef:

typedef int (*DArray_compare) (const void *a, const void *b); 

當我創建一個排序的功能,我傳遞給它一個DArray_compare,問題是,我不瞭解如何做這個比較的例子。

我試圖做這樣的事情:

int compare(const void *a, const void *b) 
{ 
    int i = (int)*a; 
    int k = (int)*b; 
    printf("%d %d\n", i, k); 
    return i - k; 
} 

但我得到一個錯誤:

error: operand of type 'void' where arithmetic or pointer type is required int i = (int)*a; 

的問題是:在不改變結構和比較的類型定義,我想創建一個比較int的比較器,我該怎麼做?

+0

你需要澄清一下上下文。比較函數的參數究竟是什麼?它是數組中兩個'DArray'結構的地址,還是指向數組中兩個結構的兩個'int'元素的指針?或者是其他東西?大部分答案都假設你傳遞了兩個指向整數的指針,因爲這就是你的問題似乎表明正在發生的事情,但是一個通用的排序函數將會使用指向這些結構的指針。請注意,您的減法存在簽名「int」溢出的風險,這會導致未定義的行爲。 –

+0

比較函數的參數是數組元素的指針。 – AR89

+0

然後,你的參數'a'和'b'實際上就是'DArray'指針,但是你可以將它們當作第一個元素('end')的指針,使用各種符號,比如接受的答案。 –

回答

4
int i = *(int*)a; 
// This one has more parens to make it really obvious what your intent is. 
int k = *((int*)b); 

第二行(k =)最容易解釋所有括號的cos。可以按如下方式重寫:

// Cast b from a pointer to a void into a pointer to an int. 
int *X = (int*)b; 
// k = "what X is pointing to" or "the contents of X" 
int k = *X; 

編輯: 我覺得RALU的評論是在暗示你改變所有的void*int*這是一個更安全的解決方案,如果你有能力。

typedef int (*DArray_compare) (const int *a, const int *b); 

int compare(const int *a, const int *b) 
{ 
    int i = *a; 
    int k = *b; 
    ... 
+0

+1,他應該改變指針的類型不只是指向 –

+0

的值int *的問題是,你不能用它與qsort和類似的標準函數。這似乎是OP正在做的事情。在這種情況下,參數必須是void *。 – Lundin

+0

你的解決方案有效,但我不明白爲什麼,參數是指針,但要訪問它們的值,爲什麼我們必須做這件事? – AR89

2

使用的比較函數與bsearch()或標準C庫DArray結構數組qsort()可能看起來像:

int compare(const void *a, const void *b) 
{ 
    const DArray *d1 = a; 
    const DArray *d2 = b; 

    if (d1->end < d2->end) 
     return -1; 
    else if (d1->end > d2->end) 
     return +1; 
    else if (d1->max < d2->max) 
     return -1; 
    else if (d2->max > d2->max) 
     return +1; 
    else 
     return 0; 
} 

顯然,如果你需要比較其他領域,你可以添加這些比較進入上面的框架很容易。函數的一般結構是我寫這種比較器的推薦方式。如果你願意,你可以添加明確的強制轉換到賦值行; C++會要求他們,但C不會。

請注意,您的typedef與比較器本身的關聯性很小(儘管比較器作爲函數指針應該與typedef相匹配)。這是比較器應具有的類型,但在編寫函數時不能使用該名稱。您可以在執行sort函數和聲明中使用typedef


我在幾個地方那久違的兩個差簽署int值作爲比較的結果會導致不確定的行爲觀察。

在到現在刪除回答評論,AR89問:

Instead of the subtraction an if statement would be safer?

是。考慮如果你有16位的int值會發生什麼,你比較-30,000和+ 30,000;你已經簽名溢出,並且你可能從比較器中得到一個正值,即使第一個值小於第二個值。類似情況可能會發生在32位或64位整數。他們相對不太可能;如果你知道你的數值在範圍之內,你會沒事的。但是通用的代碼,你應該做的分段比較:

if (i < k) 
    return -1; 
else if (i > k) 
    return +1; 
else 
    return 0; 

,因爲它的工作原理,無論ik的價值觀。另請注意,if比較也可以可靠地用於unsigned int類型,而減法確實無效(結果始終爲零或正數)。