函数返回char指针

我遇到了很多函数在一个遗留应用程序中返回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); 

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

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

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

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

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

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

以下用法是否安全?

没有。

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

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

这不安全。 原因很简单:

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

这意味着你在变量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); } 

不,还是不安全。

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

不,你看到buff[20]仅在f1函数内可用。 确切地说,内存分配在f1的堆栈上。

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

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

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

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

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

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

 void f1(char *) 

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