bsearch () в C дает ошибку сегментации в новой версии g cc 7.4.0 - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть старая программа в C, которая использует функцию bsearch() с strcmp() из библиотеки C. В старом g cc version4.4.7 он работает правильно. Но в последней версии Ubuntu 18.04 с g cc 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);
}

Он дает bsearch() вывод "wA" в старом g cc version-4.7.7, но дает ошибку сегментации в gcc7.4.0. Любая помощь в решении этой проблемы приветствуется.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Старый код не работает. Это очевидно производит ответ из воздуха; значение данных 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')

Когда запись с wA закомментирована , он выводит:

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

Это поведение правильное.

С данными в вопросе (две строки, не более wA в любом месте массива), вы никогда не будете получить что-либо, кроме NULL, от правильного вызова bsearch(). Ожидать чего-то еще - бесполезное упражнение.

JFTR: скомпилировано на macOS Mojave 10.14.6 (не спрашивайте, почему это не Catalina) с G CC 9.2.0 и Xcode 11.3.1. Я ожидаю таких же результатов на Ubuntu 18.04 LTS или на любой системе, где доступен C99. Действительно, он должен работать так же и с C90.

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     bs47.c -o bs47
$
0 голосов
/ 11 февраля 2020

В коде есть несколько проблем:

  • вы забыли включить <stdlib.h>, следовательно, bsearch не объявлено, а прототип, выведенный компилятором из вызова, неверен: TOTAL_ENTRY имеет тип int, а не size_t, который имеет другое представление в 64-битных системах.
  • Аргументы, которые вы передаете bsearch(), не согласованы, вы должны передавать указатели на структуры mytam_gnpstr и соответствующая функция сравнения, которая вызывает strcmp().
  • , функция сравнения strcmp() в любом случае не имеет правильного прототипа, по совпадению она получает указатели на char.
  • возвращаемое значение из bsearch() должно быть отлито как (struct mytam_gnpstr *) и проверено на NULL.
...