Strcmp会导致段错误

时间:2016-01-02 02:53:14

标签: c pointers casting pointer-to-pointer

以下是代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int my_compare(const void * a, const void * b);

int main()
{
    char s[][80] =
        { "gxydyv", "gdyvjv", "lfdtvr", "ayfdbk", "sqkpge", "axkoev", "wdjitd", "pyrefu", "mdafyu",
 "zdgjjf", "awhlff", "dqupga", "qoprcn", "axjyfb", "hfrgjf", "dvhhhr" };
    int i;
    puts("#Before:#");
    for (i = 0; i < 16; i++)
        puts(s[i]);
    qsort(s, 16, sizeof *s, my_compare);
    putchar('\n');
    puts("#After:#");
    for (i = 0; i < 16; i++)
        puts(s[i]);
    return 0;
}

int my_compare(const void *a, const void *b)
{
    return strcmp(*(char **)a, *(char **)b);
}

这是输出:

#Before:#
gxydyv
gdyvjv
lfdtvr
ayfdbk
sqkpge
axkoev
wdjitd
pyrefu
mdafyu
zdgjjf
awhlff
dqupga
qoprcn
axjyfb
hfrgjf
dvhhhr
Segmentation fault

我还注意到strcmp的原型是: INT的strcmp(常量字符* S1,常量字符* S2);

我认为my_compare中a和b的类型是“指向array-of-char”的指针。因此,*(char **)a是“指向char的指针”,这正是strcmp所期望的。

问题出在哪里?

2 个答案:

答案 0 :(得分:4)

变化:

return strcmp(*(char **) a, *(char **) b);

要:

return strcmp(a,b);

你有一个额外级别的指针解除引用,这是不正确的,这就是你得到段错误的原因。也就是说,您传递了char 而不是 char 指针 [已被屏蔽了]

注意:无需在void *投射。

<强>更新

在回答您的问题时,是的,因为您定义sqsort来电的方式。

如果你做完了原来的my_compare就没问题了:

char *s[] = { ... };

并将您的qsort电话改为:

qsort(s, 16, sizeof(char *), my_compare);

总结一下,有两种方法可以做到这一点

int
main()
{
    char s[][80] = { ... }

    qsort(s, 16, 80, my_compare);

    return 0;
}

int
my_compare(const void *a, const void *b)
{
    return strcmp(a,b);
}

这有点清洁[在阵列中使用更少的空间]:

int
main()
{
    char *s[] = { ... }

    qsort(s, 16, sizeof(char *), my_compare);

    return 0;
}

int
my_compare(const void *a, const void *b)
{
    return strcmp(*(char **) a,*(char **) b);
}

更新#2:

回答第二个问题:

这些甚至都没有编译:

return strcmp((char ()[80])a,(char ()[80])b);
return strcmp(*(char ()[80])a,*(char ()[80])b);
return strcmp((char [][80])a,(char [][80])b);
return strcmp(*(char [][80])a,*(char [][80])b);

但是,即使这样做,它们在逻辑上也是不正确的。以下编译,但在逻辑上更接近qsort传递的内容:

return strcmp((char [80])a,(char [80])b);

但是,当函数传递定义为char x[80]的内容时,它与char *x相同,所以qsort正在传递{{1} } [伪装成char *]。

附注:使用void *远远优于。它允许任意长度的字符串。如果给定字符串超过[或者正是] 80个字符,则另一种形式char *s[]实际上会失败。

我认为理解这一点非常重要:

  1. 数组通过引用调用。
  2. 数组和指针的互换性
  3. 以下两个是等效的:

    char s[][80]

    考虑以下[外部]定义:

    char *
    strary(char p[])
    {
    
        for (;  *p != 0;  ++p);
    
        return p;
    }
    
    char *
    strptr(char *p)
    {
    
        for (;  *p != 0;  ++p);
    
        return p;
    }
    

    这两个可以传递给以下表单的任何中的char x[] = { ... }; char *x = ...; 和/或strary [共20个]:

    strptr

    此外,请参阅我最近的回答:Issue implementing dynamic array of structures

答案 1 :(得分:0)

你可以把它转换为const char *,它现在应该可以工作:

int my_compare(const void *a, const void *b) {
    return strcmp((const char *)a, (const char *)b);
}

还应该添加:

#include <stdlib.h>