返回指针变量的函数

原文出自http://blog.chinaunix.net/uid-27411029-id-3497902.html

  1. 原文自http://blog.chinaunix.net/uid-15014334-id-3533931.html  
原文自http://blog.chinaunix.net/uid-15014334-id-3533931.html
  1. 一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错。但是如果返回的是局部变量的地址(指针)的话,程序运行后会出错。因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错。准确的来说,函数不能通过返回指向栈内存的指针(注意这里指的是栈,返回指向堆内存的指针是可以的)。  
  2. 1. 返回局部变量的值  
  3.   
  4. 可以有两种情况:返回局部自动变量和局部静态变量,比如,  
  5.   
  6. int func()  
  7. {  
  8.     int temp = 0;   // 返回局部自动变量的值  
  9.     return temp;  
  10. }  
  11.   
  12. 局部变量temp存储在栈中,函数返回时会自动复制一份temp的copy给调用者,没有问题。  
  13.   
  14. int func()  
  15. {  
  16.     static int a = 1;   // 返回局部静态变量的值  
  17.     return a;  
  18. }  
  19. 局部变量a存储在静态(全局)存储区中,从初始化后一直有效直到程序结束,仅分配一次内存,并且函数返回后,变量不会销毁,没有问题。  
  20.   
  21. vector<int> func()  
  22. {  
  23.     vector<int> v;  
  24.     v.push_back(0);  
  25.     return v;  
  26. }  
  27.   
  28. 返回的是v的值拷贝,没有问题。  
  29.   
  30. Person func()  
  31. {  
  32.     Person p1;  
  33.     p1.name = "test";  
  34.     return p1;  
  35. }  
  36.   
  37. ?  
  38. 返回的也是值拷贝,会调用Person类的拷贝构造函数,没有问题。  
  39.   
  40. 2. 返回局部变量的指针  
  41.   
  42. int* func()  
  43. {  
  44.     int temp = 0;   // 返回局部变量的地址  
  45.     return &temp;  
  46. }  
  47.   
  48. ?  
  49. 前面讨论过,局部变量temp存储在栈中,函数返回时将已销毁变量的地址返回给调用者,结果将是不可预知的。  
  50.   
  51. int* func()  
  52. {  
  53.     static int temp = 1;  
  54.     return &temp;  
  55. }  
  56.   
  57. ?  
  58. 局部变量temp存储在静态存储区,返回指向静态存储区变量的指针是可行的。  
  59.   
  60. char* func()  
  61. {  
  62.     char *p = "test";  
  63.     return p;   // 返回指向常量字符串的指针  
  64. }  
  65.   
  66. ?  
  67. 对于字符串的特殊情况,由于字符串test存储在常量存储区(不是静态存储区),因此函数返回一个指向常量的字符串指针是可行的。  
  68.   
  69. char* func()  
  70. {  
  71.     char str[] = "test";  
  72.     return str; // 返回局部字符串的指针  
  73. }  
  74.   
  75. ?  
  76. 这种情况下,str被初始化为字符串局部变量,因此函数返回一个已销毁的局部变量是不可行的。解决办法就是将字符串str声明为static。  
  77.   
  78. char* func()  
  79. {  
  80.     char *str = (char *)malloc(sizeof(char) * BUFFER_SIZE);  
  81.     strcpy(str, "test");  
  82.     return str;  
  83. }  
  84.   
  85. ?  
  86. 这种情况下,函数返回一个指向堆内存的指针,由于堆存储区由程序员手动管理,因此这种做法是可行的,但是要防止出现内存泄露,函数调用完后需要手动释放内存。这里的sizeof作用于指针返回的是指针类型的长度1byte,而如果作用于数组返回的则是数组的长度。  
  87.   
  88. char *temp = NULL;  
  89. temp = func();  
  90. // some operation...  
  91. free(temp);  
  92.   
  93. ?  
  94. 3. 返回局部变量的引用  
  95.   
  96. int& func()  
  97. {  
  98.     int temp = 0;   // 返回局部变量的引用  
  99.     return temp;  
  100. }  
  101.   
  102. 由引用的概念可知,函数返回的是temp本身,而temp在函数返回后已销毁,结果将是不可预知的。  
  103.   
  104. 补充:静态全局变量和全局变量的区别  
  105.   
  106. 静态全局变量只在当前文件中可用,全局变量在其他文件中也可用,需要用extern声明。  
  107.   
  108. 全局变量和静态变量如果没有手动初始化,则默认由编译器初始化为0。  
  109.   
  110. 1:  
  111. [cpp] view plaincopy  
  112. #include <stdio.h>     
  113. char *returnStr()     
  114. {     
  115.     char *p="hello world!";     
  116.     return p;     
  117. }     
  118. int main()     
  119. {     
  120.     char *str;     
  121.     str=returnStr();     
  122.     printf("%s\n", str);     
  123.     return 0;     
  124. }    
  125. 这个没有任何问题,因为"hello world!"是一个字符串常量,存放在只读数据段,把该字符串常量存放的只读数据段的首地址赋值给了指针,所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。  
  126. 2:  
  127. [html] view plaincopy  
  128. #include <stdio.h>     
  129. char *returnStr()     
  130. {     
  131.     char p[]="hello world!";     
  132.     return p;     
  133. }     
  134. int main()     
  135. {     
  136.     char *str;     
  137.     str=returnStr();     
  138.     printf("%s\n", str);     
  139.     return 0;     
  140. }     
  141. "hello world!"是局部变量存放在栈中。当returnStr函数退出时,栈要清空,局部变量的内存也被清空了,所以这时的函数返回的是一个已被释放的内存地址,所以有可能打印出来的是乱码。   
  142. 3:  
  143. [html] view plaincopy  
  144. int func()    
  145. {    
  146.       int a;    
  147.       ....    
  148.       return a;    //允许    
  149. }                       
  150.     
  151. int * func()    
  152. {    
  153.       int a;    
  154.       ....    
  155.       return &a;    //无意义,不应该这样做    
  156. }     
  157. 局部变量也分局部自动变量和局部静态变量,由于a返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,  
  158. 因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量  
  159. 被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存  
  160. 期从定义起到程序结束。  
  161.   
  162. 4:如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。如下:  
  163. [html] view plaincopy  
  164. #include <stdio.h>     
  165. char *returnStr()     
  166. {     
  167.     static char p[]="hello world!";     
  168.     return p;     
  169. }     
  170. int main()     
  171. {     
  172.     char *str;     
  173.      str=returnStr();     
  174.     printf("%s\n", str);     
  175.     
  176.     return 0;     
  177. }     
  178. 5: 数组是不能作为函数的返回值的,原因是编译器把数组名认为是局部变量(数组)的地址。返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。如下:  
  179. [html] view plaincopy  
  180. int* func( void )    
  181. {    
  182.     static int a[10];    
  183.     ........    
  184.     return a;    
  185. }     
  186. 6:返回指向堆内存的指针是可以的  
  187. [html] view plaincop  
  188. char *GetMemory3(int num)    
  189. {    
  190. char *p = (char *)malloc(sizeof(char) * num);    
  191. return p;    
  192. }    
  193. void Test3(void)    
  194. {    
  195. char *str = NULL;    
  196. str = GetMemory3(100);    
  197. strcpy(str, "hello");    
  198. cout<< str << endl;    
  199. free(str);    
  200. }    
  201. 程序在运行的时候用 malloc 申请任意多少的内存,程序员自己负责在何时用 free释放内存。动态内存的生存期一直到程序员自己释放。  
