函数返回char指针

时间:2010-02-26 12:42:42

标签: c memory-management

我遇到了很多函数在一个遗留应用程序中返回char指针。 其中一些返回指向本地字符数组的指针。在几次调用(不是立即!)后,它似乎导致崩溃,请参阅下面的用法

char *f1(){
  char buff[20];
  char *ptr;

  ----
  ----
  ptr=buff;
 return ptr;
}

---
---

f2(f1());

f1()返回一个指针局部变量,然后将其传递给另一个函数。当我在MS DEV中使用_DEBUG模式编译时,我直接崩溃了。但是在发布模式下,它不会导致立即崩溃,但在进行大量此类调用后可能会发生这种情况。

当我修改下面的用法时,它没有任何问题。是以下用法 安全

strcpy(arr,f1()); /* arr is fixed char array*/
f2(arr);

12 个答案:

答案 0 :(得分:12)

不,这是未定义的行为。它恰好适用于您的情况,但可能随时停止工作。

答案 1 :(得分:3)

不,这不安全。只是调用strcpy可以修改堆栈足以导致以后出现问题,因为返回地址和参数可能会覆盖数组。

答案 2 :(得分:3)

除了使用后内存应该是免费的,malloc解决方案很有意思。 (功能之外)。否则会有内存泄漏。

答案 3 :(得分:2)

f1函数返回一个临时(buff)函数,该函数在函数返回时被释放。你需要在函数中使用malloc()。

答案 4 :(得分:2)

永远不要返回指向局部变量的指针。它可能在某些情况下有效,但一般情况下你会遇到很多问题。 代替:

  • 记录你的函数,它返回一个指向已分配内存的指针,并且返回的缓冲区必须由调用者释放
  • 添加一个缓冲区和一个size参数,并填入缓冲区(这通常是在Win32 API中完成的)
  • 如果使用C ++,请使用std :: string

答案 5 :(得分:2)

  

以下用法是否安全?

没有

如果你的函数返回一个指向任何东西的指针,请确保它分配一个内存区域并返回指向它的指针:

char *safe_f1(void) {
    char *ptr;
    ptr = (char *) malloc(20 * sizeof(char));
    ...
    return ptr;
}

答案 6 :(得分:2)

这不安全。原因很简单:

函数上的任何变量都将在函数返回后释放内存的堆栈上分配。释放内存的事实并不意味着内容被更改。

这意味着您放入变量char buff[20]的内存内容仍然位于buffptr(自ptr=buff)内存位置。无论何时调用另一个函数(或执行另一个块),它的函数/块变量也会进入堆栈,从而可以更改位置ptr所指向的内存内容。

在您编写的strcpy示例中,您很幸运,strcpy函数变量未在堆栈中位于旧buff数组内的位置。这就是你得到它安全的印象的原因。

结论是,你无法真正保证堆栈中释放的内存内容不会在两个函数调用之间发生变化。

解决方案是使用malloc,因为malloc不会在堆栈上分配内存,而是在堆上分配内存。除非您选择这样做(通过免费通话),否则不会释放堆内存。

这种方法可以保证ptr指向的内存可以安全地被任何其他函数使用。

这个解决方案的缺点是内在的:一旦内存没有被解除分配,除非你以编程方式执行此操作,如果您忘记释放此内存并丢失ptr的内容,则此内存将存在,为您分配程序但永远无法实现,只要程序运行就会丢失。这个内存将成为内存泄漏: - )

这就是为什么有些语言有垃圾收集器的原因之一......但这是另一个故事: - )

PS:我认为它是安全的(如果你的程序是单线程的),虽然我不建议,做类似的事情:

{
  char safe_buffer[20];
  char *unsafe_ptr;
  int i;
  unsafe_ptr = f1();
  /*Copy the buffer without calling any function
    not to change the stack content
  */
  for(i=0;i<20 && *(unsafe_ptr + i) != 0;i++)
  {
    *(safe_buffer + i) = *(unsafe_ptr + i);
  }
  *(safe_buffer + i) = 0;
  f2(safe_buffer);
}

答案 7 :(得分:1)

不......还是不安全。

当你执行strcpy(arr,f1());时,用作第二个参数的指针已经指向一个不存在的数组。

答案 8 :(得分:1)

不,您看到buff[20]仅在f1功能中可用。确切地说,内存分配在f1堆栈上。

您需要使用buff[20]在堆上创建新的malloc,并从f1内部返回指向该内存的指针。另一种方法是在f1之外创建buff[20](来自调用f1的函数)并将其作为参数发送到f1f1然后可以更改缓冲区的内容,甚至不必返回它。

答案 9 :(得分:0)

实际上,最好的方法是修改f1()以使用malloc()。您的解决方案并未接近定义的行为。

答案 10 :(得分:0)

我建议两种可能的解决方案:

  1. char buff[20]中使用静态f1,除非从多个线程调用该函数或外部世界将指针存储在strcpy之外。

  2. return strdup (ptr);外使用freef1指针。这比malloc更容易使用(虽然技术上相同)。它比1.慢,但线程安全。

答案 11 :(得分:0)

我建议更改这些函数以获取它使用的指针

void f1(char *)

这样,调用函数的每一段代码都必须决定内存的写入位置,并删除任何已分配的内存。