HOWTO · C
Implementar Dicionário em C
Este artigo apresenta como implementar dicionário em C
Nesta página
ISO C não define um tipo de dicionário integrado. Se o ambiente de destino oferecer a interface POSIX hsearch, suas rotinas de tabela hash permitem armazenar e recuperar pares de chave e valor. O exemplo abaixo cria uma tabela, insere duas entradas, consulta uma chave presente e outra ausente, verifica os ponteiros retornados e libera a tabela. Ele demonstra uma abordagem, não todos os projetos de dicionário possíveis.
Use as rotinas POSIX hsearch para implementar um dicionário em C
hcreate, hsearch e hdestroy são rotinas POSIX declaradas em <search.h>, e não funções da biblioteca ISO C. A disponibilidade depende do sistema operacional e da biblioteca C de destino; portanto, confirme se o seu ambiente oferece essa interface antes de usar o exemplo. A especificação POSIX de hcreate e hsearch define a interface e permite consultar seus requisitos. O material fornecido não identifica uma plataforma ou versão específica de biblioteca.
Crie uma tabela hash e adicione entradas com hcreate e hsearch
Chame hcreate uma vez para criar uma tabela com a capacidade solicitada. A função retorna um valor diferente de zero em caso de sucesso e zero se não conseguir criar a tabela. ENTRY contém uma chave char * e um ponteiro de dados void *. Passe um ENTRY e um valor ACTION para hsearch: ENTER solicita a inserção, enquanto FIND solicita uma consulta. Uma chamada bem-sucedida retorna um ponteiro para uma entrada; em caso de falha, retorna NULL.
Execute este exemplo:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
#define _XOPEN_SOURCE 700
#include <search.h>
#include <stdio.h>
int main(void) {
if (hcreate(4) == 0) {
fputs("could not create table\n", stderr);
return 1;
}
ENTRY item = {"language", "C"};
if (hsearch(item, ENTER) == NULL) {
fputs("could not insert language\n", stderr);
hdestroy();
return 1;
}
item.key = "standard";
item.data = "POSIX";
if (hsearch(item, ENTER) == NULL) {
fputs("could not insert standard\n", stderr);
hdestroy();
return 1;
}
ENTRY query = {"language", NULL};
ENTRY *found = hsearch(query, FIND);
if (found == NULL) {
puts("language: not found");
} else {
printf("language: %s\n", (char *)found->data);
}
query.key = "compiler";
found = hsearch(query, FIND);
if (found == NULL) {
puts("compiler: not found");
} else {
printf("compiler: %s\n", (char *)found->data);
}
hdestroy();
return 0;
}
language: C
compiler: not found
A saída exibida inclui a mensagem compiler: not found, que permanece em inglês no exemplo inalterado.
Consulte chaves e trate entradas ausentes
A primeira chamada a FIND procura language, que o programa inseriu com o valor C; a segunda procura compiler, que não foi inserida. O resultado de cada consulta é verificado antes de o programa ler data, então um resultado NULL segue com segurança o caminho de “não encontrado”. Se uma consulta por uma chave que deveria existir retornar NULL, o exemplo ainda evita desreferenciar o ponteiro e informa o resultado. Adapte as mensagens ou a política de retorno às necessidades da sua aplicação.
hsearch também retorna NULL quando não consegue concluir uma inserção; por isso, verifique o resultado de cada chamada a ENTER antes de continuar. O exemplo trata falhas na criação e na inserção escrevendo um diagnóstico em stderr, liberando uma tabela que já tenha sido criada e retornando um status de falha. Faça essas verificações junto de cada operação para que o código seguinte só leia uma entrada depois de confirmar o ponteiro.
Libere a tabela e entenda seus limites
Chame hdestroy quando não precisar mais da tabela. A função libera a tabela, mas cabe ao chamador cuidar do armazenamento alocado dinamicamente para chaves ou valores referenciados pelas entradas; mantenha esses ponteiros e libere separadamente as alocações sob sua responsabilidade. O exemplo usa literais de string, portanto não há alocações desse tipo para liberar. A interface POSIX apresentada não oferece uma operação para remover uma entrada individual. Escolha uma capacidade adequada ao criar a tabela: o valor solicitado é passado a hcreate, e o fluxo mostrado não oferece uma operação para redimensioná-la.