free() on char* 被 valgrind 识别为无效

free() on char* recognized as invalid by valgrind

提问人:smellyourbooks 提问时间:8/4/2023 更新时间:8/5/2023 访问量:91

问:

我正在尝试释放存在于 char** 数组中的 char* 指针,但 valgrind 将此操作确定为无效。

这是我正在做的事情的一个简单例子:

struct building{
  int propertyPrice;
  int totalArea;
  char** floors;
}

int main(){

  struct building* B = malloc(sizeof(struct building));

  for(size_t i=0;i<10;i++)
    B->floors[i] = malloc(20 * sizeof(char*));

}

这是我感到困惑的地方 - 我可以通过以下循环访问元素:

for(size_t i=0;i<10;i++)
    printf("%s", B->floors[i]); //assume that a valid string exists at each floors[i]!

我正在尝试释放分配的内存,如下所示:

for(size_t i=0;i<10;i++)
    free(B->floors[i]);

free(B);

请原谅缺少针对 NULL 的 malloc() 检查,为了简洁起见,我将其删掉了。

Valgrind 确定操作是 。然而,如果我可以通过访问单个 char* 元素,我是否应该能够使用相同的语法通过简单地将函数调用从 to 切换出来释放它(我从这个 stackoverflow 答案中得到了这个想法)?free(B->floors[i])Invalid free() / delete / delete[] / realloc()B-floors[i]printf()free()

第二个调用工作正常。free()

我的程序按预期执行,但我想摆脱内存泄漏 - 因此使用了 valgrind。如果有帮助,我在执行 valgrind 时使用 gcc 的开关和参数。-Werror -ggdb--track-origins=yes --leak-check=full

C 指针 Malloc Valgrind 免费

评论

2赞 Some programmer dude 8/4/2023
B->floors是一个指针,但你永远不会让它指向任何地方。您需要例如 在循环之前。当然,一旦你完成了它(在循环释放每个元素之后)。B->floors = malloc(10 * sizeof *B->floors)free(B->floors)
0赞 Ian Abbott 8/5/2023
也可以定义为灵活的数组成员,并扩展 的分配以合并所需数量的元素: 。floorschar *floors[];Bstruct building *B = malloc(sizeof(*B) + 10 * sizeof(B->floors[0]));

答:

5赞 David Ranieri 8/5/2023 #1

这里:

for(size_t i=0;i<10;i++)
    B->floors[i] = malloc(20 * sizeof(char*));

B->floors在未初始化的情况下使用。

您需要为 10 个元素预留空间:

B->floors = malloc(10 * sizeof(char*));

然后,您可以填充锯齿状数组:

for (int i = 0; i < 10; i++) {
    B->floors[i] = strdup(...); // or malloc + memcpy if strdup is not available
}

最后:

for (int i = 0; i < 10; i++) {
    free(B->floors[i]);
}
free(B->floors);

由于是数组的最后一个成员,因此可以将其用作“灵活数组成员”:floors

struct building* B = malloc(sizeof(struct building) + (sizeof(char *) * 10));

在这种情况下,您不会在最后打电话。free(B->floors);

评论

0赞 Andrew Henle 8/5/2023
这只会得到一个包含 20 个指针的未初始化数组。我怀疑这还不是全部需要的,但这个问题是不完整的......char *
0赞 smellyourbooks 8/5/2023
虽然这处理了堆分配,但如果我现在不初始化嵌入的 char* 指针,valgrind 会抱怨这个和这个.这就是我最初使用 malloc 循环并将嵌入的 char* 指针设置为默认值的原因。Conditional jump or move depends on uninitialised value(s)Uninitialised value was created by a heap allocation
0赞 David Ranieri 8/5/2023
@AndrewHenle每个指针都需要指向堆栈上的某个有效地址或保留 or + 当然,我假设 OP 知道这一点,但无论如何都进行了编辑。strdupmallocmemcpy
0赞 0___________ 8/5/2023
@DavidRanieri为什么在堆栈上?
1赞 smellyourbooks 8/5/2023
我只想得出结论,这个答案是完美的。事实证明,当我应该在导致内存问题的内部函数中使用时,我正在通过运算符分配 char* 指针值。谢谢@DavidRanieri的所有帮助!=memcpy