2015-04-05 125 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