Пустые указатели в C ++ - PullRequest
       13

Пустые указатели в C ++

5 голосов
/ 12 апреля 2010

Я написал это 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;
}

Ответы [ 2 ]

12 голосов
/ 13 апреля 2010

Допускается неявное преобразование из любого типа указателя в void *, поскольку void * - это тип указателя, который имеет достаточный диапазон, чтобы он мог представлять любое значение, которое может иметь любой другой тип указателя. (Технически, только другие object типы указателей, исключая указатели на функции).

Это не означает, что void * имеет тот же размер или представление, что и любой другой тип указателя, хотя: преобразование указателя из другого типа указателя в void * не обязательно оставляет базовое представление неизменным . Преобразование из double * в void * аналогично преобразованию из double в int - это должно происходить при полном обзоре компилятора, вы не можете скрыть это преобразование за спиной компилятора.

Таким образом, это означает, что хотя void * является универсальным указателем, void ** является , а не универсальным указателем на указатель. Это указатель на void * - указатель void ** должен указывать только на реальные void * объекты (тогда как сам void * может указывать на что угодно).

Вот почему не существует неявных преобразований между type ** и void ** - по той же причине, по которой не существует неявных преобразований между double * и int *.

Теперь есть один особый случай: по историческим причинам char * гарантированно будет иметь те же требования к размеру, представлению и выравниванию, что и void *. Это означает, что преобразования между char ** (в частности) и void ** на самом деле в порядке, как исключение из общего правила. Так что в вашем конкретном случае ваш код будет верным, если вы добавите приведение к void ** при передаче strarr в qsort1().

Однако ваш qsort1() определен только для корректной работы с массивами void * или char * (включая unsigned char * и т. Д.). Например, вы не можете использовать его для сортировки массива double * указателей (хотя на самом деле это будет работать в большинстве современных сред).

10 голосов
/ 12 апреля 2010

Любой указатель может быть неявно преобразован в пустой указатель. Но ваш первый параметр не указатель void - это массив указателей void, и неявного преобразования в него нет. Вы, вероятно, хотите объявить свою функцию как:

void qsort(void *,int low,int high, int (*compare)(void*,void*));

но трудно сказать, не увидев код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...