使用qsort()中比较函数中结构的值 - C99 - 取消引用指向不完整类型的指针

时间:2014-04-04 05:07:40

标签: c pointers struct c99 qsort

我对c很新,并且正在努力正确使用C stdlib qsort()函数。

这与教育有关,因此我只允许使用C99和标准库,如果这很重要的话。

我有一个从HashTable中获取并放入HashItem **数组的项目列表,但是在排序时我正在努力使用compare函数,我无法从结构中获取正确的值。我环顾四周,看到了一些解决方案,但它们似乎都导致了

[Error] dereferencing pointer to incomplete type

这是结构:

typedef struct {
char *word;
int occurences;
} HashItem;

我有兴趣根据出现的值进行比较和排序。

以下是调用qsort的代码:

int n = array->number_of_values;
HashItem **standard_array = array_getarray(array); 
qsort(standard_array, n, sizeof(HashItem*), compare_func);

以下是比较功能:

int compare_func(const void *a, const void *b){
const struct HashItem* aa = (HashItem*)a;
    const struct HashItem* bb = (HashItem*)b;
    int val_1 = aa->occurencies;
    int val_2 = bb->occurencies;

    if(val_1 == val_2){
    return 0;
    }else if(val_1 > val_2){
    return 1;
    }else{
    return -1;
    }
    }

对不起格式化,我是新来的问题。

我希望你能帮助你。

数组代码:

/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
    int number_of_values; 
    int capacity;
    HashItem **items;
}DynArray;

/*Method to create a new dynamic array and return it */
DynArray* array_new(int file_size){
    DynArray *array = malloc(sizeof(DynArray));
    array->number_of_values = 0;
    array->capacity = file_size / 10;
    printf("capacity is %d " , array->capacity);
    array->items = malloc(sizeof(HashItem*)* array->capacity);
}

/*Method used to increase the size of the array and reallocate memory*/
void array_increase_if_full(DynArray *array){
    if (array->number_of_values >= array->capacity){
        array->capacity *= 1.25;
        array->items = realloc(array->items, sizeof(HashItem)*array->capacity);
    }
}

/*Method to add a string to the dynamic array specified */
void array_append(DynArray *array, HashItem *item){
    array_increase_if_full(array);
    array->items[array->number_of_values] = item;
    //printf("item %s added \n at position %d ", array->items[array->number_of_values]->word, array->number_of_values);
    array->number_of_values++;
}

/*Method used to get value at specified position for given array*/
HashItem *array_get(DynArray *array, int position){
    if(position >= array->number_of_values || position <0){
        printf("Index specified out of range");
        exit(1);
    }
    //printf("item %s at position %d retrieved", array->items[position]->word, position);
    return array->items[position];
}

HashItem **array_getarray(DynArray *array){
    HashItem **toreturn[array->number_of_values];
    int i;
    for(i = 0; i < array->number_of_values; i++){
        toreturn[i] = array_get(array, i);
    }
    return toreturn;
}

从main打印数组会给出正确的未排序值:occurences

编辑:

感谢所有花时间提供帮助的人,现在它处于Michaels建议的工作状态,我不再使用array_getarray()方法而是使用:

int n = array->number_of_values;
int i;
HashItem **standard_array = malloc(n*sizeof(HashItem*));
for(i = 0; i < n; i++){
    standard_array[i] = array_get(array, i);
    printf("%s : %d \n" , standard_array[i]->word, standard_array[i]->occurences);
}

3 个答案:

答案 0 :(得分:1)

您构建声明:

    typedef struct {
    char *word;
    int occurences;
    } HashItem;

声明匿名结构的typedef名称。 HashItem类型是结构,但没有struct HashItem类型。

因此,当您的compare_func()具有以下声明时:

const struct HashItem* aa = (HashItem*)a;
const struct HashItem* bb = (HashItem*)b;

那些struct HashItem*变量是指向前面声明的struct HashItem的指针,它与上面的HashItem结构没有关系。

只需将这些变量声明更改为:

const HashItem* aa = (HashItem*)a;
const HashItem* bb = (HashItem*)b;

和/或将结构声明更改为:

    typedef struct HashItem {
    char *word;
    int occurences;
    } HashItem;

然而,还有另一个问题(正如其他答案中所提到的):您显然正在排序指向HashItem个对象的指针数组,但您的compare_function()正在编写,就像您正在对数组进行排序一样对象(不是指针)。

解决这个问题:

int compare_func(const void *a, const void *b)
{
    // get HashItem*'s from the HashItem**'s
    const HashItem* aa = *((HashItem**)a);
    const HashItem* bb = *((HashItem**)b);

    int val_1 = aa->occurencies;
    int val_2 = bb->occurencies;

    if (val_1 == val_2) {
        return 0;
    } else if (val_1 > val_2) {
        return 1;
    } else {
        return -1;
    }
}

最后(现在无论如何),此函数将地址返回到本地数组,因此它指向的数据不再有效:

HashItem **array_getarray(DynArray *array){
    HashItem **toreturn[array->number_of_values];
    int i;
    for(i = 0; i < array->number_of_values; i++){
        toreturn[i] = array_get(array, i);
    }
    return toreturn;
}

我认为您需要使用malloc()calloc()或其他内容分配您正在重新调整的数组。但我真正认为你需要做的是退后一步,创建一些数据结构图,并考虑它们中包含的各种对象的生命周期,以及如何跟踪这些生命周期,以便你没有泄漏,双重释放,或指针解引用不再有效的对象。

答案 1 :(得分:0)

现在我认为你的问题都是从第一个定义中产生的。

/*DynArray is a dynamically resizing array that is used to hold values and retain size data throughout*/
typedef struct{
    int number_of_values; 
    int capacity;
    HashItem **items;
}DynArray;

我认为items没有理由成为双指针。注释说它应该包含值,但是指向数组的双指针将包含指针,而不是最终值。我认为这个最初的失误导致你到处去其他地方。将其更改为

    ...
    HashItem *items;
    ...

,其余的应该更自然地流动。

答案 2 :(得分:0)

qsort(standard_array, n, sizeof(HashItem), compare_func);更改为

qsort(standard_array, n, sizeof(HashItem*), compare_func);

在函数void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

第三个参数size_t size代表:

  

数组中每个元素的字节大小。