正文
局部变量&&malloc函数&&生命周期的一些见解
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
最近在温习指针的部分时发现了一个有趣的问题,先看以下程序:
//1.c
#include<stdio.h>
int* fun()
{
int t = 567;
return &t;
}
int main()
{
int *p;
p = fun();
printf("%d",*p);
}
当我把1.c运行后,发现输出结果是:567。此时编译器给出警告信息:返回值是局部变量的地址。
首先,我们知道操作系统给函数分配的内存空间都是在栈中,当函数调用结束后,操作系统就会回收其内存空间。当然,这个过程包括回收函数内部的局部变量(局部变量也是存储在栈空间中),而此处的"回收"是指销去变量名/函数名,并把其内存空间标记为可用。即操作系统可对该部分内存空间重新利用。但既然变量已经被回收了,为什么还能输出其值?
对于此问题,我是这样认为的:
1.当变量的生命周期结束后,虽然变量该变量已不存在,但其之前分配的内存空间还在,也就是其地址还是之前变量的地址,而如果该部分内存空间在main函数结束之前都一直未被操作系统重新利用的话,它的数据没有被改写,那么此时输出*p的值还是之前变量的值。
2.虽然我输出的*p是567,但是不能保证每次输出的*p都是567。因为编译器和操作系统都无法保证这部分内存空间在main函数结束前一直都不会被利用,所以这种输出是不稳定的。实际上,此时的指针p相当于一个野指针,此时虽然也可以对这部分内存空间进行读写操作(可看作对野指针的操作),但是相当危险的。
3.由此可知,一定不要把局部变量的地址作为函数的返回值。
接下来再看另一个程序:
//2.c
#include<stdio.h>
#include<stdlib.h>
int* fun()
{
int *t = (int*)malloc(sizeof(int)); ;
*t = 567;
return t;
}
int main()
{
int *p;
p = fun();
printf("%d",*p);
}
当我运行2.c后,发现其输出结果:567。并且编译器没有给出任意的警告信息。
此时t作为一个局部变量,并且函数的返回值为t的地址,为什么编译器没给出警告?
在我看来,2.c中的t与1.c中t虽然同为局部变量,两者在内存中的分布是完全不同的。1.c中的t是存储在栈空间中的,而2.c中t是存储在堆空间中的(堆与栈的区别:http://www.cnblogs.com/wangkundentisy/articles/6003482.html)。而当局部变量生命周期结束后,编译器会先消除该局部变量名,然后对于栈中的空间,编译器会释放它;而对于堆中的空间,编译器并不理会。所以,在2.c中,虽然fun函数以及指针t被销毁,但t指向的内存空间依然完好无损,并且由于编译器并未释放它,操作系统自然不会去利用这部分内存空间。所以,最后输出*p时,始终会输出567。但是,这样会造成内存泄漏,并产生垃圾!所以说malloc之后,一定要有一个free与之相对应!故在2.c中,printf函数后应加上free(p)。
综上,在写程序时,一定不要把局部变量的地址作为函数的返回值!一定尽量避免返回在函数内部使用的分配函数(malloc或new)分配的内存空间,以及malloc和free一定要成对的出现!
局部变量&&malloc函数&&生命周期的一些见解的更多相关文章- React 函数生命周期
React 函数生命周期基础 1 ,概念 在组件创建.到加载到页面上运行.以及组件被销毁的过程中,总是伴随着各种各样的事件,这些在组件特定时期,触发的事件,统称为组件的生命周期:* 2,组件生命周 ...
- Vue钩子函数生命周期实例详解
vue生命周期简介 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁 ...
- rust 函数-生命周期
记录一下自己理解的生命周期. 每个变量都有自己的生命周期. 在c++里生命周期好比作用域, 小的作用域的可以使用大作用域的变量. 如果把这里的每个作用域取个名,那么就相当于rust里的生命周期注解. ...
- Vue系列之 =>; 钩子函数生命周期
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Unity 脚本函数生命周期
Awake(),一般我们在这里做一些组件的获得,比如使用getcomponent方法. Start(),我们可以在这里给变量赋值. FixUpdate(),固定更新,因为这里得更新速度为固定(可以在T ...
- 【vue】钩子函数生命周期
图1 图2: 图3 相关资料:http://www.zhimengzhe.com/Javascriptjiaocheng/236707.html https://segmentfault.com ...
- Unity脚本中各函数成员的生命周期
在学习Unity时,掌握如何编写脚本是必须掌握的一项基本技能.但是关于Unity的游戏脚本中各函数的生命周期是怎样开始和结束的,它们的执行顺序是如何安排的?这一点我们要清楚的了解. 我们知道Unity ...
- JavaScript巩固篇(一)——数据类型与全局变量、局部变量、垃圾回收机制、存储方式、生命周期
知识要点 数据类型 存储方式 全局变量与局部变量 变量的生命周期 垃圾回收机制 知识概览 数据类型 JavaScript的数据类型分为:基本类型.引用类型 本质区别: 基本数据类型的变量实际值存储在栈 ...
- shell中的数据生命周期scope
#!/bin/shexit 0#shell 中, 默认所有的变量都是 全局变量,除非主动变量前面加 local 修饰#shell 变量是字符变量,只能放字符和数字,shell数组也是如此;而数字也是图 ...
随机推荐- CSS属性选择符
属性选择符: E[att] 选择具有att属性的E元素. <style type="text/css"> a[class]{ background-color: red ...
- 父窗口,子窗口之间的JS";通信";方法
今天需要在iframe内做一个弹窗,但使用弹窗组件的为子窗口,所以弹窗只在子窗口中显示掩膜层和定位,这样不符合需求. 后来晓勇哥指点,了解到一个以前一直没关注到的东西,每个窗口的全局变量,其实都存在对 ...
- 淘宝(阿里百川)手机客户端开发日记第六篇 Service详解(六)
Service和Thread的关系 不少初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread? 答案是Service和T ...
- C++ 基础复习 1
1. 友元 友元的作用是,友元函数内部可以直接访问外围类的private的字段或方法.通俗的理解就是解决了访问权限的问题. 1) 有点像java的内部类,但是只能在外围类中声明,定义(实现)部分要写在 ...
- JXSE and Equinox Tutorial, Part 2
http://java.dzone.com/articles/jxse-and-equinox-tutorial-part-0 ———————————————————————————————————— ...
- 使用ASP.NET MVC+Entity Framework快速搭建博客系统
学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和分享. 首先,得确定需求,木有需求的话,那还搞个毛线呀!嗯……大致思考了一下,终于得出如下需求: 1.能自定义 ...
- 什么是NoSQL
NoSQL = Not Only SQL 不仅仅是SQL NoSQL,指的是非关系型的数据库(没有声明性查询语言,没有预定义的模式,可以为键 - 值对存储,列存储,文档存储,图形数据库).不同于传统的 ...
- addEventListener以及滑轮滑动事件的应用
addEventListener用于向元素添加事件,而其适用于较新版的IE浏览器(如IE9),对于IE6/7/8来说,应该用attachEvent 下面的代码即为向<img>元素添加事件 ...
- CentOS 7.0安装配置Vsftp服务器步骤详解
安装Vsftp讲过最多的就是在centos6.x版本中了,这里小编看到有朋友写了一篇非常不错的CentOS 7.0安装配置Vsftp服务器教程,下面整理分享给各位. 一.配置防火墙,开启FTP服务器需 ...
- Educational Codeforces Round 28
A. Curriculum Vitae 题目链接:http://codeforces.com/contest/846/problem/A 题目意思:给你一个只包含0-1的数组,现在要求去可以去掉一些元 ...
React 函数生命周期基础 1 ,概念 在组件创建.到加载到页面上运行.以及组件被销毁的过程中,总是伴随着各种各样的事件,这些在组件特定时期,触发的事件,统称为组件的生命周期:* 2,组件生命周 ...
vue生命周期简介 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁 ...
记录一下自己理解的生命周期. 每个变量都有自己的生命周期. 在c++里生命周期好比作用域, 小的作用域的可以使用大作用域的变量. 如果把这里的每个作用域取个名,那么就相当于rust里的生命周期注解. ...
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
Awake(),一般我们在这里做一些组件的获得,比如使用getcomponent方法. Start(),我们可以在这里给变量赋值. FixUpdate(),固定更新,因为这里得更新速度为固定(可以在T ...
图1 图2: 图3 相关资料:http://www.zhimengzhe.com/Javascriptjiaocheng/236707.html https://segmentfault.com ...
在学习Unity时,掌握如何编写脚本是必须掌握的一项基本技能.但是关于Unity的游戏脚本中各函数的生命周期是怎样开始和结束的,它们的执行顺序是如何安排的?这一点我们要清楚的了解. 我们知道Unity ...
知识要点 数据类型 存储方式 全局变量与局部变量 变量的生命周期 垃圾回收机制 知识概览 数据类型 JavaScript的数据类型分为:基本类型.引用类型 本质区别: 基本数据类型的变量实际值存储在栈 ...
#!/bin/shexit 0#shell 中, 默认所有的变量都是 全局变量,除非主动变量前面加 local 修饰#shell 变量是字符变量,只能放字符和数字,shell数组也是如此;而数字也是图 ...
- CSS属性选择符
属性选择符: E[att] 选择具有att属性的E元素. <style type="text/css"> a[class]{ background-color: red ...
- 父窗口,子窗口之间的JS";通信";方法
今天需要在iframe内做一个弹窗,但使用弹窗组件的为子窗口,所以弹窗只在子窗口中显示掩膜层和定位,这样不符合需求. 后来晓勇哥指点,了解到一个以前一直没关注到的东西,每个窗口的全局变量,其实都存在对 ...
- 淘宝(阿里百川)手机客户端开发日记第六篇 Service详解(六)
Service和Thread的关系 不少初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread? 答案是Service和T ...
- C++ 基础复习 1
1. 友元 友元的作用是,友元函数内部可以直接访问外围类的private的字段或方法.通俗的理解就是解决了访问权限的问题. 1) 有点像java的内部类,但是只能在外围类中声明,定义(实现)部分要写在 ...
- JXSE and Equinox Tutorial, Part 2
http://java.dzone.com/articles/jxse-and-equinox-tutorial-part-0 ———————————————————————————————————— ...
- 使用ASP.NET MVC+Entity Framework快速搭建博客系统
学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和分享. 首先,得确定需求,木有需求的话,那还搞个毛线呀!嗯……大致思考了一下,终于得出如下需求: 1.能自定义 ...
- 什么是NoSQL
NoSQL = Not Only SQL 不仅仅是SQL NoSQL,指的是非关系型的数据库(没有声明性查询语言,没有预定义的模式,可以为键 - 值对存储,列存储,文档存储,图形数据库).不同于传统的 ...
- addEventListener以及滑轮滑动事件的应用
addEventListener用于向元素添加事件,而其适用于较新版的IE浏览器(如IE9),对于IE6/7/8来说,应该用attachEvent 下面的代码即为向<img>元素添加事件 ...
- CentOS 7.0安装配置Vsftp服务器步骤详解
安装Vsftp讲过最多的就是在centos6.x版本中了,这里小编看到有朋友写了一篇非常不错的CentOS 7.0安装配置Vsftp服务器教程,下面整理分享给各位. 一.配置防火墙,开启FTP服务器需 ...
- Educational Codeforces Round 28
A. Curriculum Vitae 题目链接:http://codeforces.com/contest/846/problem/A 题目意思:给你一个只包含0-1的数组,现在要求去可以去掉一些元 ...