在下面的代码中,一旦我删除了比较字符串的注释部分,我就会遇到第11段错误。我无法理解为什么!其余的代码工作正常。任何帮助表示赞赏!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare_scores_desc(const void* scorea, const void* scoreb){
int a = *(int*)scorea;
int b = *(int*)scoreb;
return a-b;
}
int compare_names(const void* namea, const void* nameb){
char** a = *(char**)namea;
char** b = *(char**)nameb;
return strcmp(*a,*b);
}
int main(int argc, char* argv[]){
int scores[7] = {456,234,65,563,67,19,100};
int i;
qsort(scores,7,sizeof(int),compare_scores_desc);
puts("\nThese are the scores in order : \n");
for(i=0;i<7;i++)
printf("%i\n",scores[i]);
char *names[] = {"Krishna","Rama","Bhishma","Arjuna"};
/*qsort(names,4,sizeof(char*),compare_names);*/
puts("------------------");
puts("The names in order are : \n");
for(i=0;i<4;i++)
printf("%s\n",names[i]);
return 0;
}
答案 0 :(得分:6)
在compare_names()
中,您在演员表后不恰当地解除引用参数。局部变量的类型是char **
类型,但是您将参数转换为char **
,并且取消引用该结果会产生char *
。
namea
和nameb
是指向names[]
中声明的数组main()
元素的指针。这意味着,它们的类型实际上是指向char *
的指针。当您取消引用这些参数但将它们分配给char **
时,会导致局部变量将char *
视为char **
(您的编译器应该发出关于此问题的诊断警告) 。现在,您获取一个char *
的指针值,并在将其传递给strcmp()
时取消引用它。这会导致程序将字符串的sizeof(char *)
个字节视为strcmp()
函数的指针值。由于4或8(或任何sizeof(char *)
)字节组成的可打印字符重新解释为指针值很少产生有效指针,当strcmp()
尝试使用这些指针时,会发生分段错误。
一种可能的解决方法是在初始化局部变量时不要取消引用。但是,参数是const void *
,因此如果您将局部变量声明为指向const
类型的指针,则可以完全避免强制转换:
int compare_names(const void* namea, const void* nameb){
char* const * a = namea;
char* const * b = nameb;
return strcmp(*a,*b);
}
请注意,如果compare_scores_desc()
导致有符号整数溢出,则a - b
的实现将失败。例如,如果a
为INT_MAX
且b
为-1
。您应该修复您的实现以适用于所有情况。
int compare_scores_desc(const void* scorea, const void* scoreb){
const int *a = scorea;
const int *b = scoreb;
return (*a > *b) - (*a < *b);
}
答案 1 :(得分:2)
问题出在你的字符串比较函数中,这可能是修复它的最小方法:
int compare_names(const void* namea, const void* nameb){
char* a = *(char**)namea;
char* b = *(char**)nameb;
return strcmp(a,b);
}
namea
和nameb
参数是指向字符串向量的指针。您理解这一点,这就是您使用char **
类型的原因。
但是,您在函数中所要做的就是从该数组中检索char *
指针。这些char *
指针已经是字符串。你不必再取消引用它们;只需将它们传递给strcmp
。
您的原始代码违反了约束条件,需要进行诊断。这应该会让您失望:
/* originally */
char** a = *(char**)namea; /* error: initialization from incompatible type */
您取消引用生成char **
的{{1}},但是您再次将其存储在char *
中并再次解除引用,从而错误地将字符数据视为指针。