【问题标题】:Initial value of calloc, when using with a struct与结构一起使用时 calloc 的初始值
【发布时间】:2019-05-17 05:32:07
【问题描述】:

我正在尝试使用以下代码编写一个非常简单的哈希表:

#include <stdio.h>
#include <string.h>
#define SIZE 10

typedef struct {
    char *first_name;
    char *last_name;
} Employee;

typedef struct {
    Employee *table;
} Hashtable;

void initHashtable(Hashtable *ht) {
    ht->table = (Employee *)calloc(SIZE, sizeof(Employee));
}

int hashKey(char *key) {
    int length = strlen(key);
    return length % SIZE;
}

void put(Hashtable *ht, Employee emp, char *key) {
    int hashedKey = hashKey(key);
    ht->table[hashedKey] = emp;
}

我可以通过以下方式插入元素:

int main(int argc, char const *argv[]) {

    Employee e1;
    e1.first_name = "John";
    e1.last_name = "Doe";

    Hashtable ht;

    initHashtable(&ht);
    put(&ht, e1, "Doe");

    return 0;
}

但是我想修改“put”函数,所以当我尝试插入一些东西时,它会检查那个索引是否为空。如果为空,则返回一些消息,如果不是,则在该索引上插入。类似于:

void put(Hashtable *ht, Employee emp, char *key) {
    int hashedKey = hashKey(key);

    if (ht->table[hashedKey] != 0) {
        printf("Employee is in that index!\n");
    } else {
        ht->table[hashedKey] = emp;
    }
}

但是这个“if 语句”不起作用。所以,我尝试了 0 和 NULL。然后我尝试了像这样的投射:

if(ht->table[hashedKey] != (Employee *)0)

if(ht->table[hashedKey] != (Employee)0)

没有任何工作。我的问题是我知道 calloc 用 0、0 初始化。那么在 struct 的情况下 calloc 用什么初始化呢?

【问题讨论】:

  • 我建议您将 table 成员设置为 指针 数组。首先,它可以更轻松地解决您的问题,因为空条目将是 NULL 指针。其次,它还可以更轻松地解决另一个问题:哈希冲突,例如使用链接列表或类似的。
  • 我正在尝试编译您的代码,我看到 invalid operands to binary expression ('Employee' and 'int') 进行比较。也许这是个问题?
  • @Someprogrammerdude 感谢您的建议,使用指针数组是个好主意。但是我仍然想知道在使用 struct 时 calloc 会初始化什么?

标签: c struct heap-memory dynamic-memory-allocation calloc


【解决方案1】:

但是这个“if 语句”不起作用。

“不工作”,我想你的意思是“不编译”。

所以,我尝试了 0 和 空值。然后我尝试了像这样的投射:

if(ht->table[hashedKey] != (Employee *)0)

if(ht->table[hashedKey] != (Employee)0)

没有任何效果。

您的编译器将发出诊断消息,解释为什么它拒绝您的代码。这样的诊断有时可能是神秘的,但是关于数据类型的抱怨肯定会让你问自己这个问题“这里涉及到什么类型?”。不过,我们可以提供帮助:

  • ht-&gt;table[hashedKey] 的类型为 Employee(一个结构,而不是指向一个的指针)。对于您的目的而言,这可能是最重要的一项,但让我们继续......

  • 0int 类型的常量,它也用作空指针常量(尽管它的类型)。

  • (Employee *) 0Employee * 类型的空指针。

  • (Employee) 0 是一个无效的表达式。它没有类型,因为将int 强制转换为Employee 等结构类型是无效的。

Employee 等结构类型不是!= 运算符(或== 运算符或大多数其他运算符)的有效操作数。这是你的主要问题。即使您生成了一个所有位为零的Employee 表示,这可以通过各种方式完成,您仍然无法通过任何 C 运算符直接比较它与ht-&gt;table[hashedKey] 的(不)相等性.但是,即使结构 可比较的,将结构与任何类型的指针进行比较也是没有意义的,就像您的第一个示例尝试做的那样。

我的问题是我知道 calloc 初始化为 0, 零。那么在 struct 的情况下 calloc 用什么初始化呢?

这似乎与您的问题没有任何关系,但既然您问了,calloc 将它分配的空间初始化为所有位为零。对于整数类型(包括结构的成员),这是 0 的表示。对于其他类型,包括指针类型,语言没有指定这种表示的含义。

要检查两个结构是否相等,您需要逐个比较它们。但是,在您的特定情况下,您实际上并不需要比较结构,您只需要检查 one 结构的成员。但是,由于所有位为零的指针值不一定是空指针,但很可能不指向任何内容,因此将通过 calloc 分配的指针值与 anything 进行比较是不安全的。在这种情况下,并且您的 Employee 结构没有任何非指针成员,calloc 的内存初始化不会为您带来任何有用的信息。

相反,您应该手动初始化每个哈希表元素:

void initHashtable(Hashtable *ht) {
    ht->table = malloc(SIZE, sizeof(Employee));
    for (int i = 0; i < SIZE; i++) {
        ht->table[i].first_name = NULL;
        ht->table[i].last_name = NULL;
    }
}

完成后,您可以通过检查成员来检查表中的给定位置是否已分配:

if (ht->table[hashedKey].first_name != NULL || ht->table[hashedKey].last_name != NULL) // ...

因为空指针在布尔上下文中计算为 false 而非空指针(即使是无效指针)计算为 true,您可以将其缩写为

if (ht->table[hashedKey].first_name || ht->table[hashedKey].last_name) // ...

...如果您愿意。任一版本都会告诉您已分配表格元素。

【讨论】:

    【解决方案2】:

    我的问题是我知道 calloc 用 0、0 初始化。那么在 struct 的情况下 calloc 用什么初始化呢?

    calloc 完全不知道你将如何使用内存。它只是为您提供您请求的数量,并将所有位设置为零。查看它的原型:

    void * calloc(size_t num, size_t size)
    

    参数numsizecalloc拥有的唯一信息。

    【讨论】:

    • 有没有办法检查索引/位置是否有任何非零值?
    • @drmirk Ehm,当然可以。您读取所有值并将它们与零进行比较。
    猜你喜欢
    • 2020-10-08
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    相关资源
    最近更新 更多