在C

时间:2018-10-23 03:09:42

标签: c generics void-pointers

所以我一直在尝试创建一个通用函数来计算某种类型的(数学)模式。 我已经将其中的一部分记下来了,但是缺少其他部分,因此它将无法编译。我需要有关如何填写那些缺失部分的帮助。

整数的众数函数使用struct count来确定元素和频率。其定义是:

struct count {
    int value;          // the value of the number
    unsigned int freq;  // how many times the number has been seen
}

mode的整数版本输出一个数组,其中包含最频繁的数字的所有联系以及有多少联系。

unsigned int mode(int* tiebuf, int* list, size_t listsize)
{
    struct count modelist[listsize];
    size_t modesize = 0;

    // initialize modelist[]
    for(int i = 0; i < listsize; i++)
    {
        int* found = search(list[i], modelist, modesize);    // signature: search(key, list, listsize)
        if(found == NULL)
        {
            (modelist[i]).num = &list[i];
            (modelist[i]).freq = 0;
             modesize++;
        }
        else
        {
            (*found).freq++;
        }
    }

    // take the most frequent element (last in modelist)
    qsort(modelist, listsize, sizeof(struct count), cmpfreq);
    int mode_element = listsize-1;

    // see if there are any ties for frequency
    size_t tiecount = 1;
    for(int i = mode_element-1; i > 0; i--)
    {
        if((modelist[i]).freq < (modelist[mode_element]).freq)
        {
            tiecount++;    // overshot by 1
            break;
        }
    }

    // output the tie as an array
    for(int i = 0; i < tiecount; i++)
    {
        tiebuf[i] = (modelist[mode_element-1-i].number);
    }
    return tiecount;    // returns how many elements are in tiebuf
}


int cmpfreq(const void* obj1, const void* obj2)
{
    struct count **t1 = (struct count**)obj1;
    struct count **t2 = (struct count**)obj2;
    return ( ((*t1)->freq) - ((*t2)->freq) );
}


int cmpnum(const void* obj1, const void* obj2)
{
    struct count **t1 = (struct count**)obj1;
    struct count **t2 = (struct count**)obj2;
    return ( ((*t1)->number) - ((*t2)->number) );
}


int* tiedmode( int* list, size_t listsize, int (*cmp)(const void*, const void*) )
{
    // takes the median of all ties in the mode
    int ties[listsize];
    int tiescount = mode(ties, list, listsize);
    qsort(ties, tiescount, cmpnum);    // this call doesn't work
                                       // want to call cmpnum with cmp as an argument
                                       // this is why we needed cmpnum
    int middle = tiescount/2;
    return ties[middle];
}

现在,我计划将其转换为通用符号。首先要做的是更改 struct count

struct count {
    void* object;       // some object
    unsigned int freq;  // how many times that object has appeared
}

模式的签名也必须更改为 unsigned int mode(void* tiebuf, size_t tienum, void* list, size_t listsize, size_t objsize, int (*cmp)(const void*, const void*))

最大的问题是辅助功能cmpnum,这是我遇到的麻烦。由于qsort需要带有签名int (*fnptr)(const void*, const void*)的函数指针,因此cmpnum也需要该签名。但是,要比较对象,cmpnum可能还需要用户提供另一个有关如何比较对象的函数指针。理想情况下,cmpnum函数应为

int cmpnum(const void* obj1, const void* obj2, int (*compare)(const void*, const void*))
{
    struct count** t1 = (struct count**)obj1;
    struct count** t2 = (struct count**)obj2;
    return ( compare(t1->object, t2->object) );
}  

那么我该如何将具有3个参数的函数指针转换为仅具有2个参数的函数指针?还是更好,我该如何解决* qsortcmpnum之间的差异的问题?

编辑:之所以首先需要cmpnum是因为tiedmode。此函数采用模式并输出平局的中位数。为了找到中位数,我必须按数字排序。但是,由于这将变得通用,因此我需要用户让库知道如何对struct count中的对象进行排序。

1 个答案:

答案 0 :(得分:0)

您传递给qsort的比较函数只能 接受两个参数。

这就是您在顶部代码块中所做的。

要在第二个代码块中执行所需的操作,您需要创建cmpnum个指针,而要创建*compare个变量。 (例如cmpnum_type1cmpnum_type2等)。这就是“干净”的方式。

另一种方法(有点混乱)是使用原始的cmpnum,但将compare子功能指针设置为 global

int (*compare) (const void *, const void *);

int
cmpnum(const void *obj1, const void *obj2)
{
    struct count **t1 = (struct count **) obj1;
    struct count **t2 = (struct count **) obj2;

    return (compare(t1->object, t2->object));
}

void
dosort(void)
{

    compare = foocmp;
    qsort(modelist, listsize, sizeof(struct count), cmpnum);

    compare = barcmp;
    qsort(modelist, listsize, sizeof(struct count), cmpnum);
}