函数返回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]
放入的内存内容仍然是buff
或ptr
(自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()。 您的解决方案不是接近定义的行为。
我建议两种可能的解决方案:
-
在
f1
使用静态char buff[20]
,除非从多个线程调用该函数或外部世界将指针存储在strcpy之外。 -
使用
return strdup (ptr);
并将指针free
到f1
之外。 这比malloc
更容易使用(虽然技术上相同)。 它比1.慢,但线程安全。
我建议更改这些函数以获取它使用的指针
void f1(char *)
这样,调用函数的每一段代码都必须决定内存写入的位置,并删除任何已分配的内存。