realloc 在简单的字典库中失败

realloc fails in simple dict library

我用 C 为一个快速项目编写了一个轻量级字典,但出现错误:realloc(): invalid next size。我知道这意味着我的堆以某种方式损坏了,但我不确定我做错了什么,看起来我的代码非常简单。

realloc 总是在第四次访问时失败,即 dict->num_kvs = 4

下面是我的代码。它包括 dict 库以及使用它的函数。任何帮助将不胜感激

违规功能:

int* get_letter_frequencies(char* stream) { 

    Dict* dict = Dict_initialize();    

    for(int i = 0; i < strlen(stream); i++) {
        Dict_increment_or_add_key(dict, stream[i]);
    }

    int* to_return = Dict_get_values_array(dict);

    Dict_free();

    return to_return;
}

simple_dict.c(加上结构定义)


typedef struct kv_pair {
    char key;
    int value;
} KV_Pair;

typedef struct dict_ {
    struct kv_pair* kv_pairs;
    int num_kvs;
} Dict;

Dict* Dict_initialize() {
    Dict* to_return = malloc(sizeof(Dict));
    to_return->num_kvs = 0;
    to_return->kv_pairs = NULL;
    return to_return;
}

void Dict_free(Dict* dict) {
    free(dict->kv_pairs);
    free(dict);
}

int Dict_add_key(Dict* dict, char key) {
    dict->num_kvs++;
    printf("next size: %d\n", dict->num_kvs);
    dict->kv_pairs = realloc(dict->kv_pairs, dict->num_kvs * sizeof(KV_Pair));
    printf("realloc passed \n");

    dict->kv_pairs[dict->num_kvs].value = 1;

    return 0;
}

int Dict_find_key(Dict* dict, char key){

    for(int i = 0; i < dict->num_kvs; i++) {
        char cur_key = dict->kv_pairs[i].key;
        if(cur_key == key) {
            return i;
        }
    }

    return -1;
}

int Dict_increment_or_add_key(Dict* dict, char key) {

    int key_index = Dict_find_key(dict, key);

    if(key_index == -1) {
        Dict_add_key(dict, key);
    } else {
        dict->kv_pairs[key_index].value++;
    }


}

int* Dict_get_values_array (Dict* dict) {
    int* to_return = malloc(dict->num_kvs * sizeof(int));

    for(int i = 0; i < dict->num_kvs; i++) {
        to_return[i] = dict->kv_pairs[i].value;
    }

    if(dict->num_kvs > 26) {
        printf("more than 26 kvs: %d", dict->num_kvs);
    }

    return to_return;
}

当您尝试添加第一个元素时,您将 dict->num_kvs 递增到 1,然后分配一个元素。然后这一行:

dict->kv_pairs[dict->num_kvs].value = 1;

它将尝试写入 [1] 元素,而不是 [0] 元素。这是越界的。你应该使用:

dict->kv_pairs[dict->num_kvs-1].value = 1;

PS: 如果您使用的是 GCC 或 Clang,AddressSanitizer 是帮助您检测此类错误的好工具。