为什么我可以重新定位一个作为函数参数的指针,但不能在'realloc'后重新给它赋值?

z6psavjg  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(90)

在这个问题中,我指的是另一个堆栈溢出问题,因为我没有足够的点来评论它。
请参阅:Valgrind Reports Invalid Realloc

**简而言之:**为什么指令buffer = trim(buffer);必须写在函数外部?为什么不能写在函数内部,如phrase = (char*)realloc(phrase, strlen(phrase)+1);
**深度:**假设我传递任何指向函数的指针--比如const *str;--那么通过执行str++;,我可以创建一个副作用,并改变字符串的起始位置。

但是,为什么不能通过动态内存管理函数(如mallocrealloc)为函数重新分配另一个值呢?
为什么不能直接设置str = (char*) realloc(str, strlen(str) + 1 * sizeof(char));
这个副作用和另一个副作用有什么不同呢?难道我不能假设把str移动到我想移动的地方吗?

lf5gs5x2

lf5gs5x21#

C通过传值传递所有参数。看一下被调用函数的参数,就像这个函数的局部变量,由调用者给出的参数的副本初始化。
如果我们传递一个指针,我们可以“模拟”通过引用传递。通过解引用指针,我们可以访问位于被调用函数之外的“被引用”对象。但是这个指针仍然是通过值传递的,这意味着它是参数的副本,初始化参数。

  • 注意: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()的多种情况。

  1. realloc()返回NULL,因为没有足够的内存来满足请求。以前的地址仍然有效。
  2. realloc()返回相同的地址,因为这样可以满足请求,由于返回的地址与前一个地址相等,所以都有效。
  3. realloc()返回一个新地址。以前的地址现在无效。
    其中,第三种情况是常见的,它导致了记录的问题。
    因为caller()中的buffer没有被called()改变,仅仅是因为called()不能访问它,它仍然保存着以前的地址。现在当用这个无效地址调用free()时,错误被检测到。
    要更正此错误,caller()需要使用返回值。执行此操作的正确方法是:
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);
}

另一种方法是将 pointer to buffer 传递给called(),让它正确地修改buffer。但是这种类型的重定向通常会生成可读性较差的代码。然而,为了方便函数,您可能会决定采用这种方法。

相关问题