在这个问题中,我指的是另一个stackoverflow问题,因为我没有足够的分数来评论它。
参见:Valgrind Reports Invalid Realloc
简而言之:为什么指令buffer = trim(buffer);
必须写在函数之外?为什么不能在函数内部写成phrase = (char*)realloc(phrase, strlen(phrase)+1);
呢?
深度:假设我将任何指针传递给一个函数-例如const *str;
-然后通过执行str++;
,我可以创建一个副作用并改变字符串的起始位置。
但是为什么我不能通过动态内存管理函数(如malloc
和realloc
)为函数重新分配另一个值呢?
为什么不能直接设置str = (char*) realloc(str, strlen(str) + 1 * sizeof(char));
?
是什么使这种副作用与另一种不同?假设我不能把str
移动到我想去的地方吗?
C passall按值的参数。查看被调用函数的形参,就像该函数的局部变量一样,由调用者给出的实参的副本初始化。
我们可以"仿真"如果传递指针,则按引用传递。通过对指针解引用,可以访问"被引用"的对象。位于被调用函数之外的对象。但是这个指针仍然是按值传递的,这意味着它是实参的副本,初始化了形参。
注意:c++和其他语言的引用实际上就是指针。不过,还有一些额外的语义。您可能需要查看生成的机器码。
所以你可以对参数中的指针做任何你想做的事情,覆盖它,自增或自减,甚至NULL
它。这对调用方指针的来源没有影响。
你所链接的问题的问题可以归结为:
char* called(char* pointer)
{
return realloc(pointer, /* some irrelevant value */);
}
void caller(void)
{
char* buffer = malloc(/* some irrelevant value */);
/* ignore returned pointer */ called(buffer);
free(buffer); /* here Valgrind reports an error */
}
我们需要在这里区分realloc()
的多种情况。
realloc()
返回NULL
,因为没有足够的内存满足请求。原地址仍然有效。realloc()
返回相同的地址,因为这样可以满足请求。由于返回地址和前地址相等,因此两者都有效。realloc()
返回新地址。原来的地址现在无效。
其中,第三种情况是最常见的,它导致了文档中的问题。
因为caller()
中的buffer
没有被called()
改变,仅仅是因为called()
无法访问它,所以它仍然保留前一个地址。现在,当使用这个无效地址调用free()
时,会检测到错误。
要纠正这个错误,caller()
需要使用返回值。正确的方法TM是:
void caller(void)
{
char* buffer = malloc(/* some irrelevant value */);
char* new_buffer = called(buffer);
if (new_buffer != NULL) {
buffer = new_buffer;
} else {
/* handle the re-allocation error, the address in buffer is still valid */
}
free(buffer);
}
另一种方法是将指向buffer
的指针传递给called()
,并让它正确地修改buffer
。但是这种类型的重定向通常会生成可读性较差的代码。但是,为了方便起见,您可能会决定走这条路。