c++返回局部变量的指针

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:55   2054   0

1、函数返回指针比较容易出错,有例为证:

#include <iostream>
using std::cout;
using std::endl;
double* treble(double); // Function prototype
int main(void)
{
double num = 5.0; // Test value
double* ptr = 0; // Pointer to returned value
ptr = treble(num);
cout << endl<< "Three times num = " << 3.0*num;
cout << endl<< "Result = " << *ptr; // Display 3*num
cout << endl;
system("pause");
return 0;
}
// Function to treble a value
double* treble(double data)

{ double result = 0.0;result = 3.0*data; return &result; }


两个输出语句,一个直接输出3*5=15。另一个在一个函数中进行了乘法运算,也是5*3, 存到result变量中也没有任何问题。返回这个变量的指针,输出时再接触引用。貌似也没有错误。两条输出语句似乎都应该输出15.但事实不是这样。编译 器会抛出[Warning] address of local variable `result' returned 这样一个警告信息,在VS中会给出一串长地址。程序运行后的结果也并非是我们预想的那样。第二条输出语句会输出一个不可预见的值。这是怎么回事呢?仔细分析一下,result是作用域在treble函数中的局部变量。当函数执行结束后。变量result会被析构。其原先占用的内存区域已经被系统回收,可以存储任何数据。而返回的指向该地址的指针也失去了其原有的意义。
因此我们得到这样一条准则:永远不要从函数中返回局部自动变量的地址。如果你真的需要这样操作。你可以在函数的参数表中传入一个指针变量。然后将需要写入的数据写入到该指针变量指向的地址。由于该指针指向的变量,作用域在函数体之外。因此不会在函数结束结束时被回收。

#include <iostream>
using std::cout;
using std::endl;
double *treble1(double data,double *result); // Function prototype
double *treble2(double data);
double result=0.0;
int main(void)
{

double num; num= 5.0; // Test value
cout << endl<< "Three times num = " << 3.0*num;
cout << endl<< "Result = " << result; // Display 3*num

double* ptr = 0; // Pointer to returned value
ptr =treble1(num,&result);
cout << endl<< "ptr = " << *ptr;
cout << endl<< "ptr = " << *ptr;

double test1;
test1= *treble2(num);
cout << endl<< "test1 = " << test1;
cout << endl<< "test1 = " << test1;

//double *test2;
//*test2=*treble2(num);
//cout << endl<< "test2 = " << test2;
//cout << endl<< "test2 = " << test2;//这样会报错!!

//test2= treble2(num);
//cout << endl<< "test2 = " << test2;
//cout << endl<< "test2 = " << test2;//两个返回的都是地址


system("pause");

return 0;

}


// Function to treble a value 
double *treble1(double data,double *result)
{

*result=3.0*data;
return result;
}



double *treble2(double data)
{

double result = 0.0;
result = 3.0*data;
return &result;

}

分析:正确的方法的共同特点是在函数结束前,对返回的指针解除引用。然后用这个数值,为变量或指针指向的内存区域赋值。也就是说必须要复制函数的返回值。因为函数体中变量会被析构。
运行结果:

2、结合字符数组理解局部变量指针

/*test1.c*/

#include <stdio.h>
char* get_str()
{
    char str[] = {"hello"};
    return str;
}
int main()
{
    char* p = get_str();
    printf("%s/n", p);
    return 0;
}

 
/*test2.c*/

#include <stdio.h>
char* get_str()
{
    char *str = {"hello"};
    return str;
}
int main()
{
    char* p = get_str();
    printf("%s\n", p);
    return 0;
}

 


test2.c运行没有问题,也可以打印出正确的值,而test1.c却是错误的,打印出来的值和预期的完全不一样。他们都是返回了局部变量的指针,为什么会有差异呢,我们仔细看代码,发现他们只有一个地方不一样,那就是test1.c 里面str是一个数组,test2.c里面str是一个指针。原因就在这,str指针,其值是一个常量,而常量是放在数据段里面的,即便函数返回了,数据段里面的常量数据也还会在,直到程序结束才会消失,所以我们可以打印出来。

而对于数组来说,它是一个局部变量,是放在栈里面的,函数返回之后,str指向的空间还是在的,如果我们打印出它的地址还是没有变。那么为什么内容会变掉呢,难道是系统会把栈中的数据清除,答案是否定的,因为这样做会消耗系统的资源,而且没有任何好处,下次用到这块内存还是会进行初始化的。打印出来的内容变掉是因为printf本身也是一个函数,也会进行参数的压栈,在压栈的过程中会把原来str指向的空间覆盖掉,也就改变了其中的值。如果我们在get_str之后,不调用任何函数并不创建新的局部变量(严格的说是不使栈继续往下增长),这个时候p指向的内容还是没变的。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP