HSEARCH(3)

ИМЯ
hcreate, hdestroy, hsearch, hcreate_r, hdestroy_r, hsearch_r - операции над ассоциативными массивами

ОБЗОР
#include <search.h>

int hcreate(size_t nel);

ENTRY *hsearch(ENTRY item, ACTION action);

void hdestroy(void);

#define _GNU_SOURCE         /* см. feature_test_macros(7) */
#include <search.h>

int hcreate_r(size_t nel, struct hsearch_data *htab);

int hsearch_r(ENTRY item, ACTION action, ENTRY **retval,
              struct hsearch_data *htab);

void hdestroy_r(struct hsearch_data *htab);

ОПИСАНИЕ
Функции hcreate(), hsearch() и hdestroy() позволяют создать и работать с ассоциативным массивом поиска (хэшем), который содержит элементы, состоящие из ключа (строки) и связанных с ним данных. Функции позволяют работать одномоментно только с одним массивом. Функции hcreate_r(), hsearch_r() и hdestroy_r() являются реентерабильными версиями, позволяющими программе создавать более одного массива поиска одномоментно. Последний параметр, htab, указывает на структуру, описывающую массив, с которым работает функция. Программист должен считать, что не знает её формат (т. е., не должен пытаться напрямую читать и изменять её поля). Сначала, хэш должен быть создан с помощью функции hcreate(). В аргументе nel указывается предполагаемое максимальное количество элементов в массиве (данный максимум нельзя изменить позже, указывайте значение с запасом). Реализация функции может изменить этот параметр для повышения быстродействия массива. Функция hcreate_r() выполняет тоже, что и hcreate(), но для массива, описанного в структуре *htab. Перед вызовом hcreate_r() структура, на которую указывает htab, должна быть обнулена. Функция hdestroy() освобождает память, занимаемую массивом, созданным hcreate(). После вызова hdestroy() функцией hcreate() можно создать новый массив. Функция hdestroy_r() выполняет аналогичную задачу для массива, описанного в *htab, который был ранее создан hcreate_r(). Функция hsearch() ищет в массиве элемент с ключом, равным item («равенство» определяется функцией strcmp(3)), и, в случае удачного завершения операции, возвращает указатель на него. Аргумент item имеет тип ENTRY, который определён в <search.h> следующим образом:

typedef struct entry {
    char *key;
    void *data;
} ENTRY;

Поле key указывает на оканчивающуюся null строку, используемую в качестве ключа для поиска. Поле data указывает на данные, связанные с ключом. Аргумент action определяет действие, выполняемое hsearch() после неудачного поиска. Его значением должно быть ENTER (указывает, что нужно вставить копию item и вернуть указатель на новый элемент массива) или FIND (нужно вернуть NULL). Если значение action равно FIND, то поле data игнорируется. Функция hsearch_r() подобна hsearch(), но работает с массивом, указанным в *htab. Функция hsearch_r() отлична от hsearch() в том, что указатель найденного элемента возвращается в *retval, а не как результат работы функции.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функции hcreate() и hcreate_r() возвращают ненулевое значение при успешном выполнении. При ошибке возвращается 0, а errno устанавливается в соответствующее значение. Функция hsearch() при успешном выполнении возвращает указатель на элемент массива. При ошибке возвращается NULL, то есть, если action равно ENTER массив полон, или, если action равно FIND и item не может быть найден в массиве. Функция hsearch_r() возвращает 0 в случае ошибки или ненулевое значение при успешном выполнении. При ошибке данные функции присваивают errno код ошибки.

ОШИБКИ

Функции hcreate_r() и hdestroy_r() могут завершиться с ошибкой по следующим причинам:

EINVAL
    Значение htab равно NULL.

Функции hsearch() и hsearch_r() могут завершиться с ошибкой по следующим причинам:

ENOMEM
    Значение action равно ENTER, значение key не найдено в массиве и в массиве нет места под новый элемент.

ESRCH
    Значение action равно FIND и значение key не найдено в массиве.

В POSIX.1 определена только ошибка ENOMEM.

АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение
hcreate(), hsearch(), hdestroy() | Безвредность в нитях | MT-Unsafe race:hsearch
hcreate_r(), hsearch_r(), hdestroy_r() | Безвредность в нитях | MT-Safe race:htab

СООТВЕТСТВИЕ СТАНДАРТАМ
Функции hcreate(), hsearch() и hdestroy() взяты из SVr4 и описаны в POSIX.1-2001 и POSIX.1-2008. Функции hcreate_r(), hsearch_r() и hdestroy_r() являются расширениями GNU.

ЗАМЕЧАНИЯ
Реализации ассоциативных массивов более эффективны, если массив содержит достаточно свободного места, чтобы не искать незанятое пространство. Это означает, что обычно, значение nel нужно увеличить на, как минимум, 25% от максимального количества элементов, ожидаемых в массиве. Функции hdestroy() и hdestroy_r() не освобождают буферы, на которые указывают элементы key и data в массиве (это невозможно сделать, так как неизвестно, были ли выделены эти буферы динамически). Если эти буферы требуется освобождать (возможно, из-за того, что программа много раз создаёт и удаляет массивы, а не создаёт один массив на всё время работы), то программа должна предусмотреть хранилище под используемые структуры, которое позволило бы их освободить.

ДЕФЕКТЫ
В SVr4 и POSIX 1003.1-2001 указано, что action имеет смысл только при неудачном поиске, поэтому при ENTER не нужно ничего делать, если что-то найдено. В библиотеках libc и glibc (до версии 2.3) реализация функций обновляет data для указанного key в этом случае. Можно добавлять элементы массива, но не удалять.

ПРИМЕР

Следующая программа вставляет в массив 24 элемента, а затем выводит на печать некоторые из них:
#include <stdio.h>
#include <stdlib.h>
#include <search.h>
static char *data[] = { "alpha", "bravo", "charlie", "delta",
     "echo", "foxtrot", "golf", "hotel", "india", "juliet",
     "kilo", "lima", "mike", "november", "oscar", "papa",
     "quebec", "romeo", "sierra", "tango", "uniform",
     "victor", "whisky", "x-ray", "yankee", "zulu"
};
int
main(void)
{
    ENTRY e, *ep;
    int i;
    hcreate(30);
    for (i = 0; i < 24; i++) {
        e.key = data[i];
        /* data — это просто целое число, а не
           указатель на что-то */
        e.data = (void *) i;
        ep = hsearch(e, ENTER);
        /* здесь ошибки быть не должно */
        if (ep == NULL) {
            fprintf(stderr, "ошибка элемента\n");
            exit(EXIT_FAILURE);
        }
    }
    for (i = 22; i < 26; i++) {
        /* показать два элемента массива и
           два не из массива */
        e.key = data[i];
        ep = hsearch(e, FIND);
        printf("%9.9s -> %9.9s:%d\n", e.key,
               ep ? ep->key : "NULL", ep ? (int)(ep->data) : 0);
    }
    hdestroy();
    exit(EXIT_SUCCESS);
}

СМОТРИТЕ ТАКЖЕ
bsearch(3), lsearch(3), malloc(3), tsearch(3)