首页 > 系统相关 >《c++高级编程》笔记--内存管理

《c++高级编程》笔记--内存管理

时间:2023-09-04 16:06:30浏览次数:40  
标签:-- c++ char int 内存 数组 new 指针


作者:fbysss
关键字:C++内存管理
《c++高级编程》笔记
1.new关键字
使用关键字new时,内存是在堆(heap)里分配的,不使用new,内存是在堆栈(stack)分配的。
句柄handle一般用来描述一个指针的指针。
之所以使用“句柄”,是因为句柄允许底层软件在必要时移动内存。
使用new的时候,会返回一个指针,并且必须要把这个指针存储到一个变量中。否则就成了孤立内存,因为没法释放了。

比如new int;这句话可以编译通过,但是无法管理。
new 与malloc的区别:
new 不仅仅可以分配内存空间,而且会构造对象,也就是说,在调用new时,会调用对象的构造函数。同理,delete会调用协构函数,而free不会。
建议只使用new和delete
2.数组 int len = 3;
 //int * dynaArray = new int[len];//可以通过
 int arr[len] ;//编译不通过,len必须是常量
dynaArray 只能说是半动态数组,运行期间要动态自由的改变数组长度,只能用vector了。
       使用new给数组分配内存时,只能使用指针变量。int dynaArray[]=new int[len]是不可以的。
realloc()是c遗留函数,作用是按照新容量分配一个内存块,把旧数据移动到新位置,从而有效地改变数组长度。但建议在c++中不要使用。
new 一个对象数组的时候,比如Simple * mySimpleArray= new Simple[4]
Simple的构造函数会执行四次(很显然。不过就是创建多个对象)。
删除数组用delete[],但只有数组中的元素是纯对象时才会调用协构函数,也就是数,只是对于一维数组来讲的。多维数

组或者指针数组,就需要分别处理,分配内存也同样如此。

Simple ** mySimplePtrArray= new Simple*[4];
//单独分配:
for (int i = 0 ; i <4 ; i++){
    mySimplePtrArray[i] = new Simple();
}
//单独释放:
for (int i = 0 ; i <4 ; i++){
   delete mySimplePtrArray[i];
}
//最后释放数组本身:
delete[] mySimplePtrArray;new 与delete配对使用
new []与delete[]配对使用。


3.多维数组
多维数组在内存中实际上是按照如一维数组那样顺序存放的。
要注意一点:多维数组不能像上面的一维数组那样初始化时长度为变量。
char ** board = new char[i][j]是编译不通过的。char[1][j] char[i][1]同样不行。
因为new分配是基于堆的,为其分配的内存是不连续的。正确的做法是,必须先为基于对的数组的第一维分配一个连续的

数组。该数组的每个元素实际上是指向另一个数组的指针,后面这个数组存储了对应第二维下标的元素。

char** allocateCharacterBoard(int xDimension,int yDimension)
{
    char **myArray = new char * [xDimension];//分配第一维数组
    for (int i = 0 ; i < xDimension; i ++)
    {
        myArray[i] = new char [yDimension];//分配子数组
    }
}释放内存:
void releaseCharacterBoard(char** myArray,int xDimension)//由于编译器无法识别数组长度,所以需要单独传入
{
    for (int i = 0 ; i< xDimension; i ++){
 delete[] myArray[i];   //释放子数组
    }
    delete[] myArray;          //释放第一维数组。
}


问题:参考上面的程序,为何这里可以用new char[yDimension]分配,delete[]删除子数组,上面的程序却不可以呢?
实际上,仔细看看就知道了,还是一样的。只不过上面是一个一维数组,每个元素为指针罢了。

--数组是指针,但指针不一定是数组
比如指针参数可以用数组传入,而int * a = new int; a[1]就不知道是什么了,虽然能编译通过。
4.字符串
c语言中的字符串,长度是实际字符串长度(strlen函数)+1,因为有一个'/0'.
 char msg [2]="/0";
 strcat(msg,"123456789");
可以。但是char msg[1]="/0";错误,因为数组长度太小。 

 char *msg = new char[1];
 strcpy(msg,"123456789");
可以通过,但是存在严重隐患,因为msg的预留空间太小,虽然msg可以正常显示了,但紧跟其后面的内容有就被覆盖掉了,一定要小心,strcpy,strcat都存在类似问题

推荐使用string来管理字符串。string.c_str()函数可以转换为c风格的字符串。
--------
char * prt= "hello";相当于const char* ptr = "hello";也就是说使用
ptr[1]='a';运行时会报错,因为字符串常量在内存中只有一个实例,该内存只读。
char stackArray[]="hello"; stackArray[1]='a'就可以了。
因为基于栈的变量在任何情况下都不可能引用其他地方的内存。
4.指针运算
myArray[2]  等价于 *(myArray+2)
5.函数指针
好处是可以把函数作为一个参数,这样,函数的具体实现可以根据需要进行替换。
6.内存泄露相关--valgrind是linux下查找内存泄露的一个工具

