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返回值深入理解的更多相关文章

  1. 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值

    关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...

  2. C# 调用存储过程操作 OUTPUT参数和Return返回值

    本文转载:http://www.cnblogs.com/libingql/archive/2010/05/02/1726104.html 存储过程是存放在数据库服务器上的预先编译好的sql语句.使用存 ...

  3. MSSQL - 存储过程Return返回值

    1.存储过程中不使用外部参数. 存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ========================== ...

  4. C#获取存储过程的 Return返回值和Output输出参数值

    1.获取Return返回值  程序代码 //存储过程//Create PROCEDURE MYSQL//     @a int,//     @b int//AS//     return @a + ...

  5. return 返回值

    # ### return 返回值 """ (1) return + 数据类型 : 将这个数据弹到函数的调用处,后面除了可以接六大标准数据类型之外,还可以返回类 对象 函数 ...

  6. 用jquery的ajax方法获取return返回值的正确姿势

    如果jquery中,想要获取ajax的return返回值,必须注意两方面,ajax的同步异步问题,在ajax方法里面还是外面进行return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第 ...

  7. return 返回值的用法

    #coding:utf-8 # (1)把数据返回到函数调用处 def func(): # return 1 # return "aaabb" return [1,2,3,4] re ...

  8. return 返回值的问题

    def yue(): print("1. 打开手机") print("2. 打开陌陌") print("3. 找个漂亮的小姐姐") prin ...

  9. 用jquery的ajax方法获取不到return返回值

    如果jquery中,获取不到ajax返回值. 两个错误写法会导致这种情况:1.ajax未用同步 2.在ajax方法中直接return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第三种写法 ...

随机推荐

  1. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  2. Excel 截取字符,判断县区 城市。

    https://jingyan.baidu.com/article/624e7459aa90e434e8ba5a8a.html https://jingyan.baidu.com/article/9f ...

  3. @RequestBody的使用

    一.说明 首先@RequestBody需要接的参数是一个string化的json,这里直接使用JSON.stringify(json)这个方法来转化 其次@RequestBody,从名称上来看也就是说 ...

  4. web程序设计关于我们

    项目名称 福大咸鱼市场 开发团队 项目板块 负责人 美工 黄鸿杰 后端 胡继文 前端 葛家灿 联系方式:1175204449@qq.com

  5. What is the difference between UNION and UNION ALL?

    What is the difference between UNION and UNION ALL? UNION removes duplicate records (where all colum ...

  6. List和数组的互转

    list转数组: /要转换的list集合 List<String> testList = new ArrayList<String>(){{add("aa" ...

  7. Microsoft.Owin 使用 文件服务

    添加引用: <package id="Microsoft.Owin" version="4.0.1" targetFramework="net4 ...

  8. MySQL可传输表空间:将一个表从一个实例拷贝到另一个实例

    MySQL版本:5.7.23 1.在源实例上,创建一个表(如果不存在): mysql> USE abce; mysql> CREATE TABLE t(c1 INT) ENGINE=Inn ...

  9. parquet 简介(转)

    原文 Parquet 列式存储格式 面向分析型业务的列式存储格式 由 Twitter 和 Cloudera 合作开发,2015 年 5 月从 Apache 的孵化器里毕业成为 Apache 顶级项目 ...

  10. 在线visio软件,在线流程图软件,在线绘图、在线画图

    1. https://www.bullmind.com/ 推荐bullmind的在线visio软件,一种低成本的Visio替代品.bullmind是基于 网络的绘图工具,具有出色图表功能.您可以使用b ...