【问题标题】:How to make a generic function C如何制作通用函数C
【发布时间】:2020-11-22 10:53:49
【问题描述】:

我必须创建一个 HashMap。我创建了两个结构。一个node struct 和一个table struct。第二个结构将“包含”我的节点。我的麻烦是insert 函数:我必须在我的表(*t)中插入一对(键,值)。问题是键和值类型必须是通用的。所以,我想插入 int, double, char, ecc.. 我怎样才能把我的函数变成一个泛型函数

插入.c

struct node{
    int key;
    int val;
    struct node *next;
    struct node *prev;
};
struct table{
    int size;
    struct node **list;
};

int hashCode(int key){
    if(key>0)
        return key-1;
    return key+1;
}

void insert(struct table *t,int key,int val){
    int pos = hashCode(key);
    struct node *list = t->list[pos];
    struct node *newNode = (struct node*)malloc(sizeof(struct node));
    struct node *temp = list;
    while(temp){
        if(temp->key==key){
            printf("%s", "Key already created");
            return;
        }
        temp = temp->next;
    }
    newNode->next = list;
    newNode->key = key;
    newNode->val = val;
    if(list!=NULL){
        list->prev = newNode; 
    }
    t->list[pos] = newNode;
    newNode->prev = NULL;
}

ma​​in.c

int main(){
    struct table *t = /* I create the structure */ ;
    insert(t,2,3);
    insert(t,3,4);
    insert(t,2,3);
    // insert(t,'a','c');  function insert should execute also with char, int, float, double ecc...
    return 0;
}

【问题讨论】:

  • 您可以使用union 存储键和值,并使用enum 建议存储哪些数据。
  • 我从未使用过 union 和 enum,如何在我的函数中使用它们? @jha-G
  • 您可以创建一个通用哈希实现,该实现为键提供比较函数,并将键存储为 void 数据类型(或指向 void 的指针)。
  • Insert 参数是 Int,那么我该如何传递一个 char 呢?我需要传递所有 type ,而不仅仅是 int 。 @PaulOgilvie
  • 您也可以使用void * 来表示keyvalue,并在您的node 中添加一个额外的参数type(可以使用enum)来解码以纠正需要时输入

标签: c generics struct insert hashmap


【解决方案1】:

你这样定义联合:

union value {
    int i;
    float f;
    char c;
//and so on
};

你的节点是这样的:

struct node{
    int key;
    union value val;
    struct node *next;
    struct node *prev;
};

你像这样改变你的函数参数:

void insert(struct table *t, int key, union value val) {}

而你的 main 变成了(我使用宏来简化联合的创建):

#define UVAL(v, k) (union value){ .k = v}

int main(){
    struct table * t = NULL; //Todo

    insert(t, 2, UVAL(3, i) );
    insert(t, 3, UVAL(4, i));
    insert(t, 2, UVAL(3, i));
    return 0;
}

用一些花车代替:

int main(){
    struct table * t = NULL; //Todo

    insert(t, 2, UVAL(3.5f, f));
    insert(t, 3, UVAL(4.f,  f));
    insert(t, 2, UVAL(3.5f, f));
    return 0;
}

【讨论】:

  • 谢谢!请问{.k = v}在define中是什么意思?
  • k 表示联合中的字段名称。这里我传了i或者f所以宏展开后会变成.i或者.f
【解决方案2】:

从 C11 开始你可以使用_Generic

#include <stdio.h>

#define hashCode(x) _Generic((x), \
    int: hash_int, \
    double: hash_double \
)(x)

int hash_int(int value)
{
    printf("Hashing %d\n", value);
    return 42;
}

int hash_double(double value)
{
    printf("Hashing %f\n", value);
    return 42;
}

int main(void)
{
    hashCode(3);
    hashCode(3.14);
    return (0);
}

来自cppreference

说明

提供一种在编译时选择多个表达式之一的方法, 基于控制表达式的类型

首先,控制表达式的类型经历左值 转换。转换仅在类型域中执行:它 丢弃顶级 cvr 限定符和原子性并应用 数组到指针/函数到指针的转换类型 控制表达式,不引发任何副作用或 计算任何值。

转换后的类型与列表中的类型名称进行比较 协会。

如果类型与其中一个的类型名称兼容 关联,然后是泛型的类型、值和值类别 selection 是表达式的类型、值和值类别 出现在该类型名称的冒号之后。

如果没有一个类型名与 控制表达式,并提供默认关联,然后 泛型选择的类型、值和值类别是 默认后的表达式的类型、值和值类别: 标签。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2016-08-13
    • 2019-08-03
    • 1970-01-01
    • 2019-11-16
    相关资源
    最近更新 更多