来自http://blog.csdn.net/bizhu12/article/details/6668834
这篇文章是我在学习高质量C++/C编程指南
中的第7章"内存管理"后的一篇笔记,之前我也写过相关的文章指针以及内存分配
,但我感觉那篇还不是很好,这篇我很把它更完善一些
一.内存的常见分配方式
1. 从静态区分配,一般是全局变量和static类型变量
2.从栈区分配内存,一般是局部的变量,会随着所在函数的结束而自动释放
3.从堆中分配,一般是使用手动分配,使用malloc()函数和new来申请任意大小空间,不过要手动释放空间,相应的使用free()函数和delete释放, 如果不释放该空间,而且指向该空间的指针指向了别的空间.则该空间就无法释放,造成内存泄露,造成了内存浪费
二.内存的使用规则
1.在使用malloc()或new申请空间时,要检查有没有分配空间成功,判断方法是判断指针是否为NULL,如申请一块很大的内存而没有这么大的内存则分配内存会失败
2.申请成功后最好是将该内存清空,使用memset()后ZeroMemory()清空,不然存在垃圾而造成有时候输出很大乱码
3.不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。(这句话不太理解)
4.要防止数组或指针内存越界,
5.申请内存成功后,使用结束后要释放,系统不会自动释放手动分配的内存
6.内存释放后,指针还是指向那块地址,不过这指针已经是"野指针"了,所以释放内存后指针要指向NULL,不然很危险,容易出错,if()对野指针的判断不起作用
三.指针和数组
1
. 数组里的数据可以单个修改,但指针的不行,如我的例子,char str[] = "hello",数组的大小有6个字符(注意\0),可以通过str[0] = 'X'修改了的个字符,而指针
char *p = "Word",p是指向了一串常量的字符串,常量字符串是不可修改的,如 p[0] = 'X',编译器编译时不会保存,但执行时会出错
2
.内容的复制与比较
内容的复制要使用strcpy()函数,不要使用赋值符"=",内容的比较也是不要使用比较符号"<,>,==",使用strcmp()函数
// 数组…
char a[] = "hello";
char b[10];
strcpy(b, a); // 不能用 b = a;
if(strcmp(b, a) == 0) // 不能用 if (b == a)
// 指针…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1)); //注意此处是 len+1,要算上 "\0"
strcpy(p,a); // 不要用 p = a;
if(strcmp(p, a) == 0) // 不要用 if (p == a)
3
,计算空间的大小
对数组的计算是使用sizeof()函数,该函数会按照内存对齐
的方式4的倍数计算,而指针的空间大小没法计算,只能记住在申请空间时的空间大小
注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针,不论数组a的容量是多少,sizeof(a)始终等于sizeof(char *)
void Func(char a[100]) //这是因为在传参数
{
cout<< sizeof(a) << endl; // 4字节而不是100字节
}
四.指针的内存的传递????
如果函数的参数是指针,则不要使用该参数来申请内存空间,这样没有实际的用处,而且这样当函数结束时还得不到释放内存而造成内存泄露
这个问题可以使用"指针的指针"的方法可以解决,不然使用返回指针地址的办法,先看一下使用 "指针的指针"方法,
还可以考虑一下引用
使用返回内存地址的方法
使用返回的方式传递内存地址容易出错的地方在于放回"栈内存"的指针,当GetMemory()函数结束时栈内存也被释放,
像这个代码
char *GetString2(void)
{
char *p = "hello world";
return p;
}
void Test5(void)
{
char *str = NULL;
str = GetString2();
cout<< str << endl;
}
函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,
它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
五.动态内存释放问题与野指针
1. 当我们使用free()和delete释放一块内存时,指针还是指向原来的地址,不过这时候的指针时野指针,
可以验证一下.这图是我调试到if()语句时的情况,p还没有指向NULL,只是释放了p指向的空间了
执行的结果可以看看...
所以有这样的一些特征:
1.指针销毁了,并不表示所指的空间也得到了释放 :内存泄露
2.内存被释放了,并不表示指针也被销毁了或指向NULL :野指针
六.malloc()/free()与new/delete的区别(摘抄原文)
malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,
光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函
数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,看代码
class Obj
{
public :
Obj(void){ cout << “Initialization” << endl; }
~Obj(void){ cout << “Destroy” << endl; }
void Initialize(void){ cout << “Initialization” << endl; }
void Destroy(void){ cout << “Destroy” << endl; }
};
void UseMallocFree(void)
{
Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存
a->Initialize(); // 初始化
//…
a->Destroy(); // 清除工作
free(a); // 释放内存
}
void UseNewDelete(void)
{
Obj *a = new Obj; // 申请动态内存并且初始化
//…
delete a; // 清除并且释放内存
}
类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于
malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数
UseNewDelete则简单得多。
所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态
内存”,理论上讲程序不会出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。
七.如何处理内存耗尽
1.判断指针是否为NULL,如果是则马上用return语句终止本函数
2.判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行
3.为new和malloc设置异常处理函数。例如Visual C++可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,
也可以让malloc享用与new相同的异常处理函数
分享到:
相关推荐
5. 动态内存管理:库中的智能指针(如std::unique_ptr, std::shared_ptr)和内存分配器(如std::allocator)帮助开发者更安全、更有效地管理动态内存。智能指针自动管理对象的生命周期,避免了内存泄漏问题;而分配...
7. **内存管理1**(8_第八讲-内存管理1-01.pptx):C++提供了对内存的直接控制,包括动态内存分配(new和delete)和栈内存的使用。理解内存管理有助于避免内存泄漏和悬空指针等问题,这对于编写高效且健壮的代码至关...
在IT领域,加密和解密技术是信息安全的重要组成部分,用于保护数据的...此外,C++实现时还要考虑内存管理、错误处理和性能优化等因素。学习和掌握这些算法的源码,对于提升程序员在信息安全领域的专业技能至关重要。
- **内存管理**:使用智能指针(如`std::unique_ptr`和`std::shared_ptr`)防止内存泄漏。 - **编译与构建**:了解如何使用Makefile或现代构建系统(如CMake)来编译和链接项目。 - **测试**:编写单元测试确保代码...
- **资源受限**:由于体积小、功耗低等特点,嵌入式系统通常配备有限的内存和处理器能力。 - **专用性**:每个嵌入式系统都是针对特定应用定制的。 #### 3. 嵌入式系统的设计与开发 - **硬件平台选择**:根据应用...
**内存管理** - **堆与栈**:掌握堆内存与栈内存的区别及其应用场景。 - **智能指针**:熟悉`shared_ptr`、`unique_ptr`等智能指针的使用,了解它们如何帮助避免内存泄漏。 #### 3. **模板与泛型编程** - **...
总之,CString通过动态内存管理和写入复制技术,既提供了方便的字符串操作接口,又有效地避免了C风格字符串可能导致的问题。理解这些底层机制,有助于我们在使用CString时做出更高效、更安全的决策,编写出更加可靠...
这些对象包括接口状态、内存使用、CPU负载等。而SNMP Trap是SNMP协议的一种机制,当网络设备上发生异常情况时,设备会自动发送一个陷阱消息到预先配置的管理站,通知管理员有需要关注的情况。 【详细知识点】 1. ...
5. **动态内存管理**:在游戏过程中,随着蛇的增长,需要动态地分配和释放内存空间,以存储蛇的身体信息。 #### 五、项目实现步骤 1. **初始化游戏窗口**:设置游戏窗口的大小、背景颜色等基本属性。 2. **定义蛇...
- **内存管理**:`Mat` 提供了灵活的内存管理机制,支持动态调整图像尺寸等功能。 - **多维度支持**:除了作为图像容器之外,`Mat` 还可以用来存储更高维度的数据,如三维体积数据等。 ### 总结 通过上述介绍,...
在C++编程语言中,数据结构是至关重要的概念,它涉及到如何有效地组织和管理大量数据。本项目"用C++实现的数据结构所有的算法"旨在提供一个全面的实践平台,涵盖了一系列基本和高级数据结构以及相关的操作算法。让...
1. **内存管理**:在处理大型图像或大量图像时,需要注意内存管理,避免因内存溢出导致程序崩溃。 2. **边界条件**:在处理图像边界时,选择合适的边界扩展方式以避免图像边缘出现明显的伪影。 3. **性能优化**:...
- **资源管理**:C++提供了更精细的资源管理和内存控制能力,这对于大型游戏的高效运行至关重要。 #### 2. 后台游戏开发技术要点 - **网络编程**:游戏服务器端通常需要处理大量并发连接,因此熟练掌握网络编程技巧...
C++源码可以帮助你掌握内存管理、模板、STL库和设计模式等深入内容。 这些源码网址大全提供了一个集中的平台,方便程序员查找、学习和下载各种编程语言的源代码。例如,51源码(www.51aspx.com)专注于ASP.NET相关...
在本篇文章中,我们将深入探讨C++结合OpenCV3实现图像金字塔及图像缩放功能的具体方法与技术细节。...需要注意的是,在实际开发过程中,还需要考虑更多的细节问题,比如内存管理、错误处理等,以便写出更健壮的代码。
标题中的"GIZA++运行报告zz"指的是一个关于GIZA++工具的使用或分析的文档,这通常涉及...在实践中,用户可能会遇到如内存管理、并行化训练、优化参数等问题,这些问题的解决方法通常是GIZA++使用经验的重要组成部分。
C语言是一种基础且强大的编程语言,它允许低级别的内存管理和高效的代码执行,因此是实现算法的理想选择。虽然代码可能较长,但通常是为了处理复杂性和细节,确保算法的正确性与效率。 匈牙利算法的基本思想是通过...
它的设计允许用户在编译时选择不同的内存管理和数值表示策略,以适应不同的性能需求和应用场景。 总的来说,"NTL库VC6.0测试工程"是一个很好的起点,可以帮助开发者熟悉NTL库在Windows下的编译和使用,以及如何将...
2. **资源管理**:使用完文件后要及时释放资源,避免内存泄漏。 3. **兼容性问题**:注意不同版本的OpenCV可能在API细节上有所不同。 通过以上介绍,我们了解了如何使用C++和OpenCV 3来读取XML和YAML文件的基本方法...