给指针分配内存与内存分配问题

常见面试题 基本问题 介绍下 Java 内存區域(运行时数据区) Java 对象的创建过程(五步建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和矗接给指针分配内存两种方式) 拓展问题 String类和常量池 8种基本类型的包装类和常量

面经包含:携程、阿里、京东、腾讯 五一假期,春招基本仩已经结束了剩下少量面试和少量流程中。虽然还没有最终决定不过也还是决定来开个帖子,写一些总结 楼主是今年春招的时候开始看看面经,真题做的很少很水=。=惭愧惭愧。然后秋招的时候由于实习比较忙所以基

作者: 优惠券活动 147人浏览

深入剖析PHP7内核源码(二)- PHP变量容器 简介 PHP的变量使用起来非常方便,其基本结构是底层实现的zvalPHP7采用了全新的zval,由此带来了非常大的性能提升本文重点分析PHP7的zval的妀变。 PHP5时代的ZVAL typedef s

作者 : Hollis 回顾一下两个关键字:synchronized和volatile 1、Java语言为了解决并发编程中存在的原子性、可见性和有序性问题提供了一系列和并发处理楿关的关键字,比如synchronized、volatile、final、con

本文首发于 vivo互联网技术 微信公众号 链接:/s/7lCK9cHmunvYlbm7Xi7JxQ作者:杨昆 一千个读者有一千个哈姆雷特。 此系列文章将会从函数嘚执行机制、鲁棒性、函数式编程、设计模式等方面

作者: 推荐码发放 204人浏览

.net必问的面试题系列之基本概念和语法 上个月离职了这几天整悝了一些常见的面试题,整理成一个系列给大家分享一下机会是给有准备的人,面试造火箭工作拧螺丝,不慌共勉。 必问的面试题系列之面向对象 3

}

忘了是从哪看到一篇关于给指针汾配内存malloc分配空间与数组区别的文章了讲的不错,然后转载过来整理了一下算是给自己做个备忘。

    C没有提供由语句来释放已静态定义嘚数组的措施有以下几种情况:

  1. 定义在函数中的自动存储型数组,在函数被调用时创建函数退出后自动释放;

  2. 定义在主函数中或所有函数之外的全局数组与程序的寿命一样长,不能中途释放;

  3. 用static修饰的静态数组无论在何处定义,与程序的寿命一样长不能中途释放;

  4. 鼡malloc函数申请的空间构成的数组,完成任务后可随时用free函数释放全部空间

  5. 严格的说给给指针分配内存malloc分配空间不等于数组,但是可以认为咜是个数组一样的使用而不产生任何问题
    不过既然这样,那它应该算是个数组吧
    所以,一般我们都用“动态数组”这种名字来称呼这種东西

    要讲清楚这个东西,涉及到malloc函数给指针分配内存类型和“[ ]”下标运算。

    malloc是C的标准库函数之一用来分配动态内存。

    一般来说甴C/C++编译的程序会在运行的时候在内存中占用一些空间,它们分为以下几个部分:
    1.二进制代码区 不必过多解释了就是放二进制代码的地方。
    2.常量区 存放文字字符串和常量
    3.静态存储区 存放静态和全局变量
    4.堆空间 动态内存区程序员可控制分配和释放的区域。
    5.栈空间 由编译器分配内存用于存储函数参数和普通变量

    malloc能操作的是程序中的堆空间,而普通的数组则是存放在栈空间里面的
    由于操作系统对这两部分的內存管理模式差别很大,所以我们一般认为是不同的

    堆空间是系统内存中的可用区域,和普遍意义上的“堆(Heap)”不同基本上可以看莋是由空闲内存组成的大链表。
    嘛操作系统怎么处理这东西不管了,反正你就可以认为堆空间是可用内存里的一片连续区域
    malloc函数的作鼡就是从这一片内存中划出一块空间来。你可以认为是malloc从内存中找到了一片可以安全存放数据的可用空间这样你的数据就可以放在这片涳间里面。这片空间的大小是你自己指定的通过malloc(字节数)这样简单的方法。

    为了找到这片空间malloc函数会告诉你这片空间开头的地址,你可鉯把它赋值给一个变量存放起来
    这样我们就知道申请到的这片内存的首地址(malloc返回)和大小(程序员指定)了。

    C语言的给指针分配内存吔有类型但是给指针分配内存总是内存地址,是一个(32位/64位)二进制整数长度也好大小也好都是确定的,理应一种类型就够了那么,给指针分配内存类型的作用是什么呢其实给指针分配内存类型就是用于判断给指针分配内存所指向的数据的类型。

    不得不说这是一个非常天才的设计
    给指针分配内存里存放着的是一个地址,它能找到一个内存单元(复杂的东西不说了操作系统都给你做了,你就认为昰某一个字节就好这个括号内部的东西写给某些较真的人看,实际上并不存在一种叫做内存单元的东西),但是数据有长有短数据們有些存在1个内存单元里面,有些存在多个内存单元里面
    给指针分配内存是为了指向一个数据,那么用什么方法可以知道这个给指针汾配内存想要的,到底是几个内存单元里的数据呢

    C语言里用了一种十分巧妙的设计——给指针分配内存类型。一个给指针分配内存指向┅个字节地址这个给指针分配内存的类型所代表的数据结构是8个字节,那么我们就把这8个字节里面的东西都读出来作为这个给指针分配内存所指向的数据的值。

    举个栗子:比如说从地址是1000开始的内存是以下的一片样子:
    然后我有个给指针分配内存a它的值是1000。
    如果这个給指针分配内存是int *a当我用*a去访问数据的时候,就会返回【11 】
    但是如果这个给指针分配内存是double *a当我用*a去访问数据,返回的就是【11 10 01000】这些數据了

    不过这个给指针分配内存值可是没有变化的,变化的只是给指针分配内存类型而已

    [ ]运算符是C语言几乎最高优先级的运算符。[ ]运算符需要两个操作数一个给指针分配内存类型,一个整数/*补充[1]*/
    标准的写法是这样的:。这样编译器会返回 *(a+i) 的值

    这样做的话相当于一個十分好用的临时给指针分配内存的移动。如果我要访问第12个变量只需要写a[11]就好了编译器会理解这个运算的规则,自动的把a给指针分配內存进行一次以下的操作:int *temp;temp=a+11;return *temp;嗯大概就是这个样子。


}

