-1

我在 C 中有一个旧程序,它使用C 库中的bsearch()函数strcmp()。在旧的 gcc version4.4.7 中,它运行正常。但是在最新的 Ubuntu 18.04 和 gcc 版本 7.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 中给出分段错误。任何解决此问题的帮助表示赞赏。

4

2 回答 2

3

旧代码已损坏。它显然是凭空产生了一个答案;数据值wA不会出现在正在搜索的数组中的任何位置,因此除了 NULL 指针之外的任何答案都是虚假的。如果显示的代码在旧系统上编译时产生wA作为答案,则代码是 IMNSHO 不言而喻的错误。

这是符合需要的代码。它包括<stdlib.h>因为那是bsearch()声明的地方。它不包括<search.h>,因为它没有声明代码使用的任何内容。同上<ctype.h>。它讲述bsearch()了它正在搜索的结构数组,而不是传递指向数组第一个元素的第一个成员的开头的指针。问题中代码中传递的比较器函数是strcmp();它的原型与预期的函数指针类型不匹配bsearch(),因此您在那里正式获得未定义的行为。此代码中的比较器功能正常工作,并期望获得一对指向结构类型的指针,转换const void *bsearch(). 第一个指针将是要搜索的键;第二个将是正在搜索的数组中的一行。

#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')

当条目 withwA被注释掉时,它会产生输出:

TAM :::::::: wA
mytam_gnpstr_array[0].mytam :::::::: 0
TOTAL_ENTRY :::::::: 3
sizeof(mytam_gnpstr_array[0]) :::::::: 198
Did not find entry matching

这种行为是正确的。

使用问题中的数据(两行,wA数组中的任何地方都没有),您将永远不会从bsearch(). 期待其他任何事情都是徒劳的。

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
$
于 2020-02-11T18:03:07.620 回答
0

代码中存在多个问题:

  • 您忘记了 include <stdlib.h>,因此bsearch没有声明,并且编译器从调用中推断出的原型不正确:TOTAL_ENTRY有 type int, not size_t,在 64 位系统上具有不同的表示形式。
  • 您传递给的参数bsearch()不一致,您应该传递指向mytam_gnpstr结构的指针和调用strcmp().
  • 无论如何,比较函数strcmp()都没有正确的原型,它char偶然获得了指针。
  • from 的返回值bsearch()应该被强制转换为(struct mytam_gnpstr *)并测试NULL.
于 2020-02-11T17:35:12.940 回答