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

#c #pointers

#c #указатели

Вопрос:

У меня возникли некоторые проблемы с функцией, которую мы должны писать. Предположительно, именно так это и должно работать, но это выдает мне ошибку несовместимого типа указателя, и я не уверен, как это исправить.

Проблема заключается в qsort, ссылающемся на функцию compare_last.

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

#define MAX_PERSONS 100

//person structure definition goes here
typedef struct{
    char last[32];
    char first[32];
    int year;
}Person;

//function declarations go here
int compare_last(Person * ptr1, Person * ptr2);

void main(void){//main function goes here
    char *infilename[20];
    char *outfilename[20];
    FILE * fptrin;
    FILE * fptrout;
    int i, j;
    Person musicians[MAX_PERSONS];
    printf("Enter input file name: ");
    scanf("%s", infilename);
    printf("Enter output file name: ");
    scanf("%s", outfilename);
    strcat(*outfilename, ".htm");
    fptrin = fopen(*infilename, "r");
    fptrout = fopen(*outfilename, "w");

    for(i = 0; i < MAX_PERSONS; i  )
    {
        fscanf(fptrin, "%s %s %i", musicians[i].last, musicians[i].first, amp;musicians[i].year);
    }

    qsort(musicians, i, sizeof(musicians[0]), compare_last);

    fprintf(fptrout, "<html>n<body>n<title>LAB14</title>n");

    for(j = 0; j < i; j  )
    {
        fprintf(fptrout, "%s %s %i <br>", musicians[j].last, musicians[j].first, musicians[j].year);
    }

    fprintf(fptrout, "</body>n</html>n");
    fclose(fptrin);
    fclose(fptrout);

}//end main

//function definitions go here

int compare_last(Person * ptr1, Person * ptr2)
{
    int result = strcmp(ptr1 -> last, ptr2 -> last);
    if(result != 0)
        return resu<
    else
        return strcmp(ptr1 -> first, ptr2 -> first); 
}
  

Комментарии:

1. Вы пишете we are supposed to be writing — означает ли это, что это домашнее задание?

Ответ №1:

 int compare_last(Person * ptr1, Person * ptr2);
  

должно быть

 int compare_last(void * ptr1, void * ptr2);
  

Затем вам нужно выполнить приведение внутри compare_last

Комментарии:

1. Хорошо, итак, как мне привести указатели? Все, что я пытаюсь, не работает, и я не могу найти никаких решений.

2. Person * personPtr1 = (Person *) ptr1;

3. Он по-прежнему выдает мне несовместимый тип указателя error….am Я неправильно использую qsort? Я изменил код на int compare_last(void * ptr1, void * ptr2) { Person * personPtr1 = (Person *) ptr1; Person * personPtr2 = (Person *) ptr2; int result = strcmp(personPtr1 -> последний, personPtr2 -> последний); если (результат!= 0) возвращает результат; в противном случае возвращает strcmp (personPtr1 -> первый, personPtr2 — > первый); }

4. @Sam: убедитесь, что вы также изменили прототип для compare_last() .

5. На самом деле параметры функции обратного вызова оба должны быть const void * .

Ответ №2:

Прототипом для qsort() является:

 void qsort(void *base, size_t nmemb, size_t size,
           int(*compar)(const void *, const void *));
  

Таким образом, ваша функция сортировки должна либо соответствовать int(*compar)(const void *, const void *) , либо вам нужно выполнить приведение при вызове qsort().

Если вы хотите выполнить сортировку Person* , самый простой способ — объявить вашу функцию сортировки как требуется, а затем выполнить приведение внутри функции:

 static int compare_last(const void *ptr1, const void *ptr2)
{
    const Person *p1 = ptr1, *p2 = ptr2;
    int result = strcmp(p1 -> last, p2 -> last);
    ...
}
  

тогда вообще нет необходимости приводить, поскольку const void * отлично преобразуется в const Person * .

Комментарии:

1. Приведение здесь несоответствующего указателя на функцию вызовет неопределенное поведение, поскольку qsort вызовет его с неправильными типами аргументов ( const void * вместо Person * ).

2. @R.: Хорошо, приятно знать. Я ожидаю, что большинство компиляторов сгенерируют там что-то разумное, поскольку const void * и Person *, скорее всего, будут представлены одинаково, но неопределенности, конечно, стоит избегать.

3. Да, на практике (и в POSIX) все указатели имеют одинаковое представление, но лучше не полагаться на это, если вам это действительно не нужно, и есть альтернативный способ написания кода, который понятен и соответствует 100%.