You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

排查C语言中‘pointer being freed was not allocated’错误

问题分析:释放未分配指针错误原因及修复

问题描述

我自行实现了一个哈希表(map),采用SDL内存函数替代标准malloc/free。当前遇到的问题是:第一次调用Map_Set可以正常工作,但使用相同键再次调用时,本该释放旧值并存储新值,却触发了pointer being freed was not allocated错误。我明明做了内存分配,不清楚错误出在哪里。

错误输出

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. 字符串字面量覆盖堆指针(直接触发错误)

在main.c中,你先通过SDL_malloc为itemA和itemB分配了堆内存,但随后直接将字符串字面量(如"Hello World")赋值给这两个指针。字符串字面量存储在只读数据段,不属于堆内存,当你调用SDL_free释放它们时,必然触发“释放未分配指针”的错误。同时,之前SDL_malloc分配的堆内存也会丢失,造成内存泄漏。

修复:
用SDL_strlcpy将字符串字面量复制到堆分配的内存中,而非直接赋值指针:

char *itemA = SDL_malloc(sizeof(char) * 12);
char *itemB = SDL_malloc(sizeof(char) * 11);
SDL_strlcpy(itemA, "Hello World", 12);
SDL_strlcpy(itemB, "What's Up?", 11);

2. Map_Create中的内存分配隐患

你在Map_Create中使用SDL_malloc(sizeof(Map)),若Map是struct Map*的typedef,当前代码没问题;但如果是struct Map的直接typedef,就会只分配指针大小的内存,导致结构体数据越界。

修复:
显式指定分配struct Map的大小,避免歧义:

Map map = SDL_malloc(sizeof(struct Map));

3. 哈希函数初始值不合理

哈希函数初始值设为unsigned int hash = -1;,unsigned类型的-1会被解析为最大值,可能导致哈希值计算时溢出或分布不佳,影响哈希表性能。

修复:
改用常规的初始值0,并调整哈希计算逻辑:

static unsigned int _Map_Hash(const char *key) {
  unsigned int hash = 0;
  while (*key) {
    hash = hash * 31 + (unsigned char)*key;
    key += 1;
  }
  return hash;
}

内容的提问来源于stack exchange,提问作者Justin808

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:44:57