C是指针数组的int比较器

时间:2012-10-02 07:15:30

标签: c pointers compare function-pointers void-pointers

我正在关注LCTHW教程,我有一项任务要做。 这是数据结构:

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;

问题是:在不更改比较器的struct和typedef的情况下,我想创建一个比较int的比较器,我该怎么做?

2 个答案:

答案 0 :(得分: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;
    ...

答案 1 :(得分:2)

与标准C库中bsearch()qsort()一起用于DArray结构数组的比较函数可能如下所示:

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匹配)。它是比较器应具有的类型,但在编写函数时不能使用typedef名称。您可以在sort函数的实现及其声明中使用typedef


我在几个地方观察到,由于比较器的结果会导致未定义的行为,因此返回两个有符号int值的差异。

在对现已删除的答案的评论中,AR89询问:

  

而不是减法if语句会更安全吗?

是。考虑如果你有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类型,而减法实际上不起作用(结果始终为零或正数)。