我遇到了带有字符串函数的内存分配的奇怪行为。
注意:现在,我被告知要忽略分配操作的失败。
我的代码是:
void string_reallocation(char *result, int result_length) {
char *temp_result = malloc((strlen(result) + 1) * sizeof(char));
strcpy(temp_result, result);
realloc(result, (result_length + 1) * sizeof(char));
strcpy(result, temp_result);
free(temp_result);
}
此函数在while循环内通过迭代调用:
while (current_node != NULL) {
current_value_to_string = current_node->toStringFunc(current_node->value);
current_value_length = (int) strlen(current_value_to_string);
current_length += current_value_length + arrow_length;
string_reallocation(result, current_length);
strcat(result, current_value_to_string);
strcat(result, arrow);
current_node = current_node->next;
}
current_node
的节点类型如下:
typedef struct t_node {
Element value;
struct t_node *next;
elementDestroy destroyFunc;
elementCopy copyFunc;
elementToString toStringFunc;
} *Node;
出于某种原因,尤其是在第三次迭代中,free(temp_result);
因分段错误而失败。
我不认为while循环与分段错误有任何关系,但我将其放在此处以防万一。
答案 0 :(得分:2)
这是一个双相解决方案,因为您需要通过检查realloc()
的原型来了解其用法。让我们先做吧。
更改此:
realloc(result, (result_length + 1) * sizeof(char));
对此:
result = realloc(result, (result_length + 1) * sizeof(char));
自reference起,我们获得了该方法的原型:
返回值:指向重新分配的内存块的指针,该指针可能是 与ptr相同或位于新位置。
现在,考虑一下变量(指针)的范围。正如@whozCraig所说,result =
(在更正的realloc()
中)为自动变量分配了一个值。传递给调用方的原始结果保持不变,现在悬而未决。这必须使用in / out arg或函数返回结果来处理。
因此,您可以做的就是通过更改此代码来简单地返回该指针:
void string_reallocation(char *result, int result_length) {
对此:
char* string_reallocation(char *result, int result_length) {
// ...
return result;
}
,然后将对此函数的调用更改为:
result = string_reallocation(result, current_length);
答案 1 :(得分:0)
您的代码中存在两个重大问题:
realloc
通话的结果。此外,解决这些问题后,还有一个重要的体系结构问题。
string_reallocation
吗? 保留realloc
重新分配的结果将被忽略。 realloc
是一个请求,要求获取一个(可能为NULL)先前动态分配的内存区域并对其进行扩展或收缩。结果 可能会导致隐藏的新分配丢失,realloc
然后将旧的内存复制到新的内存中,解除旧的内存分配,最后返回指向新的内存的指针。您应该始终假定会发生这种情况。
因此,realloc
的结果势在必行,必须保留。
result = realloc(result, result_length + 1);
注意:这不是最佳实践,因为realloc
可能会失败,但是由于您是教师可疑的指导,所以我们假设分配成功。
将realloc
结果返回给呼叫者
由于realloc
可能会导致出现一个新的内存区域,这意味着该指针的值可能会更改。但是,即使使用上面的修复程序来保留result
,您实际上也没有将其返回给调用方。
result = ...
对传递给该函数的调用者指针无任何作用。因此,一旦将该区域替换为新区域,就会发生两次灾难:(1)调用方留下了悬空的指针,(2)引入了新分配区域的内存泄漏。
要解决此问题,我们需要将指针返回给调用者。最明显的解决方案是仅使用否则会无用的函数结果。更改函数声明以返回char *
,如下所示:
// HERE: changed result type
char *string_reallocation(char *result, int result_length)
{
char *temp_result = malloc((strlen(result) + 1) * sizeof(char));
strcpy(temp_result, result);
result = realloc(result, (result_length + 1) * sizeof(char));
strcpy(result, temp_result);
free(temp_result);
return result; // HERE: returned new region pointer
}
并更改呼叫者:
result = string_reallocation(result, current_length);
但是等等。还有更多。
甚至还需要string_reallocation
?
还记得我在这开始时所说的话吗? realloc
将根据需要分配一个新的内存块,将旧块的大小内容复制到新的,然后释放旧块并返回生成的新块指针。>
这意味着您的字符串复制操作(包括malloc
的临时空间)是realloc
已经为您完成的重复工作。换句话说,整个功能可以简化为:
char *string_reallocation(char *result, int result_length)
{
result = realloc(result, result_length + 1);
return result;
}
因此,使该功能完全毫无意义。您可以自己在呼叫者那边做那个,完全摆脱string_reallocation
:
while (current_node != NULL) {
current_value_to_string = current_node->toStringFunc(current_node->value);
current_value_length = (int) strlen(current_value_to_string);
current_length += current_value_length + arrow_length;
result = realloc(result, current_length + 1);
strcat(result, current_value_to_string);
strcat(result, arrow);
current_node = current_node->next;
}
当然,我们看不到整个图片。我不知道result
在此循环之前最初所指的是什么,这将留给您自己弄清楚。此外,我不禁要问toStringFunc
操作实际上是做什么的(如果它是动态分配的,那是导致内存泄漏的原因)。无论如何,这应该可以解决您遇到的扩展问题。