一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错。但是如果返回的是局部变量的地址(指针)的话,程序运行后会出错。因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错。准确的来说,函数不能通过返回指向栈内存的指针(注意这里指的是栈,返回指向堆内存的指针是可以的)。
1. 返回局部变量的值

可以有两种情况:返回局部自动变量和局部静态变量,比如,

int func()
{
    int temp = 0;   // 返回局部自动变量的值
    return temp;
}

局部变量temp存储在栈中,函数返回时会自动复制一份temp的copy给调用者,没有问题。

int func()
{
    static int a = 1;   // 返回局部静态变量的值
    return a;
}
局部变量a存储在静态(全局)存储区中,从初始化后一直有效直到程序结束,仅分配一次内存,并且函数返回后,变量不会销毁,没有问题。

vector<int> func()
{
    vector<int> v;
    v.push_back(0);
    return v;
}

返回的是v的值拷贝,没有问题。

Person func()
{
    Person p1;
    p1.name = "test";
    return p1;
}

?
返回的也是值拷贝,会调用Person类的拷贝构造函数,没有问题。

2. 返回局部变量的指针

int* func()
{
    int temp = 0;   // 返回局部变量的地址
    return &temp;
}

?
前面讨论过,局部变量temp存储在栈中,函数返回时将已销毁变量的地址返回给调用者,结果将是不可预知的。

int* func()
{
    static int temp = 1;
    return &temp;
}

?
局部变量temp存储在静态存储区,返回指向静态存储区变量的指针是可行的。

char* func()
{
    char *p = "test";
    return p;   // 返回指向常量字符串的指针
}

?
对于字符串的特殊情况,由于字符串test存储在常量存储区(不是静态存储区),因此函数返回一个指向常量的字符串指针是可行的。

