C 中的 bsearch() 在新的 gcc 版本 7.4.0 中给出分段错误
bsearch() in C giving segmentation fault in new gcc version 7.4.0
我有一个旧的 C 程序,它使用 C 库中的 bsearch()
函数和 strcmp()
。在旧的gcc version4.4.7中,它是运行。但是在最新的 Ubuntu 18.04 和 gcc version7.4.0 中,它给出了分段错误。代码如下:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <search.h>
#define MAX_CHR_IN_STR 50
#define MAX_CHR_IN_DEMO_STR 86
#define GENDER 4
#define NUMBER 4
#define PERSON 4
#define TOTAL_ENTRY 2
#define MEDIUM 50
struct mytam_gnpstr {
char mytam[MAX_CHR_IN_STR];
char mytam_lbl[MAX_CHR_IN_STR];
char gnp_str[MAX_CHR_IN_DEMO_STR];
char gen_pos[GENDER];
char num_pos[NUMBER];
char per_pos[PERSON];
};
struct mytam_gnpstr mytam_gnpstr_array[TOTAL_ENTRY] = {
"0", "0", "0[-,s,m]", "0", "s", "m",
"0_0_kara", "0_0_kara", "02[-,-,-]kara_0[-,-,-]", "0", "0", "0",
};
int main(void) {
char *rtamexample;
char TAM[MEDIUM] = "wA";
fprintf(stderr, "TAM :::::::: %s\n", TAM);
fprintf(stderr, "mytam_gnpstr_array[0].mytam :::::::: %s\n",
mytam_gnpstr_array[0].mytam);
fprintf(stderr, "TOTAL_ENTRY :::::::: %d\n", TOTAL_ENTRY);
fprintf(stderr, "sizeof(mytam_gnpstr_array[0]) :::::::: %zu\n",
sizeof(mytam_gnpstr_array[0]));
rtamexample = (char *)bsearch(TAM, mytam_gnpstr_array[0].mytam, TOTAL_ENTRY,
(sizeof(mytam_gnpstr_array[0])), strcmp);
fprintf(stderr, "bsearch :::::::: %s\n", rtamexample);
}
它在旧的 gcc 版本 4.7.7 中给出 bsearch()
输出 "wA"
但它在 gcc7.4.0 中给出了分段错误。
任何解决此问题的帮助都将不胜感激。
代码中存在多个问题:
- 您忘记包含
<stdlib.h>
,因此未声明 [=11=],并且编译器从调用中推断出的原型不正确:TOTAL_ENTRY
的类型为 int
,不是 size_t
,它在 64 位系统上有不同的表示。
- 您传递给
bsearch()
的参数不一致,您应该传递指向 mytam_gnpstr
结构的指针和调用 strcmp()
. 的适当比较函数
- 比较函数
strcmp()
无论如何都没有正确的原型,它巧合地得到指向 char
的指针。
- 来自
bsearch()
的 return 值应转换为 (struct mytam_gnpstr *)
并针对 NULL
. 进行测试
旧代码已损坏。它显然是凭空产生一个答案;数据值 wA
不会出现在正在搜索的数组中的任何位置,因此除 NULL 指针以外的任何答案都是伪造的。如果显示的代码在旧系统上编译时产生 wA
作为答案,则恕我直言,该代码显然已损坏。
这是符合要求的代码。它包括 <stdlib.h>
因为那是声明 bsearch()
的地方。它不包括 <search.h>
因为它没有声明代码使用的任何内容。 <ctype.h>
同上。它告诉 bsearch()
它正在搜索的结构数组,而不是将指针传递给数组第一个元素的第一个成员的开头。题中代码传入的比较器函数为strcmp()
;它的原型与 bsearch()
期望的函数指针类型不匹配,所以你在那里正式得到了未定义的行为。此代码中的比较器函数正常工作,并期望得到一对指向结构类型的指针,由 bsearch()
转换为 const void *
。第一个指针将是要搜索的键;第二个将是正在搜索的数组中的一行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHR_IN_STR 50
#define MAX_CHR_IN_DEMO_STR 86
#define GENDER 4
#define NUMBER 4
#define PERSON 4
#define MEDIUM 50
struct mytam_gnpstr
{
char mytam[MAX_CHR_IN_STR];
char mytam_lbl[MAX_CHR_IN_STR];
char gnp_str[MAX_CHR_IN_DEMO_STR];
char gen_pos[GENDER];
char num_pos[NUMBER];
char per_pos[PERSON];
};
struct mytam_gnpstr mytam_gnpstr_array[] =
{
{ "0", "0", "0[-,s,m]", "0", "s", "m", },
{ "0_0_kara", "0_0_kara", "02[-,-,-]kara_0[-,-,-]", "0", "0", "0", },
{ "wA", "Match", "Match", "0", "123", "ZZZ" },
{ "zB", "Unmatch", "Unmatch", "0", "123", "ZZZ" },
};
enum { TOTAL_ENTRY = sizeof(mytam_gnpstr_array) / sizeof(mytam_gnpstr_array[0]) };
static int comparator(const void *v1, const void *v2)
{
const struct mytam_gnpstr *p1 = v1;
const struct mytam_gnpstr *p2 = v2;
return strcmp(p1->mytam, p2->mytam);
}
int main(void)
{
struct mytam_gnpstr key = { .mytam = "wA" };
fprintf(stderr, "TAM :::::::: %s\n", key.mytam);
fprintf(stderr, "mytam_gnpstr_array[0].mytam :::::::: %s\n", mytam_gnpstr_array[0].mytam);
fprintf(stderr, "TOTAL_ENTRY :::::::: %d\n", TOTAL_ENTRY);
fprintf(stderr, "sizeof(mytam_gnpstr_array[0]) :::::::: %zu\n", sizeof(mytam_gnpstr_array[0]));
struct mytam_gnpstr *res = bsearch(&key, mytam_gnpstr_array, TOTAL_ENTRY,
sizeof(mytam_gnpstr_array[0]), comparator);
if (res == 0)
fprintf(stderr, "Did not find entry matching\n");
else
fprintf(stderr, "bsearch :::::::: %s ('%s', '%s')\n",
res->mytam, res->mytam_lbl, res->gnp_str);
return 0;
}
当如图所示编译时,它产生输出:
TAM :::::::: wA
mytam_gnpstr_array[0].mytam :::::::: 0
TOTAL_ENTRY :::::::: 4
sizeof(mytam_gnpstr_array[0]) :::::::: 198
bsearch :::::::: wA ('Match', 'Match')
当带有 wA
的条目被注释掉时,它会产生输出:
TAM :::::::: wA
mytam_gnpstr_array[0].mytam :::::::: 0
TOTAL_ENTRY :::::::: 3
sizeof(mytam_gnpstr_array[0]) :::::::: 198
Did not find entry matching
这种行为是正确的。
使用问题中的数据(两行,数组中的任何地方都没有 wA
),您将永远不会从 bsearch()
的有效调用返回 NULL 以外的任何内容。期待其他任何事情都是徒劳的。
JFTR:使用 GCC 9.2.0 和 Xcode 11.3.1 在 macOS Mojave 10.14.6(不要问为什么不是 Catalina)上编译。我希望在 Ubuntu 18.04 LTS 或任何可使用 C99 的系统上得到相同的结果。事实上,它也应该与 C90 一样工作。
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
> bs47.c -o bs47
$
我有一个旧的 C 程序,它使用 C 库中的 bsearch()
函数和 strcmp()
。在旧的gcc version4.4.7中,它是运行。但是在最新的 Ubuntu 18.04 和 gcc version7.4.0 中,它给出了分段错误。代码如下:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <search.h>
#define MAX_CHR_IN_STR 50
#define MAX_CHR_IN_DEMO_STR 86
#define GENDER 4
#define NUMBER 4
#define PERSON 4
#define TOTAL_ENTRY 2
#define MEDIUM 50
struct mytam_gnpstr {
char mytam[MAX_CHR_IN_STR];
char mytam_lbl[MAX_CHR_IN_STR];
char gnp_str[MAX_CHR_IN_DEMO_STR];
char gen_pos[GENDER];
char num_pos[NUMBER];
char per_pos[PERSON];
};
struct mytam_gnpstr mytam_gnpstr_array[TOTAL_ENTRY] = {
"0", "0", "0[-,s,m]", "0", "s", "m",
"0_0_kara", "0_0_kara", "02[-,-,-]kara_0[-,-,-]", "0", "0", "0",
};
int main(void) {
char *rtamexample;
char TAM[MEDIUM] = "wA";
fprintf(stderr, "TAM :::::::: %s\n", TAM);
fprintf(stderr, "mytam_gnpstr_array[0].mytam :::::::: %s\n",
mytam_gnpstr_array[0].mytam);
fprintf(stderr, "TOTAL_ENTRY :::::::: %d\n", TOTAL_ENTRY);
fprintf(stderr, "sizeof(mytam_gnpstr_array[0]) :::::::: %zu\n",
sizeof(mytam_gnpstr_array[0]));
rtamexample = (char *)bsearch(TAM, mytam_gnpstr_array[0].mytam, TOTAL_ENTRY,
(sizeof(mytam_gnpstr_array[0])), strcmp);
fprintf(stderr, "bsearch :::::::: %s\n", rtamexample);
}
它在旧的 gcc 版本 4.7.7 中给出 bsearch()
输出 "wA"
但它在 gcc7.4.0 中给出了分段错误。
任何解决此问题的帮助都将不胜感激。
代码中存在多个问题:
- 您忘记包含
<stdlib.h>
,因此未声明 [=11=],并且编译器从调用中推断出的原型不正确:TOTAL_ENTRY
的类型为int
,不是size_t
,它在 64 位系统上有不同的表示。 - 您传递给
bsearch()
的参数不一致,您应该传递指向mytam_gnpstr
结构的指针和调用strcmp()
. 的适当比较函数
- 比较函数
strcmp()
无论如何都没有正确的原型,它巧合地得到指向char
的指针。 - 来自
bsearch()
的 return 值应转换为(struct mytam_gnpstr *)
并针对NULL
. 进行测试
旧代码已损坏。它显然是凭空产生一个答案;数据值 wA
不会出现在正在搜索的数组中的任何位置,因此除 NULL 指针以外的任何答案都是伪造的。如果显示的代码在旧系统上编译时产生 wA
作为答案,则恕我直言,该代码显然已损坏。
这是符合要求的代码。它包括 <stdlib.h>
因为那是声明 bsearch()
的地方。它不包括 <search.h>
因为它没有声明代码使用的任何内容。 <ctype.h>
同上。它告诉 bsearch()
它正在搜索的结构数组,而不是将指针传递给数组第一个元素的第一个成员的开头。题中代码传入的比较器函数为strcmp()
;它的原型与 bsearch()
期望的函数指针类型不匹配,所以你在那里正式得到了未定义的行为。此代码中的比较器函数正常工作,并期望得到一对指向结构类型的指针,由 bsearch()
转换为 const void *
。第一个指针将是要搜索的键;第二个将是正在搜索的数组中的一行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHR_IN_STR 50
#define MAX_CHR_IN_DEMO_STR 86
#define GENDER 4
#define NUMBER 4
#define PERSON 4
#define MEDIUM 50
struct mytam_gnpstr
{
char mytam[MAX_CHR_IN_STR];
char mytam_lbl[MAX_CHR_IN_STR];
char gnp_str[MAX_CHR_IN_DEMO_STR];
char gen_pos[GENDER];
char num_pos[NUMBER];
char per_pos[PERSON];
};
struct mytam_gnpstr mytam_gnpstr_array[] =
{
{ "0", "0", "0[-,s,m]", "0", "s", "m", },
{ "0_0_kara", "0_0_kara", "02[-,-,-]kara_0[-,-,-]", "0", "0", "0", },
{ "wA", "Match", "Match", "0", "123", "ZZZ" },
{ "zB", "Unmatch", "Unmatch", "0", "123", "ZZZ" },
};
enum { TOTAL_ENTRY = sizeof(mytam_gnpstr_array) / sizeof(mytam_gnpstr_array[0]) };
static int comparator(const void *v1, const void *v2)
{
const struct mytam_gnpstr *p1 = v1;
const struct mytam_gnpstr *p2 = v2;
return strcmp(p1->mytam, p2->mytam);
}
int main(void)
{
struct mytam_gnpstr key = { .mytam = "wA" };
fprintf(stderr, "TAM :::::::: %s\n", key.mytam);
fprintf(stderr, "mytam_gnpstr_array[0].mytam :::::::: %s\n", mytam_gnpstr_array[0].mytam);
fprintf(stderr, "TOTAL_ENTRY :::::::: %d\n", TOTAL_ENTRY);
fprintf(stderr, "sizeof(mytam_gnpstr_array[0]) :::::::: %zu\n", sizeof(mytam_gnpstr_array[0]));
struct mytam_gnpstr *res = bsearch(&key, mytam_gnpstr_array, TOTAL_ENTRY,
sizeof(mytam_gnpstr_array[0]), comparator);
if (res == 0)
fprintf(stderr, "Did not find entry matching\n");
else
fprintf(stderr, "bsearch :::::::: %s ('%s', '%s')\n",
res->mytam, res->mytam_lbl, res->gnp_str);
return 0;
}
当如图所示编译时,它产生输出:
TAM :::::::: wA
mytam_gnpstr_array[0].mytam :::::::: 0
TOTAL_ENTRY :::::::: 4
sizeof(mytam_gnpstr_array[0]) :::::::: 198
bsearch :::::::: wA ('Match', 'Match')
当带有 wA
的条目被注释掉时,它会产生输出:
TAM :::::::: wA
mytam_gnpstr_array[0].mytam :::::::: 0
TOTAL_ENTRY :::::::: 3
sizeof(mytam_gnpstr_array[0]) :::::::: 198
Did not find entry matching
这种行为是正确的。
使用问题中的数据(两行,数组中的任何地方都没有 wA
),您将永远不会从 bsearch()
的有效调用返回 NULL 以外的任何内容。期待其他任何事情都是徒劳的。
JFTR:使用 GCC 9.2.0 和 Xcode 11.3.1 在 macOS Mojave 10.14.6(不要问为什么不是 Catalina)上编译。我希望在 Ubuntu 18.04 LTS 或任何可使用 C99 的系统上得到相同的结果。事实上,它也应该与 C90 一样工作。
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
> bs47.c -o bs47
$