众所周知,我们在编程的时候经常会在函数中声明局部变量(包括普通类型的变量、指针、引用等等)。

同时,为了满足程序功能的需要,函数的返回值也经常是指针类型或是引用类型,而这返回的指针或是引用也经常指向函数中我们自己声明的局部变量。

这样,程序在某些情况下就可能存在一定的问题。看似很简单的问题,通过仔细的分析,我们就能够更好的理解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++中函数中变量内存分配以及返回指针、引用类型的思考的更多相关文章

  1. 【转载】c++中堆、栈内存分配

    一.内存划分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数参数值,局部变量值等.其操作方式类似于数据结构中栈.2.堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时 ...

  2. (转)C++ STL中的vector的内存分配与释放

    C++ STL中的vector的内存分配与释放http://www.cnblogs.com/biyeymyhjob/archive/2012/09/12/2674004.html 1.vector的内 ...

  3. c++中堆、栈内存分配

    转自:https://blog.csdn.net/qingtingchen1987/article/details/7698415 一个由C/C++编译程序占用内存分为以下几个部分1.栈区(stack ...

  4. Java继承中的转型及其内存分配

    看书的时候被一段代码能凌乱啦,代码是这样的: package 继承; abstract class People { public String tag = "疯狂Java讲义"; ...

  5. 代码中函数、变量、常量 / bss段、data段、text段 /sct文件、.map文件的关系[实例分析arm代码(mdk)]

    函数代码://demo.c #include<stdio.h> #include<stdlib.h> , global2 = , global3 = ; void functi ...

  6. Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF

    1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是: BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...

  7. Javascript中函数及变量定义的提升

    <html> <head> <title>函数提升</title> <script language="javascript" ...

  8. MIC中函数和变量的声明

    c++/c使用 __declspec(target(mic))函数或变量声明 或 __attribute__((target(mic)))函数或变量声明 举例如下: __attribute__((ta ...

  9. C++变量内存分配及类型修饰符

    前言 了解C++程序内存分配,有助于深刻理解变量的初始化值以及其生存周期.另外,变量类型修饰符也会影响到变量的初始化值及其生存周期.掌握了不同类型变量的初始化值及其生存周期,能够让我们设计程序时定义变 ...

随机推荐

  1. ECshop通过文章分类的ID实现不同模板

    当客户需要想要用不同模板来实现文章页面时,文章就需要实现调用不同模板的内容,着手点就是它的分类ID.直接通过分类ID来判断一下,现在68ecshop技术来告诉你该怎么做 方法如下所示: 一.打开根目录 ...

  2. html5 canvas画流程图

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  3. LeetCode Design Hit Counter

    原题链接在这里:https://leetcode.com/problems/design-hit-counter/. 题目: Design a hit counter which counts the ...

  4. JAVASE02-Unit09: 多线程基础

    Unit09: 多线程基础 * 线程 * 线程用于并发执行多个任务.感官上像是"同时"执行 *  * 创建线程有两种方式. * 方式一: * 继承线程并重写run方法来定义线程要执 ...

  5. linux下普通用户如何使用80端口启动程序

    linux下普通用户如何使用80端口启动程序 http://blog.csdn.net/shootyou/article/details/6750230 大家都知道默认情况下linux的1024以下端 ...

  6. Static方法在多线程环境下的运行

    最近看了Jfinal 一致对model的那个static final dao有些疑惑,全局一个实例安全吗?同时也出了一个疑惑,静态方法执行会有并发影响吗?看代码 StaticThread.java p ...

  7. android:descendantFocusability用法简析

    开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了 ...

  8. c/c++ qsort 函数的简单使用(1)

    #include <stdio.h> #include <stdlib.h> //打印数组元素 void print(int arr[], int n){ ; i < n ...

  9. 多线程java的concurrent用法详解(转载)

    我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量Java ...

  10. 2.2 C#的注释

    注释,是代码中的一些“说明文档”,注释注释本身不会参与程序代码的编译和运行,仅仅是为了方便程序员阅读. C#的注释分为:单行注释.多行注释.文档注释. 单行注释的符号是2条斜杠线(斜线的方向是左下到右 ...