【问题标题】:Access violation of dynamic array for hashmaphashmap 的动态数组的访问冲突
【发布时间】:2015-03-28 18:43:16
【问题描述】:

我正在尝试实现的一个小哈希表的表格有问题。

地图.h

typedef struct Map Map;

Map *map_create();
int map_set(Map *map, char *key, void *val);

地图.c

const int MAP_INITIAL_SIZE = 100;

typedef struct MapPair MapPair;
struct MapPair
{
    char *key;
    void *val;
};

struct Map
{
    MapPair **table;
    int count;
    int limit;
};

Map *map_create(void)
{
    Map *map = (Map*)malloc(sizeof(Map));
    if (!map) return NULL;

    map->table = (MapPair**)malloc(MAP_INITIAL_SIZE * sizeof(MapPair));
    if (!map->table)
    {
        free(map);
        return NULL;
    }

    map->count = 0;
    map->limit = MAP_INITIAL_SIZE;

    return map;
}

void add(MapPair **context, int start, MapPair *pair, int limit)
{
    int i = start;
    while (context[i] != NULL && strcmp(context[i]->key, pair->key) != 0) // crashing here
    {
        i++;
        if (i == limit) i = 0;
    }
    context[i] = pair;
}

int map_set(Map *map, char *key, void *val)
{
    if (map->count >= map->limit / 2)
    {
        if (!expand(map)) return 0;
    }

    MapPair *pair = (MapPair*)malloc(sizeof(MapPair));
    if (!pair) return 0;

    pair->key = key;
    pair->val = val;

    add(map->table, hash(key, map->limit), pair, map->limit);

    ++map->count;
    return 1;
}

我最初是在 pelles c 中开发的,但是当我遇到问题时,我转移到了 vs2013 的调试器。然后在 vs2013 中,程序会在 add 函数处崩溃,但在 pelles c 中不会。我假设它与我计划稍后扩展的动态数组有关。

谁能告诉我为什么当我尝试访问动态数组的索引时程序似乎崩溃了?

【问题讨论】:

  • 函数expand()和hash()定义在什么头文件中?
  • 看来你的一级间接太多了。您的Map 应该包含MapPair *,并且您应该使用context[i].key 访问这些字段。 (您对map->table 的分配反映了这种模式。您还可以在哈希映射中存储指向对的指针,但这会引入额外的内存管理。)
  • @codefrenzy 相同的标头,我省略了它们以尽量减少代码量。我什至没有进入扩展部分。
  • 您不会将map->table 初始化为所有NULLs,从而取消引用垃圾指针。不初始化会使(主要有用的)检查NULL 无用。
  • @CarsonEvans: 是的,但你可以让他们有一个NULL 键,例如。

标签: c arrays dynamic hashmap


【解决方案1】:

在添加函数中,您正在检查表,直到到达 NULL 指针:

while (context[i] != N ...

但是当你分配这个表时,你从来没有将这些指针中的任何一个设置为 NULL:

map->table = (MapPair**)malloc(MAP_INITIAL_SIZE * sizeof(MapPair));

您应该将它们设置为 NULL:

for( size_t i = 0 ; i < MAP_INITIAL_SIZE ; i++ )
    map->table[i] = NULL ;

否则您将超出该数组的范围。

【讨论】:

    【解决方案2】:

    我不知道 Visual 可以编译纯 C 项目!无论如何,您的崩溃是由魔术字符串引起的:http://en.wikipedia.org/wiki/Magic_number_(programming)

    * 0xABABABAB : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory
    * 0xABADCAFE : A startup to this value to initialize all free memory to catch errant pointers
    * 0xBAADF00D : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory
    * 0xBADCAB1E : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger
    * 0xBEEFCACE : Used by Microsoft .NET as a magic number in resource files
    * 0xCCCCCCCC : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory
    * 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory
    * 0xDEADDEAD : A Microsoft Windows STOP Error code used when the user manually initiates the crash.
    * 0xFDFDFDFD : Used by Microsoft's C++ debugging heap to mark "no man's land" guard bytes before and after allocated heap memory
    * 0xFEEEFEEE : Used by Microsoft's HeapFree() to mark freed heap memory
    

    (来源:In Visual Studio C++, what are the memory allocation representations?

    与 GCC(或我想象的 pelles)不同,Visual Studio 将未初始化的堆数组指针设置为 0xCDCDCDCD,而不是 NULL。因此,即使上下文未初始化,您对 context[i] != NULL 的检查也会返回 true。

    ...这就是为什么显式总是比隐式更好的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多