2015-04-05 3 views
-2

Как и в следующем коде, intcmp1 работает правильно, но intcmp получает ошибку сегмента. Я не знаю, почему. Эти два кода выглядят одинаково.Почему этот указатель получил ошибку сегментации C?

Моя системная среда: OS X 10.10.2 64bit; лязг

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
int intcmp(const void *v1, const void *v2){ //Segment Fault 
    return (*((int*)(*(int*)v1)) - *((int*)(*(int*)v2))); 
} 
int intcmp1(const void *v1, const void *v2){ //No Problem 
    return (**(int**)v1-**(int**)v2); 
} 
int main(int argc, char *argv[]) { 
    int a[5]={0,1,2,3,4}; 
    int **b,i; 
    b=calloc(5,sizeof(int*)); 
    for(i=0;i<5;i++){b[i]=&a[i];} 

    printf("cmp1 begin\n"); 
    qsort(b,5,sizeof(int*),intcmp1); 
    printf("cmp1 end\n"); 
    printf("cmp1 begin\n"); 
    qsort(b,5,sizeof(int*),intcmp); 
    printf("cmp2 end\n"); 
} 

Не **((int**)a) равно, как *((int*)(*(int*)a))?

+1

Зачем вам ожидать, что первая версия будет работать? Вы передаете int **, но бросаете в int *. –

+1

Как они выглядят одинаково? 'int *' не 'int **'. – m0skit0

ответ

1

Нет, **((int**)a) и *((int*)(*(int*)a)) не являются эквивалентными. Первый из них является правильным в контексте: a действительно является указателем на элемент массива int*, переданный в qsort. **((int **)a) или просто **(int**)a читает целое число, которое вы хотите сравнить.

С другой стороны, выражение *((int*)(*(int*)a)) делает что-то другое: он считывает из того же адреса в памяти, но как int, а затем делает вид, это на самом деле int адрес и пытается прочитать с этого адреса. Если int и адреса не имеют такой же ширины, это будет неэффективно. Это они одинакового размера, и это будет нецелесообразно.

Кроме того, вы не можете достоверно сравнить значения int, просто вычитая один из другого. Например, INT_MIN < 1, но INT_MIN - 1 вызывает неопределенное поведение и, скорее всего, вычисляет INT_MAX, положительное значение.

intcmp1 следует переписать следующим образом:

int intcmp1(const void *v1, const void *v2) { // works better 
    return (**(int**)v1 > **(int**)v2) - (**(int**)v1 < **(int**)v2); 
} 

В < и > операторы сравнения возвращают 1 или 0, таким образом, imtcmp1 возвратит -1, 0 или 1 точно.

+0

Этот код может работать в Windows и Ubuntu, где sizeof (int) = 4 sizeof (int *) = 8, так же, как OS X. Как я могу сделать этот прогон правильно на OS X без изменения кода? Большое спасибо – Jxy

+0

@Jxy: какой код? Ваш код может работать на OS/X, если вы компилируете с помощью '-m32', заставляя 32-битный режим, когда' sizeof (int) == sizeof (int *) ' – chqrlie

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