--二次删除与无效指针
二次删除:
delete(ptr);
doSomething();//假设这里占用了刚才释放的内存空间
delete(ptr);//二次删除,把doSomething所占空间释放了,隐患。
无效指针:
delete(ptr);
ptr还可以用。但内容已经不知道是什么了。
--访问越界指针
比如一个字符串指针,按照设计,在'/0'之前操作是安全的,一旦超出这个范围,可能覆盖掉别的内容,从而导致程序崩溃。一个错误的例子:
void fillWithM(char * inStr)
{
   int i = 0 ;
  while(inStr[i]!='/0'){
    inStr[i] = 'm';
    i++;
 }
}


本意是填充字符串为m,殊不知很可能这个字符串丢掉了'/0',结果,后面的内容就不能保证是否被覆盖了。
--智能指针auto_ptr可以把动态分配的对象在超出作用域时释放。语法很难看,等需要再研究。

另外要注意局部指针问题,因为指针是在函数内部分配的,调用该函数之后,很容易忘记去delete该指针,所以最好是先分配,再传入参数,再释放。

 

 

标签:--,c++,char,int,内存,数组,new,指针
From: https://blog.51cto.com/u_16245757/7351661

相关文章

  • Xml2Bean:为Webservice返回Collection准备的一个实用类
    作者:fbysss关键字:Webservice,Xml2Bean背景:Webservice 返回的是xml,如何得到Collection类型呢?最简单的方式就是把xml还原成Collection。准备包:commons-digester-1.8.jar源代码1:Xml2Beanpackagecn.edu.ustb.db.task.util;/***//***<p>标题:Xml2Bean.java</p>......
  • SqlServer2000数据库迁移"用户已存在"问题解决
    作者:fbysss关键字:sqlserver数据库用户,关联缺失背景:数据库从另外一台服务器备份之后还原,发现程序中登录数据库失败。排查:发现"安全性"->"登录"中的数据库用户与数据库没有关联,但是手工再关联,却报出错误21002:[sql-dmo]用户***已经存在的异常信息。而删除该数据库用户也无法进行,因为......
  • 迅雷占用80端口,小心了
        今天安装Apache的时候居然说80端口被占用,但本机并没有安装过IIS和apache,tomcat是8080,为何?    用netstat-ano 一查,找到0.0.0.0:80对应的pid,用tasklist查到该程序居然是Thunder.exe!真是没有想到。      很久以来,我对迅雷的印象还是不错的,但自从Web迅雷推......
  • sql server2005 jdbc解决自动自动增长列统一处理问题纪实
    作者fbysss关键字:自动增长列,jdbc,sqlserver2005背景:系统要支持多种数据库,统一insert的时候获取自动增长列的处理方式问题1:insert+select方案sqlserver2000可以使用insertSql +SELECT@@IDENTITYAS'Identity'的方式来获得,但是mysql则只能使用executeUpdate(insertSql);execut......
  • css盒子,很棒
    作者:fbysss关键字:css盒子css盒子模式其实还是很好的,今后的布局应该坚决贯彻。一些基础知识与技巧:1.什么是BOX?CSS把HTML中以<somesign>……</somesign>的部分称为BOX(容器),BOX有三类属性:padding、margin和border。2.在CSS中,类选择符在一个半角英文句点(.)之前,而id则在半角英文井号(#)......
  • 软件测试 | Dalvik虚拟机是如何执行程序的
    Android系统的架构采用分层思想,这样的好处是拥有减少各层之间的依赖性、便于独立分发、容易收敛问题和错误等优点。Android系统由Linux内核、函数库、Android运行时、应用程序框架以及应用程序组成。如图3-4的Android系统架构所示,Dalvik虚拟机属于Android运行时环境,它与一些核心库......
  • Tomcat5.5的管理模块的几点注意事项
    作者fbysss关键字:Tomcat,adminTomcat5.5默认没有admin模块了.得单独去网站下.下载后,根据相同目录结构拷贝到tomcat下.另外需要注意几个地方:否则点击TomcatAdministration会出现"Tomcat'sadministrationwebapplicationisnolongerinstalledbydefault.Downloadandinst......
  • Subversion 加锁功能
    作者fbysss关键字:svn   Subversion一样可以加锁,只不过需要单独去操作。checkout不会自动加锁。在Tortoise中可以使用GetLock菜单项来操作。   如果加锁者出差了,如何打开锁呢?通过breaklock来实现。这个好像要在browse里面进行。不用担心强行解锁会如何,因为一切操作都有记......
  • 软件测试 | Selenium-Grid架构
    Selenium-Grid是基于传统Selenium架构发展起来的,它有如下优点:1.Selenium测试案例、待测Web应用系统、RemoteControl/浏览器组合之间无须紧密耦合。它们之间通过HTTP进行通信,因此不需要工作在一台机器上。2.Selenium测试案例和待测Web应用系统与具体项目相关。不过,无论SeleniumRem......
  • Python爬虫——新手使用代理ip详细教程
    Python代理IP爬虫是一种可以让爬虫拥有更多网络访问权限的技术。代理IP的作用是可以为爬虫提供多个IP地址,从而加快其爬取数据的速度,同时也可以避免因为访问频率过高而被网站封禁的问题。本文将介绍如何使用Python实现代理IP的爬取和使用。一、代理IP的获取首先我们需要找到一个可用......