代码之家  ›  专栏  ›  技术社区  ›  Justin808

试图理解C中的“未分配释放的指针”错误

  •  1
  • Justin808  · 技术社区  · 2 年前

    所以这个错误是不言自明的,但我不明白我是怎么得到的。我做了malloc,现在免费抱怨。

    我正在努力为自己建立一个地图/哈希表。我是C语言的新手,但不是编程,所以我认为这将是一个很好的开始。我也在使用SDL,所以我使用这些函数而不是直接的malloc/free。但这不应该改变任何事情。。。

    所以我可以创建基本映射,并为其添加一个键/值。我将free函数与它一起存储,这样映射就知道如何释放自己的项目。第一套有效。当我用同一个键再次设置时,它应该释放当前值并存储新值。但这就是错误发生的地方。

    我所有的错误在哪里/我做错了什么?

    输出

    DEBUG: test/src/util/map.c:53:Map_Create(): Map created 0 of 10 used.
    DEBUG: test/src/util/map.c:101:Map_Set(): Add item 3 of 10.
    DEBUG: test/src/util/map.c:89:Map_Set(): Free item 3 of 10.
    sdl_test(19543,0x1ffee1e00) malloc: *** error for object 0x10249bf8e: pointer being freed was not allocated
    

    main.c

    #include <SDL3/SDL.h>
    #include <SDL3/SDL_main.h>
    #include "util/map.h"
    
    int main(int argc, char *argv[]) {
    
      char *itemA = SDL_malloc(sizeof(char) * 12);
      char *itemB = SDL_malloc(sizeof(char) * 11);
      itemA = "Hello World";
      itemB = "What's Up?";
    
      Map map = Map_Create(10);
    
      Map_Set(map, "test", itemA, SDL_free);
      Map_Set(map, "test", itemB, SDL_free);
    
      Map_Destroy(map);
    
      SDL_Quit();
    }
    

    map.c

    #include <SDL3/SDL.h>
    #include <SDL3/SDL_assert.h>
    #include "util/map.h"
    #include "debug.h"
    
    struct Map_Item {
      struct Map_Item *next;
      void (*free)(void*);
      void *value;
      char *key;
    } Map_Item;
    
    struct Map {
      struct Map_Item **items;
      int capacity;
      int size;
    };
    
    /**
     * Internal functions
     */
    
    static unsigned int _Map_Hash(const char *key) {
      unsigned int hash = -1;
      while (*key) {
        hash *= 31;
        hash ^= (unsigned char) *key;
        key += 1;
      }
      return hash;
    }
    
    /**
     * Public functions
     */
    
    Map Map_Create(int capacity) {
      Map map = SDL_malloc(sizeof (Map));
      SDL_assert(map != NULL);
    
      // Create space for the initial items
      map->items = SDL_calloc(capacity, sizeof (struct Map_Item *));
      SDL_assert(map->items != NULL);
    
      map->capacity = capacity;
      map->size = 0;
    
      // Clear each location as there is currently nothing in any of them
      for (int i = 0; i < map->capacity; i += 1) {
        map->items[i] = NULL;
      }
    
      DEBUG_PRINT("Map created %d of %d used.\n", map->size, map->capacity);
    
      return map;
    }
    
    void Map_Destroy(Map map) {
      DEBUG_PRINT("Map cleanup %d of %d used.\n", map->size, map->capacity);
    
      // Loop over each item and free it;
      for (int i = 0; i < map->capacity; i += 1) {
        struct Map_Item *curr = map->items[i];
        while (curr != NULL) {
          DEBUG_PRINT("Free item %d of %d.\n", i, map->capacity);
          struct Map_Item *next = curr->next;
          if (curr->free != NULL) {
            curr->free(curr->value);
          }
          SDL_free(curr->key);
          SDL_free(curr);
          curr = next;
        }
      }
    
      SDL_free(map->items);
      SDL_free(map);
    }
    
    
    void Map_Set(Map map, const char *key, void *value, void (*free)(void*)) {
      int b = _Map_Hash(key) % map->capacity;
    
      // Look if the key is in use, if it is then free the old value and store the
      // new one in its place.
      for (struct Map_Item *curr = map->items[b]; curr != NULL; curr = curr->next) {
        if (SDL_strcmp(curr->key, key) == 0) {
          if (curr->free != NULL) {
            DEBUG_PRINT("Free item %d of %d.\n", b, map->capacity);
            curr->free(curr->value);
          }
          DEBUG_PRINT("Replace item %d of %d.\n", b, map->capacity);
          curr->value = value;
          curr->free = free;
          return;
        }
      }
    
      // No existing key was found, so insert it as a new entry at the head of the
      // list.
      DEBUG_PRINT("Add item %d of %d.\n", b, map->capacity);
      struct Map_Item *new = SDL_malloc(sizeof (struct Map_Item));
      new->key = SDL_malloc(sizeof(char) * SDL_strlen(key) + 1);
      new->next = map->items[b];
      new->value = value;
      new->free = free;
      SDL_strlcpy(new->key, key, SDL_strlen(key) + 1);
      map->items[b] = new;
      map->size += 1;
    }
    
    1 回复  |  直到 2 年前
        1
  •  3
  •   John Bollinger    2 年前

    在这里

      char *itemA = SDL_malloc(sizeof(char) * 12);
      char *itemB = SDL_malloc(sizeof(char) * 11);
    

    …为两个数组分配内存 char ,并将指向这些已分配空间的指针存储在 itemA itemB

    在这里

      itemA = "Hello World";
      itemB = "What's Up?";
    

    代替 指向已分配空间的指针与指向字符串文字的指针(泄漏已分配内存)。这些确实不是动态分配的。当你试图释放其中一人时,这个系统完全有理由抱怨。

    您可能希望将数据复制到分配的块中,而不是将项目指向不同的对象。这将是:

      strcpy(itemA, "Hello World");
      strcpy(itemB, "What's Up?");