C语言return返回值深入理解
C语言使用return关键字返回函数值,可以很好对函数做封装,此处的疑问是:函数内部创建的变量都是局部变量,即私有的,作用域就在函数之内,为什么却可以把值传给调用函数?
解释这个问题还需要从C语言调用函数传参类比来说,C语言传参调用时,可以采用传值和传指针两种方式。
传值的形式:只是将参数值的拷贝传给函数,并非参数本体,如:
int test_func(int i)
{
i++;
printf("Function i : %d\n", i);
return ;
} int main()
{
int a = ;
printf("Main Pre: %d\n", a);
test_func(a);
printf("Main Now: %d\n", a); return ;
}
传指针形式:直接传给函数的是变量的地址,由于被调函数在参数指针的作用域之内,此时直接改变变量的本体。
int test_func(int *i)
{
(*i)++; //注意:++的优先级比*高
printf("Function i : %d\n", *i);
return ;
} int main()
{
int a = ;
printf("Main Pre: %d\n", a);
test_func(&a);
printf("Main Now: %d\n", a); return ;
}
同理,函数返回也有两种形式。
1、函数返回变量值
此时,返回变量值的方式与函数调用传值同样的道理,在函数结束返回时,将局部变量值拷贝给一个临时变量,然后将这个临时变量返回给调用函数。因此,即使局部变量在返回时已经释放内存,也不影响返回的变量值。
int test_func()
{
int i = ;
printf("Function i : %d\n", i);
return i;
} int main()
{
int a = ;
a = test_func();
printf("Main Now: %d\n", a); return ;
}
从汇编的角度来看源代码:
由以上看出:返回变量值的时候,直接将局部变量的值传给了了寄存器eax,也就是说,函数返回以后,虽然局部变量已被释放,但是eax里面的还有一个值的拷贝。
2、函数返回地址
此时注意:C语言的指针操作,大部分都是直接对指针指向的变量直接操作,函数内部的变量和指针一般分配在栈上,而栈上的数据都是临时保存的,当函数返回时会自动释放掉,因此如果直接返回一个栈上的指针,返回的值将不可预知。
int *test_func()
{
int local_data = ; printf("Function local_data : %d\n", local_data); return &local_data;
} int main()
{
int *main_data = NULL; main_data = test_func(); printf("Return data: %d\n", *main_data); return ;
}
从汇编语言角度查看源码:
由以上看出:返回指针的时候,用的是指令lea,这条指令的作用是,将[ebp-4](此单元对应的是变量local_data在栈上的数据存储位置)这个数据单元的地址传给eax寄存器,但是像这样在栈上开辟出来临时存储数据的单元,只要调用函数结束,就会释放掉里面的数据,因此虽然返回了一个指针,指针指向的数据却已经被系统销毁了,这就导致返回的指针指向不可预知的数据。
C语言return返回值深入理解的更多相关文章
- 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值
关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...
- C# 调用存储过程操作 OUTPUT参数和Return返回值
本文转载:http://www.cnblogs.com/libingql/archive/2010/05/02/1726104.html 存储过程是存放在数据库服务器上的预先编译好的sql语句.使用存 ...
- MSSQL - 存储过程Return返回值
1.存储过程中不使用外部参数. 存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========================== ...
- C#获取存储过程的 Return返回值和Output输出参数值
1.获取Return返回值 程序代码 //存储过程//Create PROCEDURE MYSQL// @a int,// @b int//AS// return @a + ...
- return 返回值
# ### return 返回值 """ (1) return + 数据类型 : 将这个数据弹到函数的调用处,后面除了可以接六大标准数据类型之外,还可以返回类 对象 函数 ...
- 用jquery的ajax方法获取return返回值的正确姿势
如果jquery中,想要获取ajax的return返回值,必须注意两方面,ajax的同步异步问题,在ajax方法里面还是外面进行return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第 ...
- return 返回值的用法
#coding:utf-8 # (1)把数据返回到函数调用处 def func(): # return 1 # return "aaabb" return [1,2,3,4] re ...
- return 返回值的问题
def yue(): print("1. 打开手机") print("2. 打开陌陌") print("3. 找个漂亮的小姐姐") prin ...
- 用jquery的ajax方法获取不到return返回值
如果jquery中,获取不到ajax返回值. 两个错误写法会导致这种情况:1.ajax未用同步 2.在ajax方法中直接return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第三种写法 ...
随机推荐
- 用户生命周期(User Lifetime)
什么是用户生命周期? 用户生命周期是从用户开始接触产品到离开产品的整个过程.用户生命周期可分为:引入期.成长期.成熟期.休眠期.流失期.对应的是用户对产品不同的参与程度. 用户生命周期有什么用? 按照 ...
- 2019.10.1 qbxt模拟题
第一题 考虑树上\(DP\),f[i][j][0/1]表示以\(i\)为根的子树,入读为零点的个数为\(j\),点\(i\)的入度为\(0\)/不为\(0\)时的方案数 转移的时候考虑\(u\)的一个 ...
- 关于m3u8文件, ts文件解密, hls 解密. 一些记录
使用openssl 解密 openssl aes-128-cbc -d -in 原.ts -out 解密后.ts -nosalt -iv 偏移量 -K key16进制 其中 iv 偏移量和 key 一 ...
- mvc基础配置
视图解析器 在spring-mvc文件中编写 <!--配置视图解析器--> <bean class="org.springframework.web.servlet.vie ...
- MySQL中自增ID起始值修改方法
在实际测试工作过程中,有时因为生产环境已有历史数据原因,需要测试环境数据id从某个值开始递增,此时,我们需要修改数据库中自增ID起始值,下面以MySQL为例: 表名:users; 建表时添加: ); ...
- 经典算法(一) top k
问题:1亿数据中,找出最大的k个数,要求使用内存不超过1m (延伸问题:1亿数据中,找出重复出现次数最多的k个,要求使用内存不超过1m 等) 分析: 1亿数字(int)占内存:100000000 * ...
- vi 调到第一行和最后一行
gg 跳到文件第一行Shift + g 跳到文件最后一行 chmod 777 abc.txt
- 用JAVA把内存里的二进制文件打包成ZIP包
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.ut ...
- java 从 PKCS12(比如pfx格式)证书中提取私钥证书(PrivateKey)和受信任的公钥证书(X509Certificate)的序列号(SerialNumber)
import lombok.Cleanup; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; impor ...
- JavaScript 工厂模式
//工厂 function FruitMaker() { //function 后不带方法名,这里cococola未定义,make return时,返回 FruitMaker.cococola thi ...