【问题标题】:Strcmp causes segfaultstrcmp 导致段错误
【发布时间】:2016-01-02 02:53:13
【问题描述】:

代码如下:

#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(const char *s1,const char *s2);

我认为 my_compare 中 a 和 b 的类型是“指向字符数组的指针”。因此,*(char **)a 是一个“指向 char 的指针”,这正是 strcmp 所期望的。

那么问题出在哪里?

【问题讨论】:

  • qsort(s, 16, sizeof *s, my_compare);int my_compare(const void *a, const void *b) 或消除硬编码值:qsort(s, sizeof s/sizeof *s, sizeof *s, my_compare);
  • 是我还是最初的问题尝试循环遍历 80 个值,而值却明显减少?不过,我的头脑和眼睛可能在耍花招。
  • 你是对的——原来的问题一直在变化......

标签: c pointers casting pointer-to-pointer


【解决方案1】:

变化:

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

收件人:

return strcmp(a,b);

你有一个额外的指针取消引用是不正确的,这就是你得到段错误的原因。也就是说,你传递了char valuesnot char pointers [被演员掩盖了]。 p>

注意:这里不需要从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正在通过char *[伪装成void *]。

附注:使用char *s[] 效果要好得多。它允许任意长度的字符串。如果给定的字符串超过 [或正好] 80 个字符,另一种形式 char s[][80] 实际上会失败。


我认为你理解这一点很重要:

  1. 数组是引用调用
  2. 数组和指针的互换性

以下两个是等价的:

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和/或strptr [共20个]:

strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);

strXXX(x + 1);
strXXX(&x[1]);

另外,请在此处查看我最近的回答:Issue implementing dynamic array of structures

【讨论】:

  • 你的意思是 qsort 给 my_compare 的 a 和 b 是指向 char 的指针,而不是指向 array-of-char 的指针?
  • 对于 char s[][80],也许你应该使用 int my_compare(const void a, const void *b) { return strcmp(*(char ()[ 80])a, (字符​​ ()[80])b); }
【解决方案2】:

您可以将其转换为 const char *,它现在应该可以工作了:

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

你还应该添加:

#include <stdlib.h>

【讨论】:

  • 如果他有void *,则无需在C中进行转换。
猜你喜欢
  • 2021-06-11
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 2018-10-08
  • 2011-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多