2010-04-02 92 views
4

我有一個指向Objective-C對象的指針數組。這些對象有一個與它們相關的排序鍵。我試圖使用qsort來排序這些對象的指針數組。但是,第一次調用比較器時,第一個參數指向數組中的第一個元素,但第二個參數指向垃圾,當我嘗試訪問其排序鍵時,給了我一個EXC_BAD_ACCESS。在指向Objective-C對象的指針數組上的qsort

這裏是我的代碼(轉述):

- (void)foo:(int)numThingies { 
    Thingie **array; 
    array = malloc(sizeof(deck[0])*numThingies); 

    for(int i = 0; i < numThingies; i++) { 
     array[i] = [[Thingie alloc] initWithSortKey:(float)random()/RAND_MAX]; 
    } 

    qsort(array[0], numThingies, sizeof(array[0]), thingieCmp); 
} 

int thingieCmp(const void *a, const void *b) { 
    const Thingie *ia = (const Thingie *)a; 
    const Thingie *ib = (const Thingie *)b; 

    if (ia.sortKey > ib.sortKey) return 1; //ib point to garbage, so ib.sortKey produces the EXC_BAD_ACCESS 
    else return -1; 
} 

任何想法,爲什麼發生這種情況?

+0

你是否檢查'b'是否指向分配數組內?也許這將提供一個線索。 – 2010-04-02 01:04:54

+0

爲什麼不使用NSArray或類似的可可數據結構來跟蹤你的Thingies並對它們進行分類? – stefanB 2010-04-02 02:13:51

+0

不幸的是,NSArray在這個*特殊情況下不符合我的要求。看到我對下面的bbum(優秀)答案的迴應。 – ElBueno 2010-04-02 09:58:59

回答

10

的問題是雙重的:

  • qsort的第一個參數需要是指向數組開頭的指針

  • 傳遞給排序函數的參數是act ually指針數據

的指針考慮這個工作代碼:

int thingieCmp(const void *a, const void *b) { 
    NSObject *aO = *(NSObject **)a; 
    NSObject *bO = *(NSObject **)b; 

    if (aO.hash > bO.hash) return 1; 
    else return -1; 
} 


int main (int argc, const char * argv[]) { 
    NSObject **array; 
    array = malloc(sizeof(NSObject*)*20); 

    for(int i = 0; i < 20; i++) { 
     array[i] = [NSObject new]; 
    } 

    qsort(array, 20, sizeof(NSObject*), thingieCmp); 

    return 0; 
} 

注意,比較函數由NSObject *aO = *(NSObject **)a解決了數據指針和qsort函數採用array直接的論據。

儘管如此,所有這些都引起了的問題爲什麼要麻煩?

NSArray是非常擅長處理對象的數組,很便於排序。在一般情況下性能非常好。如果性能分析表明它不是,您可以相對容易地優化它。

請注意,我也一直在使用sizeof() - 兩個地方都是一樣的。另外,原始代碼中的const不是必需的。

+0

輝煌!宏偉,先生!非常感謝! 爲了回答你的問題,這是我希望能夠在未來的純C項目中使用的可移植引擎代碼(Thingie即將變爲無效)。我在原型設計時使用了NSArray,而且你是對的,這是一個很好的數據結構。只要它符合我的要求! 再次感謝。你贏得了生命。 :) (Quick aside:我如何在這些評論中進行換行符?Markdown編輯幫助頁面中的雙空間技巧無法使用。) – ElBueno 2010-04-02 09:55:56

+0

歡迎您! 換行幾乎是手動格式化代碼塊的問題... – bbum 2010-04-02 16:20:29

1

我認爲,一個錯誤在於正確的線

qsort(array[0], numThingies, sizeof(array[0]), thingieCmp); 

嘗試

qsort(&array[0], numThingies, sizeof(array[0]), thingieCmp); 

甚至

qsort(array, numThingies, sizeof(array[0]), thingieCmp); 

代替。編譯器不會在這裏抱怨,因爲qsort應該採用void*,並且您將其傳遞給,可合法地將其轉換爲void*而不發出警告,但您確實希望qsort在整個陣列上運行,該陣列的類型爲Thingy**

的另一件事是:比較將指向數組插槽作爲參數調用,所以你得到的實際上是一個Thingy**

int 
thingieCmp(void* a, void* b) 
{ 
    Thingie *ia = *((Thingie**)a); 
    Thingie *ib = *((Thingie**)b); 

    ... 
} 
+0

嘗試了這兩個想法。兩者都導致/ both /參數指向垃圾。 – ElBueno 2010-04-02 01:27:18

+0

@ElBueno:數組分配中的'deck'是什麼?只是一個錯字? – Dirk 2010-04-02 01:36:57

+0

錯字,是的。我知道我會錯過一個。 :) – ElBueno 2010-04-02 09:42:40