C/C++定义了4个内存区间:

    代码区全局变量与静态变量区,局部变量区即栈区动态存储区,即堆(heap)区或自由存储区(free store)

通常定义变量(或对象),编译器在编译时都可鉯根据该变量(或对象)的类型知道所需内存空间的大小从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存儲分配;

    有些操作对象只在程序运行时才能确定这样编译时就无法为他们预定存储空间,只能在程序运行时系统根据运行时的要求进荇内存分配,这种方法称为动态存储分配所有动态存储分配都在堆区中进行。

当程序运行到需要一个动态分配的变量或对象时必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象当不再使用该变量或对象时,也就是它的生命结束时要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配做到重复使用有限的资源。

2.堆内存的分配与释放

堆空间申请、释放的方法:

在C++中申请和释放堆中分配的存贮空间,分别使用new和delete的两个运算符来完成:   


给指针分配内存变量名=new 类型名(初始化式);

区别:pi所指向的變量是由库操作符new()分配的位于程序的堆区中,并且该对象未命名  

堆空间申请、释放说明:

⑴.new运算符返回的是一个指向所分配类型變量(对象)的给指针分配内存。对所创建的变量或对象都是通过该给指针分配内存来间接操作的,而且动态创建的对象本身没有名字

⑵.一般定义变量和对象时要用标识符命名,称命名对象而动态的称无名对象(请注意与栈区中的临时对象的区别,两者完全不同:生命期不同操作方法不同,临时变量对程序员是透明的)

⑶.堆区是不会在分配时做自动初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化new表达式的操作序列如下:从堆区分配对象,然后用括号中的值初始化该对象

3.堆空间申请、释放演示:

⑵.当pi生命周期结束时,必須释放pi所指向的目标:

注意这时释放了pi所指的目标的内存空间也就是撤销了该目标,称动态内存释放(dynamic memory deallocation)但给指针分配内存pi本身并没囿撤销,它自己仍然存在该给指针分配内存所占内存空间并未释放。

下面是关于new 操作的说明

⑴.new运算符返回的是一个指向所分配类型变量(对象)的给指针分配内存对所创建的变量或对象,都是通过该给指针分配内存来间接操作的而动态创建的对象本身没有名字。
   ⑵.一般定义变量和对象时要用标识符命名称命名对象,而动态的称无名对象(请注意与栈区中的临时对象的区别两者完全不同:生命期不同,操作方法不同临时变量对程序员是透明的)。

⑶.堆区是不会在分配时做自动初始化的(包括清零)所以必须用初始化式(initializer)来显式初始化。new表达式的操作序列如下:从堆区分配对象然后用括号中的值初始化该对象。

4. 在堆中建立动态一维数组

给指针分配内存变量名=new 类型名[下標表达式];

注意:“下标表达式”不是常量表达式即它的值不必在编译时确定,可以在运行时确定

注意:方括号非常重要的,如果delete语句Φ少了方括号因编译器认为该给指针分配内存是指向数组第一个元素的,会产生回收不彻底的问题(只回收了第一个元素所占空间)加了方括号后就转化为指向数组的给指针分配内存,回收整个数组delete [ ]的方括号中不需要填数组元素数,系统自知即使写了,编译器也忽畧

5. 动态一维数组的说明

① 变量n在编译时没有确定的值,而是在运行中输入按运行时所需分配堆空间,这一点是动态分配的优点可克垺数组“大开小用”的弊端,在表、排序与查找中的算法若用动态数组,通用性更佳一定注意:delete []pc是将n个字符的空间释放,而用delete pc则只释放了一个字符的空间;

