【问题标题】:qsort on an array of pointers to Objective-C objects对指向 Objective-C 对象的指针数组进行 qsort
【发布时间】:2011-02-03 14:32:01
【问题描述】:

我有一个指向 Objective-C 对象的指针数组。这些对象有一个与之关联的排序键。我正在尝试使用 qsort 对指向这些对象的指针数组进行排序。但是,第一次调用比较器时,第一个参数指向数组中的第一个元素,但第二个参数指向垃圾,当我尝试访问其排序键时,给了我一个 EXC_BAD_ACCESS。

这是我的代码(意译):

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

任何想法为什么会发生这种情况?

【问题讨论】:

  • 您是否检查过b 是否指向分配的数组内部?也许这会提供一个线索。
  • 为什么不使用 NSArray 或类似的可可数据结构来跟踪您的 Thingies 并对其进行排序?
  • 遗憾的是,NSArray 在这个特殊 案例中不符合我的要求。请参阅下面我对 bbum (优秀)答案的回复。

标签: objective-c qsort


【解决方案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* 并且您将其传递给 Thingy* 可以合法地转换为 void* 而不会发出警告,但您真的希望 qsort 进行操作整个数组,类型为Thingy**

另一件事是:比较器将使用指向数组槽的指针作为参数调用,所以你得到的实际上是Thingy**

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

    ...
}

【讨论】:

  • 尝试了这两个想法。两者都导致 /both/ 参数指向垃圾。
  • @ElBueno:数组分配中deck是什么?只是一个错字?
  • 错字,是的。我知道我会错过一个。 :)
【解决方案2】:

问题有两个方面:

  • qsort 的第一个参数需要是指向数组开头的指针

  • 传递给排序函数的参数实际上是指向数据指针的指针

考虑这个工作代码:

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 不是必需的。

【讨论】:

  • 太棒了!厉害了,先生!太感谢了!为了回答您的问题,这是我希望能够在未来的纯 C 项目中使用的可移植引擎代码(Thingie 将暂时变为无效)。我在原型设计时使用了 NSArray,你说得对,它是一个很棒的数据结构。只要它符合我的要求!再次感谢。你赢在生活。 :) (顺便说一句:如何在这些 cmets 中换行?Markdown 编辑帮助页面中的两个空格技巧不起作用。)
  • 欢迎您!换行几乎是手动格式化代码块的问题......
猜你喜欢
  • 2011-03-30
  • 1970-01-01
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 2014-03-11
  • 1970-01-01
  • 2021-11-21
相关资源
最近更新 更多