本文汇总了一下C/C++中用到的一些关于内存使用方面的用法~
-----------------------------malloc/free---------------------
百度百科 名称解释:malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。
malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。
函数原型:
void *malloc(unsigned int num_bytes);
头文件:
#include <stdlib.h>
或者
#include <malloc.h>
返回值:如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。关于该函数的原型,在以前malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。
工作机制:
malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内存块时,一定要进行返回值的判断。正确的使用实例:
typedef struct data_type
{
int age;
char name[20];
}data;
data*bob=NULL;
bob=(data*)malloc(sizeof(data));
if(bob!=NULL)
{
bob->age=22;
strcpy(bob->name,"Robert");
printf("%sis%dyearsold\n",bob->name,bob->age);
}
else
{
printf("mallocerror!\n");
exit(-1);
}
free(bob);
bob=NULL;
注:1. 根据malloc的使用机制,在写程序时需要验证malloc是否正确申请到内存,即验证是否==NULL,并在使用结束后free().否则可能会出现内存泄漏的意外情况。
2. malloc与free一定要配对使用,否则会出现问题,如果申请了空间但未释放这就会造成内存泄漏,而释放只能进行一次,释放多次会出现错误;(释放空指针例外,释放空指针等于什么也没做,所以释放多次也无所谓)
3. 虽然void*可以指向任意类型的指针,但是最好在使用前,将其强转成指定类型,这样可以更好的避过有些编译器的优化;
----------------------------memcpy---------------------------
C语言memccpy()函数:复制内存内容(忽略\0),头文件:
#include <string.h>
定义函数:
void * memcpy ( void * dest, const void * src, size_t num );
memcpy() 会复制 src 所指的内存内容的前 num 个字节到 dest 所指的内存地址上。memcpy() 不关心被复制的数据类型,只是逐字节地进行复制,可以面向任何数据类型进行复制。需要注意的是:
dest 指针要分配足够的空间,即大于等于 num 字节的空间。如果没有分配空间,会出现错误。
dest 和 src 所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全)。
另外,memcpy()与 strcpy() 的不同点事,memcpy() 会完整的复制 num 个字节,不会因为遇到“\0”而结束。
//memcpy实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N (10)
int main()
{
char* p1 = "fcqing"; //注意,这里p1字节数需要小于N,否则会出现错误。
char* p2 = (char*)malloc(sizeof(char)* N);
char* p3 = (char*)memcpy(p2, p1, N);
printf("p2 = %s\np3 = %s\n", p2, p3);
free(p2);
p2 = NULL;
p3 = NULL;
system("pause");
return 0;
}
memcpy对内存空间有要求的,dest和src所指向的内存空间不能重叠,否则复制的数据是错误的.如果内存空间布局入下图所示:
src所指向的内存空间后面部分数据被新拷贝的数据给覆盖了(也就是dest<=src+size).所以拷贝到最后,原来的数据肯定不是原来的数据,拷贝的数据也不是想要的数据,使用memcpy函数可以得到错误的结果.
----------------------------new/free--------------------------
new 和 delete 是 C++ 用于管理堆内存的两个运算符,对应于 C 语言中的 malloc 和 free,但是 malloc 和 free 是函数,new 和 delete 是运算符。除此之外,new 在申请内存的同时,还会调用对象的构造函数,而 malloc 只会申请内存;同样,delete 在释放内存之前,会调用对象的析构函数,而 free 只会释放内存。
当使用关键字new在堆上动态创建一个对象时,new 运算符的内部实现分为两步:
(1)内存分配
调用相应的 operator new(size_t) 函数,动态分配内存。如果 operator new(size_t) 不能成功获得内存,则调用 new_handler() 函数用于处理new失败问题。如果没有设置 new_handler() 函数或者 new_handler() 未能分配足够内存,则抛出 std::bad_alloc 异常。“new运算符”所调用的 operator new(size_t) 函数,按照C++的名字查找规则,首先做依赖于实参的名字查找(即ADL规则),在要申请内存的数据类型T的 内部(成员函数)、数据类型T定义处的命名空间查找;如果没有查找到,则直接调用全局的 ::operator new(size_t) 函数。
(2)构造函数
在分配到的动态内存块上 初始化 相应类型的对象(构造函数)并返回其首地址。如果调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。
delete 运算符的内部实现分为两步:
(1)析构函数
调用相应类型的析构函数,处理类内部可能涉及的资源释放。
(2)内存释放
调用相应的 operator delete(void *) 函数。调用顺序参考上述 operator new(size_t) 函数(ADL规则)。
每个 new 获取的对象,必须用 delete 析构并释放内存,以免 内存泄漏。
new语法:
1)new int;
开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.
2)int *a = new int(5) 作用同上,但是同时将整数赋值为5
2. 开辟数组空间
一维: int *a = new int[100];开辟一个大小为100的整型数组空间
二维: int **a = new int[5][6]
三维及其以上,依此类推.
实例:
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test构造函数" << endl;
str = new char[2];
}
~Test(){
cout << "Test析构函数" << endl;
delete[] str;
}
private:
char * str;
};
int main(int argc, char* argv[])
{
char buf[100];
Test *p = new(buf)Test(); // Test()产生的临时变量用于初始化 指定内存地址
p->~Test(); // 主动调用析构函数,避免内存泄漏。
char * buf2 = new char[100];
Test * p2 = new(buf2)Test();
p2->~Test(); // 切记,主动调用析构函数
delete[] buf2; // 堆内存需要主动释放
return 0;
}
------------------------malloc与new的区别----------------------
特征 | new/delete | malloc/free |
---|---|---|
分配内存的位置 | 自由存储区 | 堆 |
内存分配失败返回值 | 完整类型指针 | void* |
内存分配失败返回值 | 默认抛出异常 | 返回NULL |
分配内存的大小 | 由编译器根据类型计算得出 | 必须显式指定字节数 |
处理数组 | 有处理数组的new版本new[] | 需要用户计算数组的大小后进行内存分配 |
已分配内存的扩充 | 无法直观地处理 | 使用realloc简单完成 |
是否相互调用 | 可以,看具体的operator new/delete实现 | 不可调用new |
分配内存时内存不足 | 客户能够指定处理函数或重新制定分配器 | 无法通过用户代码进行处理 |
函数重载 | 允许 | 不允许 |
构造函数与析构函数 | 调用 | 不调用 |
参考:
http://www.cnblogs.com/GarfieldEr007/p/5594524.html
http://www.jb51.net/article/71559.htm
http://www.linuxidc.com/Linux/2016-01/127591.htm
http://blog.youkuaiyun.com/hihozoo/article/details/51441521