Я записал этот qsort:
void qsort(void *a[],int low,int high, int (*compare)(void*,void*));
Когда я обращаюсь к этому
char *strarr[5];
Это говорит что недопустимое преобразование из символа ** для освобождения **. Почему это неправильно?
Это - код:
#include<cstdlib>
#include<cstdio>
#include<iostream>
using namespace std;
inline void strswap(void *a,void *b) {
char *t=*(char**)a;
*(char**)a=*(char**)b;
*(char**)b=t;
}
int strcompare(void *a, void *b) {
return strcmp(*(char**)a,*(char**)b);
}
void qsort1(void *a[],int low,int high, int (*compare)(void*,void*), void (*swap)(void*,void*)) {
if(low>=high)
return;
int q=low-1;
for(int i=low;i<=high-1;i++)
if((*compare)(&a[i],&a[high]) < 0)
swap(&a[i],&a[++q]);
swap(&a[high],&a[++q]);
qsort1(a,low,q-1,compare,swap);
qsort1(a,q+1,high,compare,swap);
}
int main() {
const int n=3;
//int a[n]={4,6,8,12,10,9,8,0,24,3};
char *strarr[5]={"abcd","zvb","cax"};
qsort1(strarr,0,n-1,strcompare,strswap);
for(int i=0;i<n;i++)
cout << strarr[i] << " ";
cout << endl;
return 0;
}
Разрешено неявное преобразование любого типа указателя в void *
, потому что void *
определяется как тип указателя, имеющий достаточный диапазон, чтобы он мог представлять любое значение, которое может представлять любой другой тип указателя. (Технически, только другие типы указателей на объекты , что исключает указатели на функции).
Это не означает, что void *
имеет тот же размер или представление, что и любой другой тип указателя: преобразование указателя из другого типа указателя в void *
не обязательно оставить базовое представление неизменным .Преобразование из double *
в void *
аналогично преобразованию из double
в int
- это должно происходить на виду у компилятора , вы не можете скрыть это преобразование за спиной компилятора.
Таким образом, это означает, что хотя void *
является универсальным указателем, void **
является не универсальным указателем на указатель. Это указатель на void *
- указатель void **
должен указывать только на реальные объекты void *
(тогда как void *
сам может указывать на что угодно).
Вот почему нет неявных преобразований между типом **
и void **
- по той же причине, по которой нет неявных преобразований между double *
и int *
.
Теперь есть один особый случай: по историческим причинам char *
гарантированно будет иметь тот же размер, представление и требования к выравниванию, что и void *
. Это означает, что преобразования между char **
(в частности) и void **
на самом деле допустимы, как исключение из общего правила. Таким образом, в вашем конкретном случае ваш код верен, если вы добавляете приведение к void **
, когда вы передаете strarr
в qsort1 ()
].
Однако ваш qsort1 ()
определен только для правильной работы с массивами void *
или char *
(включая unsigned char *
и др.).Вы не можете использовать его, например, для сортировки массива указателей double *
(хотя сегодня он действительно работает в большинстве распространенных сред).
Любой указатель может быть неявно преобразован в указатель void. Но ваш первый параметр не является указателем void - это массив указателей void, и неявного преобразования для него не существует. Возможно, вы хотите объявить свою функцию как:
void qsort(void *,int low,int high, int (*compare)(void*,void*));
но трудно сказать, не видя кода.