C сортировать массив строк с помощью qsort и strcmp - предупреждение: несовместимый тип указателя

Я попытался отсортировать массив строк с помощью qsort, но получил это предупреждение:

предупреждение: передача аргумента 4 qsort из несовместимого типа указателя

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_PRODUCTS   1000

int main (void) {
    int i, index = 0, isUnique;
    char products[MAX_PRODUCTS][100];
    char product[100];
    int  count[MAX_PRODUCTS];

    FILE * fp;

    fp = fopen ("one.txt", "r");

    // Read words from file and put in array if unique
    while (fscanf(fp, "%s", product) != EOF){
        isUnique = 1;
        for (i=0; i<index && isUnique; i++){
            if (strcmp(products[i], product) == 0){
                isUnique = 0;
            }   
        }

        if (isUnique) {
            strcpy(products[index], product);
            index++;
        }

        else {
            count[i - 1]++;
        }
    }

    qsort(products, MAX_PRODUCTS, sizeof(char*), strcmp);

    fclose(fp);

    return 0;
}

Я также пробовал настраивать функцию для сравнения строк, но это тоже не сработало. Что я могу сделать, чтобы это исправить?


person Tom    schedule 22.01.2020    source источник
comment
Пожалуйста, покажите свою индивидуальную функцию   -  person Gerhardh    schedule 22.01.2020
comment
Помимо предупреждения у вас есть еще одна проблема: вы говорите своему компилятору, что у вас есть массив char *, а у вас есть массив char[100]   -  person Gerhardh    schedule 22.01.2020


Ответы (3)


qsort - это задокументировано на веб-сайте Microsoft, где говорится:

compare Указатель на предоставленную пользователем процедуру, которая сравнивает два элемента массива и возвращает значение, определяющее их взаимосвязь.


Использовать это:

int compare (const void * a, const void * b)
{
  return strcmp((char*)a, (char*)b );
}

следующим образом:

qsort(products, MAX_PRODUCTS, 100, compare);
person lenik    schedule 22.01.2020
comment
По крайней мере, это должно исправить предупреждение компилятора, почему голосование против? - person Ctx; 22.01.2020
comment
Похоже, что причина отрицательного голоса остается невыявленной, как и причина использования этой функции. Хороший ответ должен объяснить, почему и как это использовать: а не просто бросать рыбу. - person Tommylee2k; 22.01.2020
comment
@ Tommylee2k Тем не менее, это единственный способ исправить предупреждение, опубликованное для этой проблемы. Следовательно, хотя и очень кратко, я не вижу разумности отрицательного голоса. - person Ctx; 22.01.2020
comment
Да, лучше не взрывать код в ответ. Предоставьте ссылки на параметр qsort и фрагмент информации. - person Andrew Truckle; 22.01.2020
comment
Нет, я довольно часто предоставлял ссылки на ресурс MSDN по рассматриваемому методу с цитатой соответствующей информации в самом ответе. Многие из хорошо зарекомендовавших себя ответов SO имеют это точно так же, как вы можете видеть в других ответах на этот вопрос. - person Andrew Truckle; 22.01.2020
comment
@AndrewTruckle спасибо за исправления ответа! знак равно - person lenik; 22.01.2020
comment
Мы говорим о том, чтобы научить людей находить собственные ответы и сделать наши ответы максимально полезными. Для вас это просто, потому что вы уже знаете задействованные принципы. Я поддержал ваш вопрос (никогда не голосовал против). Просто хотел сделать наблюдение. В конце концов, я думаю, это зависит от вас, что вы хотите делать. - person Andrew Truckle; 22.01.2020
comment
@AndrewTruckle, я не собираюсь спорить. Ответ на вопрос, содержащий 80 строк кода и 2 строки текста, объясняющий проблему, с 3 строками кода и 1 строкой текста, звучит для меня разумно. Если бы OP более подробно объяснил свои проблемы или OP спросил бы о деталях позже, я был бы рад уточнить ... - person lenik; 22.01.2020

Вы говорите qsort(), что хотите отсортировать массив указателей, но действительно имеете массив массивов!

Это дает вам массив указателей:

char *products[MAX_PRODUCTS]

for (int i = 0; i < sizeof(products)/sizeof(*products); i++) {
    products[i] = malloc(100);
}

Вы также можете отсортировать все элементы массива, но это включает в себя замену целых строк (строго говоря, целых массивов, даже если строки короче) множество раз, что может быть довольно неэффективным. Намного быстрее поменять местами только указатели.

Кроме того, сигнатура strcmp() не соответствует прототипу, который ожидает qsort. Поэтому вы должны заключить его в функцию сравнения с прототипом

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

как показано на странице руководства. Тогда компилятор больше не должен жаловаться.

person Ctx    schedule 22.01.2020

На самом деле у вас больше проблем, чем полученное предупреждение:

  • Вы всегда сортируете MAX_PRODUCTS элементы массива products, независимо от того, сколько элементов действительно действительны (вы сортируете неинициализированные и неопределенные строки).

  • Вы говорите, что размер элемента массива products равен sizeof(char*), но products является массивом массивов, поэтому каждый элемент products является sizeof producst[0] большим.


Теперь о самом предупреждении: объявление strcmp является

int strcmp( const char *lhs, const char *rhs );

в то время как функция сравнения, переданная в qsort,

int (*comp)(const void *, const void *)

Типы аргументов разные. Казалось бы, возможное решение - привести указатель strcmp к правильному типу:

typedef int (*sortfun_type)(const void *, const void *);

// After the loop the variable index should be the number of strings read
qsort(products, index, sizeof products[0], (sortfun_type) &strcmp);

Как отмечено в комментарии, это технически неверно (но все равно должно работать). Правильное решение - написать функцию-оболочку с правильными типами аргументов, которая затем вызывает strcmp (как показано другими).

person Some programmer dude    schedule 22.01.2020
comment
Если вы видите это строго, это вызывает UB: указатель используется для вызова функции, тип которой несовместим с указанным типом. Чистый способ - написать функцию-оболочку, как показано в ответе @lenik. Сказав это, это, вероятно, все равно сработает. - person Ctx; 22.01.2020