关于函数返回值的一些见解

我们都知道c++函数返回类型有三种 返回值 返回指针 返回引用。
下面简单说说在函数返回的时候到底发生了什么动作。

返回值类型:
拿一个很简单的例子:
函数定义:

int get()
{
  int n=3;
  return n;
}

int main()
{
  int k=get();
}

先看get函数,局部变量n是一个产生在栈区的值,因此在函数结束的时候空间就会被释放,这个函数结束就底是指
在return前还是return后呢。

答案是不一定,一般是不会被立刻释放。
return这个动作会把n的值复制给一个临时变量q,这个临时变量充当函数的返回值,直到main函数的赋值成功后临时变量就被销毁。
所以实际上在main函数里面 k=get() k是获取get()函数的临时变量的值,而这个值的确是存在的,所以赋值成功。
在k成功获取q的值之后,临时变量q和局部变量n可能会被销毁,也可能不会被销毁,这是不确定的。

返回指针类型:

int *get()
{
  int *p = new int(3);
  return p;
}

int main()
{
  int *k=get();
}

也是先看get函数,局部变量p申请了一块动态内存,值为3. 在return p这里发生的动作有:
函数会产生一个临时变量,这个变量类型是int *,我们假设为 q
q = p; 即q指向了p指向的地方,这里是p申请的那块动态内存。
临时变量q充当函数的返回值
所以在main函数里面 k = get() 实际上就是 k = q 这时候k就指向了那块动态申请的内存。
同理临时变量q完成任务后和局部变量p的地址是无效的,但它们的值仍然存在。

所以返回一个指向动态内存的局部指针是可行的。

错误用法:返回指向局部对象的指针。

int *get()
{
  int n = 3;
  return &n;
}

int main()
{
  int *p = NULL;
  int *k = NULL;
  p = k = get();
  cout<<*p<<endl;
  cout<<"operation"<<endl;
  cout<<*p<<endl;
}
这里get函数返回的是n的地址。
在get函数返回的时候同样发生了一次复制 假设临时变量名为temp  int *temp = &n;
此时temp的确指向了n的地址,并作为函数的返回值返回。
再看main函数 这里我用了一个链式复制来更好说明问题。
先看 k = get(),即发生了 k =temp; 此时k也指向了函数n的值。
然后p = k,p也指向了函数局部变量n的值。
cout<<*p  神奇地发现的确输出3. 可能大家会想难道局部变量n的值还没被释放么。
的确还是没被释放,因为n是临时变量,n的地址是被系统回收了
但它的值还没有被别的内容写入,所以3这个值仍然存在。 之所以这里设计是涉及到一个编译器运用内存的效率,即写时复制,当需要这块内存时候直接写入省去中间释放这个步骤。
但在第二次执行 cout<<*p<<endl; 发现不再输出3而是一个值很大的数。
这时候说明3这个值占用的内存被重写了。 所以解释是:在第一个cout<<*p<<endl执行之后,当再运行一段时间后,系统在调用<<函数、输出结果等过程中使用已回收的内存做其它用途了,此时该地址对应的值就被更改成无效的值了。
所以这是一个不确定的问题,你不知道编译器什么时候会把这个临时变量n的值释放掉,所以存在安全隐患。

返回局部引用也是如此。

时间: 2024-11-08 23:16:10

关于函数返回值的一些见解的相关文章

以函数返回值做参数时,函数调用的顺序

环境:vs2013 在下面的代码中 1 //类似于下面的代码 2 3 foo(char*,char*,char*); 4 5 char* str ="A#B#C"; 6 7 foo(strtok(str,"#"),strtok(NULL,"#"),strtok(NULL,"#")); 预计让函数foo得到("A","B","C")的参数,程序编译的时候没问题,但是运行

函数指针与指针函数返回值的区别

指针函数是指带指针的函数,即本质是一个函数.函数返回类型是某一类型的指针定义: 类型标识符 *函数名(参数表)eg: int *f(x,y);函数指针是指向函数的指针变量,即本质是一个指针变量.int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func函数的首地址赋给指针f */ 函数指针与指针函数返回值的区别,码迷,mamicode.com

对象做函数参数和函数返回值时,调用复制构造函数,构造函数,析构函数的情况

// 对象做函数参数和返回值.cpp : 定义控制台应用程序的入口点.//exit(0)表示正常退出程序,exit(0)表示异常退出 //在调用input时,编译器用对象A去创建了形参对象temp,调用了复制构造函数,对象A中的数据复制给了对象temp// 在input函数中,执行temp.set(s),为对象temp中数据成员str申请了动态储存空间,并设置了输入的字符串//并没有改变实参A中的数据成员str的储存空间,故在执行语句A.show()后输出的字符串并没有改变.在函数调用结束后 /

shell调用函数返回值深入分析

编写shell脚本过程中,我们经常会自定义一些函数,并根据函数的返回值不同来执行相应的流程,那么我们如何来获取函数的返回值呢? 首先shell中调用函数有两种方式: 第一种:value=`function_name [arg1 arg2 ......]` 或 第二种:function_name [arg1 arg2 ......] echo $? 这两种有什么区别呢? 举个例子来说: [[email protected] ~]# cat test.sh #!/bin/sh function aa

const修饰函数参数 const修饰函数返回值 const修饰成员函数

看到const 关键字,C++程序员首先想到的可能是const 常量.这可不是良好的条件反射.如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮.const 更大的魅力是它可以修饰函数的参数.返回值,甚至函数的定义体. const 是constant 的缩写,"恒定不变"的意思.被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.所以很多C++程序设计书籍建议:"Use const whenever you need". 1

string 中的 length函数 和size函数 返回值问题

string 中的 length函数 和 size函数 的返回值  (  还有 char [ ] 中 测量字符串的  strlen 函数 ) 应该是 unsigned int 类型的 不可以 和 -1 比较. 应尽量避免 unsigned int 类型 和 int类型 数据 的比较 .当unsigned int 类型 和 int类型 数据 比较 时 ,会 把int 类型 转换 为 unsigned int类型 .如果 int是负数 ,转换 为 unsigned int 会是 一个 很大 的正整数

C语言的函数返回值

一:背景 谈到C语言的函数返回值,可能会感觉很亲切,不就是一个函数返回值嘛,当初学C语言的时候早就学过了很easy嘛,我曾经也是这么想的.后来要上研究生了,研究生阶段搞得就是C,所以又重新开始学习C,学习C的过程中遇到了很多问题,在此博客中一一记录.实际过程中遇到的第一个问题自然就是函数返回值了.如果有人问你在一个函数中声明一个字符串数组,最后再return这个数组.这可以实现嘛?如果是问我我可能会毫不犹豫的说OK.那事实呢?由此本文诞生了...... 二:问题 先看几个实际的例子: #incl

将引用作为函数返回值的优缺点

格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }好处:在内存中不产生被返回值的副本:(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的.因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!注意事项:(1)不能返回局部变量的引用.这条可以参照Effective C++[1]的Item 31.主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态.(2)不能返回函数内部new

linux编程中接收主函数返回值以及错误码提示

程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> int main() { pid_t pid, rpid; int stat; if ((pid = fork()) < 0) { perror("for