2015-04-05 99 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 *。 – 2015-04-05 19:13:45

+1

它們看起來如何? 'int *'不是'int **'。 – m0skit0 2015-04-05 19:18:17

回答

1

不,**((int**)a)*((int*)(*(int*)a))不等價。第一個在上下文中是正確的:a確實是指向數組的元素的指針,傳遞給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); 
} 

<>比較運算返回10,從而imtcmp1將返回-101精確。

+0

此代碼可以在Windows和Ubuntu上運行,其中sizeof(int)= 4 sizeof(int *)= 8,與OS X相同。如何在OS X上正確運行而不編輯代碼?非常感謝 – Jxy 2015-04-06 05:16:06

+0

@Jxy:哪個代碼?如果你用'-m32'編譯,你的代碼可能在OS/X上運行,強制32位模式,其中'sizeof(int)== sizeof(int *)' – chqrlie 2015-04-06 06:44:42