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++程序内存分配,有助于深刻理解变量的初始化值以及其生存周期.另外,变量类型修饰符也会影响到变量的初始化值及其生存周期.掌握了不同类型变量的初始化值及其生存周期,能够让我们设计程序时定义变 ...
随机推荐
- java beans
There are N little kids sitting in a circle, each of them are carrying some java beans in their hand ...
- [Maven]初次实践
都说Maven好,以前一直用ant,这次体验一下. 开始之前,maven给我的印象有2个,一是库依赖管理做得比较好,二是规范了构建编译过程,说白了就是什么目录都规定好了. 好开始安装,解压缩,设置m2 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- php常用关键字
1.final关键字 <?php //final关键字修饰的类 是最终的类不能被继承 class demo{ //final关键字修饰的成员方法 是最终版本的方法不能被重写 final publ ...
- EF实体框架之CodeFirst一
对于SQL Server.MySql.Oracle等这些传统的数据库,基本都是关系型数据库,都是体现实体与实体之间的联系,在以前开发时,可能先根据需求设计数据库,然后在写Model和业务逻辑,对于Mo ...
- Fatal error: Call to undefined function curl_init()问题
最近分别在win7和Win8.win10 上分别安装php 高版本!都遇到了这个问题! 一.win7系统, apache2.2/apache2.4, php5.2升级到5.4. 这个比较容易: 1. ...
- ubuntu 安装transmission最新版
访问 www.transmissionbt.com 下载最新版 1)下载transmission:# wget https://transmission.cachefly.net/transmi ...
- Win7开机登陆密码忘记了?不必重做系统(详图)
1)如果是普通账户密码忘了.方法:重新启动电脑,启动到系统登录界面时,同时按住Ctrl+Alt键,然后连击Del键两次,会出现新的登录界面,用户名处输入“Administrator”密码为空,回车即 ...
- Android Studio 使用Lambda
1,昨天在使用RxJava的时候,调用map.filter之类的方法要创建挺多的匿名内部类,所以我们打算试用一下Lambda让我们的代码更有阅读新性,下看一下我们的对比 在使用之前我们代码是这样的 O ...
- 《玩转D语言系列》一、通过四个版本的 Hello Word 初识D语言
对于D语言,相信很多朋友还没听说过,因为它还不够流行,跟出自名门的一些语言比起来也没有名气,不过这并不影响我对它的偏爱,我就是这样的一种人,我喜欢的女孩子一定是知己型,而不会因为她外表,出身,学历,工 ...