内存分配方式
- 静态存储区
全局变量 static 变量
- 栈 效率高
函数内局部变量
- 堆
堆和栈:
栈:编译器分配
堆:程序员手动分配
对于堆来讲,频繁的new/delete
势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低
内存错误
- 未成功分配
assert(p!=NULL)
if(p==NULL)
-
成功分配,未初始化
默认值不一定是0,进行必要的初始化和赋零工作
e. 数组没有初始化 -
越界
-
忘记释放内存,内存泄漏
-
操作已经释放的内存
- 野指针,free/delete之后没有置为 NULL
- 返回“栈”上的指针/引用
- 调用关系复杂,需重新设计数据结构
指针变量在创建的同时应当被初始化,要么将指针设置为 NULL,要么让它指向合法的内存。
char *p = NULL;
char *p = (char*)malloc(100);
delete
之后要设置为 NULL
,避免指向一段被释放的内存,同时不要释放已释放的内存,结果是不确定的,但如果设置为 NULL
,对空指针使用 delete
是安全的。
同理,free
也是一样的。如果 p
是 NULL
指针,那么 free
对 p
无论操作多少次都不会出问题。如果 p
不是 NULL
指针,那么 free
对 p
连续操作两次就会导致程序运行错误。
Notice:
1. malloc/new申请内存之后,应立即检查指针是否为NULL,防止使用NULL的内存
2. 数组和动态内存赋初值
3. 注意可能越界的操作
4. 动态内存的申请和释放要对应,防止内存泄漏
5. free/delete之后要置为NULL,防止野指针产生
指针和数组对比
- 数组
数组名对应着一块内存,其地址和容量在生命期内保持不变,地址中的内容可以改变
函数返回指针时 不要 return 栈内存指针
char *GetString(void)
{
char p[] = "hello world";
return p; // 编译器将提出警告
}
malloc/free 和 new/delete
对于非内部数据类型的对象而言,光用 malloc/free
无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于 malloc/free
是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于 malloc/free
。
所以我们不要企图用 malloc/free
来完成动态对象的内存管理,应该用new/delete
。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言 malloc/free
和new/delete
是等价的。