strcmp 导致段错误
Strcmp causes segfault
代码如下:
#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的类型是"pointer to array-of-char"。结果,*(char **)a 是一个 "pointer to char",这正是 strcmp 所期望的。
那么问题出在哪里呢?
您可以将其转换为 const char *,它现在应该可以工作了:
int my_compare(const void *a, const void *b) {
return strcmp((const char *)a, (const char *)b);
}
你还应该添加:
#include <stdlib.h>
变化:
return strcmp(*(char **) a, *(char **) b);
收件人:
return strcmp(a,b);
你有一个额外的指针取消引用级别是不正确的,这就是你得到段错误的原因。也就是说,您传递的是 char
值 而 而不是 char
指针 [被演员掩盖了]。
注意:这里不需要从void *
投射。
更新:
回答您的问题,是的,因为您定义 s
和 qsort
调用的方式。
你原来的 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);
}
这有点干净[在数组中使用较少 space]:
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:
回答你的第二个问题:否
None 其中甚至编译:
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]
实际上会失败。
我认为您理解这一点很重要:
- 数组通过引用调用。
- 数组和指针的互换性。
下面两个是等价的:
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
and/or strptr
in any以下表格中的 [共 20 个]:
strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);
strXXX(x + 1);
strXXX(&x[1]);
此外,请在此处查看我最近的回答:
代码如下:
#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的类型是"pointer to array-of-char"。结果,*(char **)a 是一个 "pointer to char",这正是 strcmp 所期望的。
那么问题出在哪里呢?
您可以将其转换为 const char *,它现在应该可以工作了:
int my_compare(const void *a, const void *b) {
return strcmp((const char *)a, (const char *)b);
}
你还应该添加:
#include <stdlib.h>
变化:
return strcmp(*(char **) a, *(char **) b);
收件人:
return strcmp(a,b);
你有一个额外的指针取消引用级别是不正确的,这就是你得到段错误的原因。也就是说,您传递的是 char
值 而 而不是 char
指针 [被演员掩盖了]。
注意:这里不需要从void *
投射。
更新:
回答您的问题,是的,因为您定义 s
和 qsort
调用的方式。
你原来的 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);
}
这有点干净[在数组中使用较少 space]:
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:
回答你的第二个问题:否
None 其中甚至编译:
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]
实际上会失败。
我认为您理解这一点很重要:
- 数组通过引用调用。
- 数组和指针的互换性。
下面两个是等价的:
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
and/or strptr
in any以下表格中的 [共 20 个]:
strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);
strXXX(x + 1);
strXXX(&x[1]);
此外,请在此处查看我最近的回答: