函数不能返回局部指针变量
2013-07-26 12:06
246 查看
转自:http://blog.csdn.net/snakewarhead/article/details/8046673
声明自动指针变量时,编译器为其在堆栈区分配内存,如果在函数中将另外一个自动变量的地址赋值给自动指针变量,在函数调用完毕后,指向堆栈区的栈顶指针将移动到调用此函数之前的地址位置,从而使自动变量失去意义,返回的失去意义的地址将会使程序不稳定。
函数返回指针。本来就是一个比较容易出问题的操作。在霍顿的《VC++ 入门经典》一书中,给出了一个很有代表性的例子,如下:
[cpp] view
plaincopy
// Ex5_11.cpp
#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 - mark 1
double* treble(double da
ta)
{
double result = 0.0;
result = 3.0*da
ta;
return &result;
}
两个输出语句,一个直接输出3*5=15.另一个在一个函数中进行了乘法运算,也是5*3,存到result变量中也没有任何问题。返回这个变量的指针,输出时再接触引用。貌似也没有错误。两条输出语句似乎都应该输出15.但事实不是这样。编译器会抛出[Warning] address of local variable `result' returned 这样一个警告信息。程序运行后的结果也并非是我们预想的那样。第二条输出语句会输出一个不可预见的值。这是怎么回事呢?
仔细分析一下,result是作用域在treble函数中的局部变量。当函数执行结束后。变量result会被析构。其原先占用的内存区域已经被系统回收,可以存储任何数据。而返回的指向该地址的指针也失去了其原有的意义。因此我们得到这样一条准则:
永远不要从函数中返回局部自动变量的地址。
如果你真的需要这样操作。你可以在函数的参数表中传入一个指针变量。然后将需要写入的数据写入到该指针变量指向的地址。由于该指针指向的变量,作用域在函数体之外。因此不会在函数结束结束时被回收。
现在回到我们遇到的问题。时间函数localtime就是一个返回指针的函数。返回值类型:tm*
该如何接收这个返回值?当然是声明一个与之类型相同的变量。
于是你会这样写:tm* result;
接下来呢?还用问?赋值嘛。是不是这样:result=localtime(....);
返回什么类型,当然要给什么类型的变量赋值。但是这样却发生了我们不想看到的结果。
也许你想到了。就是这个指针!返回的指针在函数结束后不再有效。正确的方法可以是:
tm result;
result = *localtime(....);
也可以是:
tm* result;
*result = *localtime(...);
正确的方法的共同特点是在函数结束前,对返回的指针解除引用。然后用这个数值,为变量或指针指向的内存区域赋值。也就是说必须要复制函数的返回值。因为函数体中变量会被析构。
指针是灵活而强大的,避免低级错误,明确基本概念。才能让指针更好的为我们服务
声明自动指针变量时,编译器为其在堆栈区分配内存,如果在函数中将另外一个自动变量的地址赋值给自动指针变量,在函数调用完毕后,指向堆栈区的栈顶指针将移动到调用此函数之前的地址位置,从而使自动变量失去意义,返回的失去意义的地址将会使程序不稳定。
函数返回指针。本来就是一个比较容易出问题的操作。在霍顿的《VC++ 入门经典》一书中,给出了一个很有代表性的例子,如下:
[cpp] view
plaincopy
// Ex5_11.cpp
#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 - mark 1
double* treble(double da
ta)
{
double result = 0.0;
result = 3.0*da
ta;
return &result;
}
两个输出语句,一个直接输出3*5=15.另一个在一个函数中进行了乘法运算,也是5*3,存到result变量中也没有任何问题。返回这个变量的指针,输出时再接触引用。貌似也没有错误。两条输出语句似乎都应该输出15.但事实不是这样。编译器会抛出[Warning] address of local variable `result' returned 这样一个警告信息。程序运行后的结果也并非是我们预想的那样。第二条输出语句会输出一个不可预见的值。这是怎么回事呢?
仔细分析一下,result是作用域在treble函数中的局部变量。当函数执行结束后。变量result会被析构。其原先占用的内存区域已经被系统回收,可以存储任何数据。而返回的指向该地址的指针也失去了其原有的意义。因此我们得到这样一条准则:
永远不要从函数中返回局部自动变量的地址。
如果你真的需要这样操作。你可以在函数的参数表中传入一个指针变量。然后将需要写入的数据写入到该指针变量指向的地址。由于该指针指向的变量,作用域在函数体之外。因此不会在函数结束结束时被回收。
现在回到我们遇到的问题。时间函数localtime就是一个返回指针的函数。返回值类型:tm*
该如何接收这个返回值?当然是声明一个与之类型相同的变量。
于是你会这样写:tm* result;
接下来呢?还用问?赋值嘛。是不是这样:result=localtime(....);
返回什么类型,当然要给什么类型的变量赋值。但是这样却发生了我们不想看到的结果。
也许你想到了。就是这个指针!返回的指针在函数结束后不再有效。正确的方法可以是:
tm result;
result = *localtime(....);
也可以是:
tm* result;
*result = *localtime(...);
正确的方法的共同特点是在函数结束前,对返回的指针解除引用。然后用这个数值,为变量或指针指向的内存区域赋值。也就是说必须要复制函数的返回值。因为函数体中变量会被析构。
指针是灵活而强大的,避免低级错误,明确基本概念。才能让指针更好的为我们服务
相关文章推荐
- C++函数返回局部变量指针的问题
- effective C++笔记之条款31、32: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针所指对象的引用、尽可能地推迟变量的定义
- 返回指向局部变量指针的函数 与 返回局部变量引用的函数
- C指针以及为什么不能返回局部指针变量,却可以返回局部变量
- C语言学习7 :二级指针定义,强制转换,多级指针初步,6级指针构造,错误应用*p=&a,错误应用 二级p2,void型指针的兼容性,malloc函数基本用法,malloc分配空间和堆栈空间的区别,验证malloc函数内存的分配,验证malloc函数的越界,内存泄漏,指针不能返回局部变量地址,内存分配
- C++函数返回局部变量指针的问题
- C指针以及为什么不能返回局部指针变量,却可以返回局部变量
- C/C++ 子函数返回局部变量、指针 和改变指针指向
- c语言中函数返回局部变量的指针(一些容易犯错的地方)
- 关于函数不能返回局部对象的引用或者局部对象的指针
- 返回函数局部变量的指针和引用
- 为什么在函数中不能通过指针返回本地定义的变量
- 杜绝返回函数内局部变量的指针或引用
- 返回指向局部变量的指针或引用的带来的问题讨论
- 条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用 (转自effective c++ second edition)
- C++ 从函数返回指针(函数外返回局部静态变量的地址)
- c++函数返回局部变量
- Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题
- C语言的那些秘密之--函数返回局部变量
- 蚊子132 C++中函数局部变量指针是如何释放的呢?