2013-07-10 2 views
2

qsort здесь работает, но если каждый член массива v занимает sizeof(void *), почему qsort ожидает sizeof(int)?QSort с указателем на указатель на аннулированию

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

int comp(const void *pa, const void *pb) 
{ 
    int a = *(int *)pa; 
    int b = *(int *)pb; 

    if (a > b) 
     return +1; 
    else 
    if (b > a) 
     return -1; 
    else 
     return 0; 
} 

int main(void) 
{ 
    int i, a[] = {3, 1, 2, 0, 4}; 
    void **v; 

    v = malloc(sizeof(void *) * 5); 
    for (i = 0; i < 5; i++) { 
     v[i] = &a[i]; 
    } 
    for (i = 0; i < 5; i++) { 
     printf("%d\n", *(int *)v[i]); 
    } 
    qsort(v[0], 5, sizeof(int), comp); // why sizeof(int) if v is void ** 
    printf("Sorted:\n"); 
    for (i = 0; i < 5; i++) { 
     printf("%d\n", *(int *)v[i]); 
    } 
    free(v); 
    return 0; 
} 
+0

David: вы понимаете 'v [i] = &a[i];' выражение в коде, почему это необходимо и почему 'v' является' void * 'здесь корректно? –

+0

@GrijeshChauhan, я должен использовать void ** (как абстракция для универсального контейнера) для сортировки разных типов. –

+1

Правильно !, а 'v [i] = & a [i]' необходимо, потому что вы хотите сортировать 'a [] 'array, но в' qsort() 'вызов вы передаете' v', который не содержит о типе вашего массива 'a []', поэтому вы явно передаете информацию содержания, что 'a [i]' elements являются 'int' , –

ответ

6
qsort(v[0], 5, sizeof(int), comp); // why sizeof(int) if v is void ** 

Адрес начала блока памяти для сортировки, что вы передаете qsort является

v[0] = &a[0] 

адрес начального элемента a, поэтому массив, который вам сортировать это a, а не блок, начальный элемент которого v указывает на. Элементы a: int s, поэтому sizeof(int) - верный размер.

Если вы хотите отсортировать массив указателей, вам необходимо передать адрес первого элемента в этом массиве, &v[0] или просто v - qsort. Тогда, конечно, размер аргумент должен быть sizeof (void*):

qsort(v, 5, sizeof(void*), cmp); 

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

int cmp(const void *pa, const void *pb) { 
    int a = *(int*)(*(void**)pa); 
    int b = *(int*)(*(void**)pb); 

    if (a > b) 
     return +1; 
    else 
    if (b > a) 
     return -1; 
    else 
     return 0; 
} 

или что-то подобное. Поскольку то, что передается функции сравнения от qsort, является адресом вещей для сравнения, нам нужно одно косвенное указание, чтобы получить указатели для сравнения, и поскольку здесь мы хотим сравнить указатели на то, что int значения, на которые они указывают, нам нужно второе чтобы получить заостренный указатель на int.

+0

Но сравнение по-прежнему неверно, не так ли? –

+0

Нет, 'qsort' передает' & a [i] 'и' & a [j] '(вычисленный с помощью параметра' size') в 'comp', так что это правильно. Возможно, это не так, как предполагалось, - если было намерено сортировать массив указателей, но, как оказалось, код правильный. Возможно, случайно. –

+0

Да, я знаю, что '& a [i]' и '& a [j]' передаются компаратору, и это точно * то, что меня смущает ... Я не понимаю, как это правильно, я пропускаю уровень косвенность ... может быть, мне нужно было бы поспать, а не болтаться на SO :) –

Смежные вопросы