char* func()
{
    char str[] = "test";
    return str; // 返回局部字符串的指针
}

?
这种情况下,str被初始化为字符串局部变量,因此函数返回一个已销毁的局部变量是不可行的。解决办法就是将字符串str声明为static。

char* func()
{
    char *str = (char *)malloc(sizeof(char) * BUFFER_SIZE);
    strcpy(str, "test");
    return str;
}

?
这种情况下,函数返回一个指向堆内存的指针,由于堆存储区由程序员手动管理,因此这种做法是可行的,但是要防止出现内存泄露,函数调用完后需要手动释放内存。这里的sizeof作用于指针返回的是指针类型的长度1byte,而如果作用于数组返回的则是数组的长度。

char *temp = NULL;
temp = func();
// some operation...
free(temp);

?
3. 返回局部变量的引用

int& func()
{
    int temp = 0;   // 返回局部变量的引用
    return temp;
}

由引用的概念可知,函数返回的是temp本身,而temp在函数返回后已销毁,结果将是不可预知的。

补充:静态全局变量和全局变量的区别

静态全局变量只在当前文件中可用,全局变量在其他文件中也可用,需要用extern声明。

全局变量和静态变量如果没有手动初始化,则默认由编译器初始化为0。

1:
[cpp] view plaincopy
#include <stdio.h>   
char *returnStr()   
{   
    char *p="hello world!";   
    return p;   
}   
int main()   
{   
    char *str;   
    str=returnStr();   
    printf("%s\n", str);   
    return 0;   
}  
这个没有任何问题,因为"hello world!"是一个字符串常量,存放在只读数据段,把该字符串常量存放的只读数据段的首地址赋值给了指针,所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
2:
[html] view plaincopy
#include <stdio.h>   
char *returnStr()   
{   
    char p[]="hello world!";   
    return p;   
}   
int main()   
{   
    char *str;   
    str=returnStr();   
    printf("%s\n", str);   
    return 0;   
}   
"hello world!"是局部变量存放在栈中。当returnStr函数退出时,栈要清空,局部变量的内存也被清空了,所以这时的函数返回的是一个已被释放的内存地址,所以有可能打印出来的是乱码。 
3:
[html] view plaincopy
int func()  
{  
      int a;  
      ....  
      return a;    //允许  
}                     
  
int * func()  
{  
      int a;  
      ....  
      return &a;    //无意义,不应该这样做  
}   
局部变量也分局部自动变量和局部静态变量,由于a返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,
因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量
被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存
期从定义起到程序结束。

4:如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。如下:
[html] view plaincopy
#include <stdio.h>   
char *returnStr()   
{   
    static char p[]="hello world!";   
    return p;   
}   
int main()   
{   
    char *str;   
     str=returnStr();   
    printf("%s\n", str);   
  
    return 0;   
}   
5: 数组是不能作为函数的返回值的,原因是编译器把数组名认为是局部变量(数组)的地址。返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。如下:
[html] view plaincopy
int* func( void )  
{  
    static int a[10];  
    ........  
    return a;  
}   
6:返回指向堆内存的指针是可以的
[html] view plaincop
char *GetMemory3(int num)  
{  
char *p = (char *)malloc(sizeof(char) * num);  
return p;  
}  
void Test3(void)  
{  
char *str = NULL;  
str = GetMemory3(100);  
strcpy(str, "hello");  
cout<< str << endl;  
free(str);  
}  
程序在运行的时候用 malloc 申请任意多少的内存,程序员自己负责在何时用 free释放内存。动态内存的生存期一直到程序员自己释放。

  1. 可以函数的参数表中传入一个指针变量,然后局部指针指向这个参数指针,则当函数返回时,由于参数指针所指的内存空间的寿命是主函数的寿命,函数返回时不会被释放。  
可以函数的参数表中传入一个指针变量,然后局部指针指向这个参数指针,则当函数返回时,由于参数指针所指的内存空间的寿命是主函数的寿命,函数返回时不会被释放。
  1. int *fun(int *p)  
  2. {  
  3.     int *a;  
  4.     *p=4;  
  5.     a=p;  
  6.     return a;  
  7. }  
  8. int main()  
  9. {  
  10.     int a=2;  
  11.     int *p=&a;  
  12.     int *r=fun(p);  
  13.     cout<<*r;  
  14.     return 0;  
  15. }  
int *fun(int *p)
{
	int *a;
	*p=4;
	a=p;
	return a;
}
int main()
{
	int a=2;
	int *p=&a;
	int *r=fun(p);
	cout<<*r;
	return 0;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值