新gcc版本7.4.0中C中的b搜索()给出分段错误

新gcc版本7.4.0中C中的b搜索()给出分段错误,c,bsearch,C,Bsearch,我有一个C语言的旧程序,它使用C库中的bsearch()函数和strcmp()。在旧的gcc版本4.4.7中,它运行正常。但在gcc版本7.4.0的最新Ubuntu18.04中,它给出了分段错误。代码如下: #include <stdio.h> #include <ctype.h> #include <string.h> #include <search.h> #define MAX_CHR_IN_STR 50 #define MAX_CHR_

我有一个C语言的旧程序,它使用C库中的
bsearch()
函数和
strcmp()
。在旧的gcc版本4.4.7中,它运行正常。但在gcc版本7.4.0的最新Ubuntu18.04中,它给出了分段错误。代码如下:

#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);
}
#包括
#包括
#包括
#包括
#在第50列中定义最大值
#在演示中定义最大值
#定义性别4
#定义数字4
#定义人员4
#定义总_条目2
#定义介质50
结构mytam\u gnpstr{
char mytam[MAX_CHR_IN_STR];
char mytam_lbl[MAX_CHR_IN_STR];
char gnp_str[最大值在演示中];
char gen_pos[性别];
字符数位置[数字];
每个职位[人]的字符数;
};
结构mytam\u gnpstr mytam\u gnpstr\u数组[总项]={
“0”、“0”、“0[-,s,m]、“0”、“s”、“m”,
“0_0_kara”,“0_0_kara”,“02[-,-,-]kara_0[-,-,-],“0”,“0”,“0”,
};
内部主(空){
字符*RTAME示例;
char TAM[中]=“wA”;
fprintf(stderr,“TAM::::%s\n”,TAM);
fprintf(stderr,“mytam\u gnpstr\u数组[0]”。mytam:,
mytam_gnpstr_数组[0].mytam);
fprintf(stderr,“总条目”:%d\n”,总条目);
fprintf(stderr,“sizeof(mytam\u gnpstr\u数组[0]):::::%zu\n”,
sizeof(mytam_gnpstr_数组[0]);
rtamexample=(char*)b搜索(TAM,mytam\u gnpstr\u数组[0]。mytam,TOTAL\u条目,
(sizeof(mytam_gnpstr_数组[0]),strcmp);
fprintf(stderr,“b搜索::::%s\n”,rtamexample);
}
它在旧的gcc版本4.7.7中给出了
bsearch()
输出
“wA”
但它在gcc7.4.0中给出了分段错误。
非常感谢您的帮助。

代码中有多个问题:

  • 您忘记包含
    ,因此未声明
    b搜索
    ,编译器从调用中推断出的原型不正确:
    TOTAL\u ENTRY
    具有type
    int
    ,而不是
    size\u t
    ,在64位系统上具有不同的表示形式
  • 传递给
    bsearch()
    的参数不一致,应传递指向
    mytam\u gnpstr
    结构的指针和调用
    strcmp()
    的适当比较函数
  • 比较函数
    strcmp()
    没有正确的原型,它碰巧获得指向
    char
    的指针
  • bsearch()
    的返回值应转换为
    (struct mytam_gnpstr*)
    ,并测试
    是否为NULL

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

      下面是符合需要的代码。它包括
      ,因为这是声明
      bsearch()
      的地方。它不包括
      ,因为它不声明代码使用的任何内容。
      同上。它告诉
      bsearch()
      它正在搜索的结构数组,而不是传递指向数组第一个元素的第一个成员的开始的指针。问题代码中传递的比较器函数是
      strcmp()
      ;它的原型与
      bsearch()
      所期望的函数指针类型不匹配,因此您在那里正式获得了未定义的行为。此代码中的comparator函数工作正常,并期望通过
      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;
      }
      
      当注释掉带有
      wA
      的条目时,它将生成输出:

      TAM :::::::: wA
      mytam_gnpstr_array[0].mytam :::::::: 0
      TOTAL_ENTRY :::::::: 4
      sizeof(mytam_gnpstr_array[0]) :::::::: 198
      bsearch :::::::: wA ('Match', 'Match')
      
      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)上编译。我希望在Ubuntu18.04LTS或任何C99可用的系统上也能得到同样的结果。事实上,它也应该适用于C90

      $ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
      >     bs47.c -o bs47
      $
      

      main(argc,argv)intargc;char*argv[]
      。。。从回头路机器!!什么警告?您在问题中没有提到它们。
      strcmp
      不是传递给
      bsearch
      的有效比较函数。它需要
      int(*)(常量void*,常量void*)
      而不是
      int(*)(常量char*,常量char*)
      。这可能不是崩溃的原因,但如果您添加强制转换以尝试“消除警告”,则会违反书面和书面规定的约束。你需要一个包装函数来包装strcmp。你有一个结构类型的数组。您试图假装它是一个固定大小字符串的数组。数据中不包含带有
      “wA”
      的条目,因此
      bsearch()
      应返回一个空指针,然后尝试打印该指针。这可能会触发分段错误,尽管令人沮丧的是,现代库经常试图通过打印
      (null)
      或类似的方式来保护粗心的程序员不受其渎职行为的影响,当使用
      %s
      传递空指针进行格式化时。您说:“在旧操作系统中,相同的代码返回
      'wA”
      “-对我来说,这是代码被破坏的积极迹象。当数据中不存在
      wA
      时,搜索如何在数组中找到它?“它仍在发出警告和空输出。非常感谢。我有一个查询,在提到的场景中,B搜索会搜索我吗