c++中函数中变量内存分配以及返回指针、引用类型的思考
众所周知,我们在编程的时候经常会在函数中声明局部变量(包括普通类型的变量、指针、引用等等)。
同时,为了满足程序功能的需要,函数的返回值也经常是指针类型或是引用类型,而这返回的指针或是引用也经常指向函数中我们自己声明的局部变量。
这样,程序在某些情况下就可能存在一定的问题。看似很简单的问题,通过仔细的分析,我们就能够更好的理解c++中内存分配和释放的问题。
好,废话不多说,我们进入正题。首先,简单介绍一下程序的内存区域的分配:
程序的内存分配
①堆区(heap)。这一部分主要是由程序开发人员自己通过new和malloc等操作创建的“对象”所保存的内存区域,该区域的变量需要开发人员自己释放。存储方式类似链表。
②栈区(stack)。这一部分主要是程序中的函数所以及其中的变量所占用的内存区域(包括了main函数)。存储方式类似栈。
③全局区或常量区(static)。这一部分主要是存放全局变量、静态数据、常量。程序结束后由系统释放。
④文字常量区。这一部分除妖存放常量字符串。 程序结束后由系统释放。
⑤程序代码区。程序的二进制代码。
1、函数中声明普通变量
void func1()
{
int i;
}
在函数func1()中,我们声明了一个int变量i,它保存在栈区中,当func1执行完成后,i也将被释放。
2、函数中声明指针类型变量
void func2()
{
int *p = (int*)malloc(sizeof(int));
A *a = new A; //A是一个类
}
在函数func2()中,我们声明了一个int型指针变量p和一个用户自定义类A指针变量a,它们都保存在堆区中,在函数func2执行完成后,仍然不会被释放,需要程序开发人员自己使用free()或delete等等进行释放。否则就会导致内存泄漏的问题。
3、函数返回值为指针或引用类型
函数的返回值为指针和引用类型是非常常见而且实用的,如果我们的函数返回的指针或者引用来自函数中声明的指针类型变量,则没有问题。如下:
int* CreatePointerFactory()
{
int *p = (int*)malloc(sizeof(int));
//to do sth here
return p;
}
这样的代码也是常见的简单工厂模式。但是需要注意的是,在通过函数CreatePointerFactory得到指针之后,在完成了相关操作之后,要进行对应的内存释放工作。最后需要将指针的值设置为NULL,防止野指针的产生。
第二种情况,函数返回的指针或者引用来自函数中声明的普通类型变量,则会产生非常严重的问题。如下:
int* getPointer()
{
int i = 1;
//to do sth here
return &i;
} //main.cpp
int* p = getPointer();
因为变量i在栈区创造,在getPointer函数执行结束之后,这片内存区域将被释放,变量i所对应的内存也将被释放掉。因此,如果我们在其他某处(如主函数中)调用了该函数,那么返回得到的指针则是非常危险的,指向的位置是没有任何意义的。
但是,在做实验的时候,我们会发现,此时在某些编译器下,打印*p的值,可能仍是1,有的也可能是乱码。
这里的原因主要如下:
①不同的编译器处理和优化不同。
②OS在释放了这一部分内存之后,并不是完全清空内存中的数据,而只是将标志位flag只为true,表示此块内存是未被占用的。
c++中函数中变量内存分配以及返回指针、引用类型的思考的更多相关文章
- 【转载】c++中堆、栈内存分配
一.内存划分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数参数值,局部变量值等.其操作方式类似于数据结构中栈.2.堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时 ...
- (转)C++ STL中的vector的内存分配与释放
C++ STL中的vector的内存分配与释放http://www.cnblogs.com/biyeymyhjob/archive/2012/09/12/2674004.html 1.vector的内 ...
- c++中堆、栈内存分配
转自:https://blog.csdn.net/qingtingchen1987/article/details/7698415 一个由C/C++编译程序占用内存分为以下几个部分1.栈区(stack ...
- Java继承中的转型及其内存分配
看书的时候被一段代码能凌乱啦,代码是这样的: package 继承; abstract class People { public String tag = "疯狂Java讲义"; ...
- 代码中函数、变量、常量 / bss段、data段、text段 /sct文件、.map文件的关系[实例分析arm代码(mdk)]
函数代码://demo.c #include<stdio.h> #include<stdlib.h> , global2 = , global3 = ; void functi ...
- Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF
1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是: BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...
- Javascript中函数及变量定义的提升
<html> <head> <title>函数提升</title> <script language="javascript" ...
- MIC中函数和变量的声明
c++/c使用 __declspec(target(mic))函数或变量声明 或 __attribute__((target(mic)))函数或变量声明 举例如下: __attribute__((ta ...
- C++变量内存分配及类型修饰符
前言 了解C++程序内存分配,有助于深刻理解变量的初始化值以及其生存周期.另外,变量类型修饰符也会影响到变量的初始化值及其生存周期.掌握了不同类型变量的初始化值及其生存周期,能够让我们设计程序时定义变 ...
随机推荐
- JQ第二天
一.属性.表单过滤选择器 $("div[id]")选取有id属性的<div>//$("div [id]")有空格表示div层当中有id属性的元素 $ ...
- ajax的使用:(ajaxReturn[ajax的返回方法]),(eval返回字符串);分页;第三方类(page.class.php)如何载入;自动加载函数库(functions);session如何防止跳过登录访问(构造函数说明)
一.ajax例子:ajaxReturn("ok","eval")->thinkphp中ajax的返回值的方法,返回参数为ok,返回类型为eval(字符串) ...
- 带你玩转JavaWeb开发之六-mysql基本语法详解及实例(4)
按照分类的名称统计每个分类商品所花的总钱数[排序查询] SQL中对查询的列进行排序,使用关键字order by.默认情况下是升序的排序(从小到大的排序顺序关键字 asc).使用降序排序需要使用关键字d ...
- mysql slow query---pt-query-digest----db structure consistency,monitor table records before and after transaction.
将数据库脚本纳入版本管理是很必要的,尤其对于需要在客户那里部署升级的系统. 对于Python Django等框架,由于数据库是通过Model生成的,因此框架本身包括数据库升级工具,并通过代码版本间接管 ...
- django--forms
forms模块的功能 1 表单提交验证 2 生成HTML标签 其他 提交后保留页面数据 创建forms类 首先从django中引入forms,一般会在application中新建一个文件专门保存for ...
- 为什么要使用CachedRowSetImpl?
很多情况我们使用ResultSet 就会因为这样那样的问题,rs被关闭或数据链接被关闭,导致ResultSet不能使用.其实这个问题我们可以用CachedRowSetImpl来解决.我的理解是这是一个 ...
- iOS学习路线图
一.iOS学习路线图 二.iOS学习路线图--视频篇 阶 段 学完后目标 知识点 配套学习资源(笔记+源码+PPT) 密码 基础阶段 学习周期:24天 学习后目标: ...
- 使用git版本控制器C#工程,git托管到GitHub和visual studio on line
类比TFS, 托管到了VS online,为私有.GitHub上托管的代码为开源. 新建工程选择版本控制器"Git" VS online: 本地: GitHub,下载github ...
- CentOS进不了mysql
在tty1里输入命令:“mysql -uroot -p+密码” 可以正常进入mysql,但在tty2里就不行了, 提示:Error 1045(28000): Access denied for use ...
- ubuntu启动tomcat出错解决方案
从终端进入tomcat的bin目录,然后执行startup.sh,出现以下异常: Cannot find ./catalina.sh The file is absent or does not ha ...