Calloc 不会将整个内存块初始化为零

Calloc does not initialize entire memory block to zero

在玩 hashmap 玩具示例的实现时(为了好玩)我发现了一个奇怪的行为,calloc 没有像预期的那样将我想要的整个内存块初始化为零。如果整个内存块都清零,则以下代码不会产生任何输出:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define DICT_INITIAL_CAPACITY 50


typedef struct dictionary_item {
    char* ptr_key;
    void* ptr_value;
} dict_item;

typedef struct dictionary {
    dict_item* items;
    uint16_t size, max_capacity;
} Dict;

Dict* dict_new() {
    Dict *my_dict = calloc(1, sizeof *my_dict);
    my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof my_dict->items);
    my_dict->size = 0;
    my_dict->max_capacity = DICT_INITIAL_CAPACITY;    

    for (int j = 0; j < my_dict->max_capacity; j++) {
        int key_null = 1;
        int value_null = 1;
        if ((my_dict->items + j)->ptr_key != NULL)
            key_null = 0;
        if ((my_dict->items + j)->ptr_value != NULL)
            value_null = 0;
        if ((my_dict->items + j)->ptr_key != NULL || (my_dict->items + j)->ptr_value != NULL)
            printf("item %d, key_null %d, value_null %d\n", j, key_null, value_null);
    }
    return my_dict;
}


int main(int argc, char** argv) {

    Dict* dict = dict_new();


}

然而它产生的输出是:

item 25, key_null 1, value_null 0

唯一的非零项始终是 DICT_INITIAL_CAPACITY / 2 处的项。我也尝试过使用 memset 将所有块置为零,结果是一样的。如果我使用以下方法明确地将内存归零:

for (int j = 0; j < my_dict->max_capacity; j++){
            (my_dict->items + j)->ptr_key = 0;
            (my_dict->items + j)->ptr_value = 0;
        }

然后我得到了想要的行为。但我不明白为什么它不能使用 calloc。我做错了什么?

my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof my_dict->items);

应该是

my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof *my_dict->items);

还要注意,一般来说,calloc 可能不会将指针设置为 null(尽管它在我所知道的所有现代系统上都是这样做的)。显式初始化任何本应为空的指针会更安全。

话虽如此,您似乎正在存储一个 size 变量来指示字典的大小,因此您可以通过不读取当前 size 之外的条目来完全避免此问题;当你增加 size 然后初始化你刚刚添加的条目。