② 如果有一个char *pc1令pc1=p,同样可用delete [] pc1来释放该空间尽管C++不对数组作边界检查,但在堆空间分配时对数组分配空间大小昰纪录在案的。

③ 没有初始化式(initializer)不可对数组初始化。


6.给指针分配内存数组和数组给指针分配内存

一个数组里存放的都是同一个类型嘚给指针分配内存通常我们把他叫做给指针分配内存数组。

 一个指向一维或者多维数组的给指针分配内存.

注意这个时候释放空间一定偠delete [] ,否则会造成内存泄露, b 就成为了空悬给指针分配内存

注意:在这里b2等效于二维数组名,但没有指出其边界即最高维的元素数量,但昰它的最低维数的元素数量必须要指定!就像指向字符的给指针分配内存即等效一个字符串,不要把指向字符的给指针分配内存说成指向芓符串的给指针分配内存。

new 类型名[下标表达式1] [下标表达式2]……;

例如:建立一个动态三维数组

注意:cp等效于三维数组名但没有指出其边界,即最高维的元素数量就像指向字符的给指针分配内存即等效一个字符串,不要把指向字符的给指针分配内存,说成指向字符串的给指针汾配内存这与数组的嵌套定义相一致。

     两个数组都是由600个浮点数组成前者是只有一个元素的三维数组,每个元素为30行20列的二维数组洏另一个是有30个元素的二维数组,每个元素为20个元素的一维数组


//1、先看二维数组的动态创建:

//3、再看二维数组的撤销与内存释放:

二维數组的内存释放可以做成函数,

通过给指针分配内存使堆空间编程中的几个可能问题

⑴.动态分配失败。返回一个空给指针分配内存(NULL)表示发生了异常,堆资源不足分配失败。

⑵.给指针分配内存删除与堆空间释放删除一个给指针分配内存p(delete p;)实际意思是删除了p所指嘚目标(变量或对象等),释放了它所占的堆空间而不是删除p本身,释放堆空间后p成了空悬给指针分配内存,不能再通过p使用该涳间在重新给p赋值前,也不能再直接使用p

⑶.内存泄漏(memory leak)和重复释放。new与delete 是配对使用的 delete只能释放堆空间。如果new返回的给指针分配内存值丢失则所分配的堆空间无法回收,称内存泄漏同一空间重复释放也是危险的,因为该空间可能已另分配所以必须妥善保存new返回嘚给指针分配内存,以保证不发生内存泄漏也必须保证不会重复释放堆内存空间。

⑷.动态分配的变量或对象的生命期无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用我们也称堆空间为自由空间(free store)就是这个原因。但必须记住释放该对象所占堆空间并只能释放一次,在函数内建立而在函数外释放是一件很容易失控的事,往往会出错 

编程学习-动態内存分配-基于C++类

 通过new建立的对象要调用构造函数,通过deletee删除对象也要调用析构函数

    堆对象的生命期并不依赖于建立它的作用域,所以除非程序结束堆对象(无名对象)的生命期不会到期,并且需要显式地用delete语句析构堆对象上面的堆对象在执行delete语句时,C++自动调用其析构函数

正因为构造函数可以有参数,所以new后面类(class)类型也可以有参数这些参数即构造函数的参数。
但对创建数组则无参数,並只调用缺省的构造函数见下例类说明:

  CGoods(){}; //缺省构造函数。因已有其他构造函数系统不会再自动生成缺省构造,必须显式说明

//下面注意如何使用:

 //动态建立数组,不能初始化调用n次缺省构造函数 

此例告诉我们堆对象的使用方法:

申请堆空间之后构造函数运行;

释放堆涳间之前析构函数运行;

再次强调:由堆区创建对象数组,只能调用缺省的构造函数不能调用其他任何构造函数。如果没有缺省的构造函数则不能创建对象数组。

对象的构造也可以由拷贝构造函数完成,即用一个对象的内容去初始化另一个对象的内容

此时,若对象使用了堆空间(注意和“堆对象”区分)就有深、浅拷贝的问题,不清楚则很容易出错

2、浅拷贝可能带来什么问题?

4、深拷贝的实现方法

缺省拷贝构造函数:用一个对象的内容初始化另一个同类对象,也称为缺省的按成员拷贝不是对整个类对象的按位拷贝。这种拷貝称为浅拷贝

} //程序执行完,对象pc1和pc将被析构此时出错。

析构时如用缺省的析构函数,则动态分配的堆空   

如果用有“delete Name;”语句的析构函數则先

这时就要重新定义拷贝构造函数,给每个对象独

深拷贝——自定义拷贝构造

  //加1不可少否则串结束符冲了其他信息,析构会出错!

堆内存是最常用的需要自定义拷贝构造函数的资源但不是唯一的,如打开文件等也需要

   如果类需要析构函数来释放某些资源,则类吔需要一个自定义的拷贝构造函数此时,对象的拷贝就是深拷贝了

}

我要回帖

更多关于 给指针分配内存 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信