简体   繁体   English

在qsort()中的compare函数中使用结构的值-C99-将指针解引用为不完整类型

[英]Using values from a struct in the compare function in qsort() - C99 - Dereferencing pointer to incomplete type

i am fairly new to c and struggling to properly use the C stdlib qsort() function. 我对c还是相当陌生,并且正在努力正确使用C stdlib qsort()函数。

This is relevant to education and as such i am only allowed to use C99 and standard libraries if this is important. 这与教育有关,因此,如果这很重要,则只能使用C99和标准库。

I have a list of items taken from a HashTable and put into a HashItem **array but then when sorting this i am struggling with the compare function, i cannot get the correct value out of the struct. 我有一个从HashTable中取出的项目列表,并放入HashItem **数组中,但是当对它进行排序时,我在用compare函数进行挣扎,我无法从结构中获取正确的值。 I have looked around and seen a few solutions but they all seem to lead to a 我环顾四周,看到了一些解决方案,但它们似乎都导致了

[Error] dereferencing pointer to incomplete type

Here is the struct : 这是结构:

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

And i am interested in comparing and sorting by the occurences value. 我对按出现值进行比较和排序感兴趣。

Here is the bit of code which calls the qsort: 这是调用qsort的代码:

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

Here is the compare function: 这是比较功能:

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

Sorry for the formatting, i am new to asking questions here. 对不起格式,我是在这里问问题的新手。

I hope you can help thankyou. 希望您能帮助您。

Array code : 数组代码:

/*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;
}

Printing the array from the main gives the correct unsorted values of word:occurences 从主打印数组会给出正确的word:occurences的未排序值

Edit: 编辑:

Thanks to everyone that took their time to help, it is now in a working state with Michaels suggestion, i no longer use the array_getarray() method and instead use: 由于每个人都花了很多时间来帮助,它现在处于迈克尔建议的工作状态,我不再使用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);
}

You structure declaration: 您构造声明:

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

declares a typedef name for an anonymous struct. 为匿名结构声明typedef名称。 There is a HashItem type that's a structure, but there is no struct HashItem type. 有一个HashItem类型的结构,但是没有struct HashItem类型。

So when your compare_func() has the following declarations: 因此,当您compare_func()具有以下声明时:

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

those struct HashItem* variables are pointers to a forward declared struct HashItem that has nothign to do with the HashItem strucuture above. 这些struct HashItem*变量是指向向前声明的struct HashItem指针,该声明与上述HashItem结构无关。

Just change those variable declarations to: 只需将这些变量声明更改为:

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

and/or change the declaration of the structure to: 和/或将结构的声明更改为:

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

However, there's another issue (as mentioned in other answers): you are apparently sorting an array of pointers to HashItem objects, but your compare_function() is being written as if you're sorting an array of the objects (not pointers). 但是,还有另一个问题(如其他答案中所述):您显然正在对HashItem对象的指针数组进行排序,但是您正在编写compare_function()就像对对象数组(而不是指针)进行排序一样。

To address this: 要解决此问题:

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

Finally (for now anyway), this function is returning the address to a local array, so the data it points to is no longer valid: 最后(无论如何现在),此函数将地址返回到本地数组,因此它指向的数据不再有效:

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

I think you'll need to allocate the array you're retuning using malloc() or calloc() or something. 我认为您需要使用malloc()calloc()或其他方式分配要重新调整的数组。 But what I really think you need to do is step back and create some drawing of your data structures and think about the lifetime of the various objects contained in them and how those lifetimes can be tracked an managed so that you don't have leaks, double frees, or pointer dereferences to no longer valid objects. 但是我真正认为您需要做的是退后一步,创建一些数据结构图,并考虑其中包含的各种对象的生存期,以及如何跟踪这些生存期以进行管理,以免出现泄漏, double释放,或指针取消引用不再有效的对象。

It now looks to me like your problems are all springing from the first definition. 在我看来,您的问题全都源于第一个定义。

/*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;

I see no reason for items to be a double-pointer. 我认为没有理由让items成为双重指标。 The comment says it should contain values, but a double-pointer pointing to an array would contain pointers , not the ultimate values. 注释说它应该包含值,但是指向数组的双指针将包含指针 ,而不是最终值。 I think this initial misstep is causing you to trip everywhere else. 我认为最初的失误导致您到其他地方旅行。 Change it to 更改为

    ...
    HashItem *items;
    ...

and the rest should flow more naturally. 其余的应该更自然地流动。

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

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

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

the third parameter size_t size stands for: 第三个参数size_t size表示:

Size in bytes of each element in the array. 数组中每个元素的大小(以字节为单位)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM