C/C++中函数返回局部变量的问题

本文探讨了C语言中返回局部变量可能导致的问题,并通过实例分析了不同解决方案的特点,包括使用字符串常量、全局数组、静态数组等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


       阅读《C专家编程》中,描述一个Sun的Pascal编译器出现的Bug——编译器日期被破坏。这个Bug点出C/C++中的函数返回局部变量可能存在的问题:

       1、如果函数返回的是局部变量的值,程序不会出现问题;

       2、如果函数返回的是局部变量的指针(地址),可能会出现问题


书中给出的代码如下:

<span style="font-size:14px;">char * localized_time(char *filename)
{
	struct tm *tm_ptr;
	struct stat stat_block;
	char buffer[120];

	stat(filename,&stat_block);
	tm_ptr=localtime(&stat_block.st_mtime);
	strftime(buffer,sizeof(buffer),"%a %b %e %T %Y",tm_ptr);
	return buffer;
}</span>

 然而,在实际的编译(32bit-Win7+VS2008环境)中,会出现问题,可能是Windows和Unix之间的差异,具体留后面讨论。


书中讲到:在C语言中,自动变量在堆栈中分配内存。当包含自动变量的函数或代码块退出时,它们所占用的内存便被回收,它们的内容肯定会被下一个所调用的函数覆盖。这一切取决于堆栈中先前的自动变量位于何处,活动函数声明了什么变量,写入了什么内容等。原先自动变量地址的内容可能被立即覆盖,也可能稍后才被覆盖。


        解决方案如下几种:

              1、返回一个指向字符串常量的指针。(此方案太过于局限)

              2、使用全局声明的数组。

                                 

<span style="font-size:14px;">char *func()
{
	...
	global_array[i]=
	...
	return global_array;
}</span>

                 缺点:<1>、任何人都有可能在任何时刻修改这个全局数组;

                            <2>、该函数的下一次调用也会覆盖该数组的内容;

                            <3>、浪费内存空间(尤其是数组比较大的情况)。


        3、使用静态数组。

char *func()
{
	static char buffer[20];
	...
	return buffer;
}

                优点:可以防止任何人修改该数组,只有拥有指向该数组的指针的函数才能修改该静态数组(通过参数传递)。

                缺点:<1>、该函数的下一次调用也会覆盖该数组的内容;

                           <2>、浪费内存空间(尤其是数组比较大的情况)。


         4、显示分配一些内存,保存返回的值。

char *func()
{
	char *s =malloc(120);
	...
	return s;
}

               优点: <1>、可以防止任何人修改该数据,且该函数在下次被调用不会覆盖以前的返回值;

                          <2>、适用于多线程的代码。

               缺点:需要承担内存管理的工作,容易产生内存泄漏。


        5、出参的方式返回数组,由调用者管理内存分配与回收(推荐)

void func(char *result,int size)
{
	strncpy(result,"just for test",size);
}

buffer =malloc(size);
func(buffer,size);
...
free(buffer);

        最好在同一代码块同时进行“malloc”和“free”操作,遵循谁分配,谁释放的原则。



        好了,分享了作者的阐述,下面是我的通过编译的测试代码。

#include "stdafx.h"
#include <time.h> 
#include <sys/stat.h>
#include <string.h>
char * localized_time(char *filename)
{
	struct tm *tm_ptr;
	struct stat stat_block;
	char buffer[120];

	stat(filename,&stat_block);
	tm_ptr=localtime(&stat_block.st_mtime);
	int iErrorCode=strftime(buffer,sizeof(buffer),"%a %b %Y  %c ",tm_ptr);
	printf("strftime:%s\n",buffer);
	return buffer;
}
 int main(void)
{
	char *szFileName="test.cpp";
	printf("return :%s\n",localized_time(szFileName));
	return 0;
}

遇到两个问题:

1、书中给出的代码段:strftime(buffer,sizeof(buffer),"%a %b %e %T %Y",tm_ptr);运行是产生崩溃。

       原因是strftmie.c第832行抛出异常,_ASSERTE( ( "Invalid format directive" , 0 ) );

       结合strftmie.c中的源代码及MSDN。是因为strftime()函数没有“%e和%T”,这里可能是Windows和Unix的差异?没有深究。


2、运行上述修改过的代码后,发现:

            <1>、调用函数可以打印出正确的返回值;

            <2>、如果把buffer[120]改为buffer[90],调用函数可以打印出正确返回值的一部分+乱码;

            <3>、如果把buffer[120]改为buffer[90],调用函数打印的结果为空;

            <4>、注释掉 “printf("strftime:%s\n",buffer);”,调用函数打印的结果为乱码。

      这也印证了 如果函数返回的是局部变量的指针(地址),可能会出现问题。




           ZhaiPillary   

    2015/05/21  于上海

    博客地址:http://blog.youkuaiyun.com/pillary















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值