正如下面的代码一样,intcmp1正确运行,但intcmp出现段错误。我不知道为什么。这两个代码看起来是一样的。
我的系统环境是: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 beginn");
qsort(b,5,sizeof(int*),intcmp1);
printf("cmp1 endn");
printf("cmp1 beginn");
qsort(b,5,sizeof(int*),intcmp);
printf("cmp2 endn");
}
**((int**)a)
不等于*((int*)(*(int*)a))
吗?
否,**((int**)a)
和*((int*)(*(int*)a))
不等价。第一个在上下文中是正确的:a
实际上是指向传递给qsort
的int*
数组元素的指针。**((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
。