C++自学21:动态分配内存(malloc/calloc/realloc/new)/回收内存(free/delete)
原创
©著作权归作者所有:来自51CTO博客作者文天大人的原创作品,请联系作者获取转载授权,否则将追究法律责任
一:malloc函数,请求系统分配内存
// 让系统分配8个字节的内存,这8个字节是连续的,就是一个数组
int* a=(int*)malloc(8);
// 如果分配成功,则返回数组首字节的地址,分配不成功,则返回0
if(a!=0){
// 使用前四个字节,分配一个int整数11
a[0] = 11;
// 使用后四个字节,分配一个int整数22
a[1] = 22;
std::cout << a[0] << std::endl;//11
std::cout << a[1] << std::endl;//22
}
// 注意这里,nullptr相当于上面的0,这是c++的写法,以后会有用,不过现在就认为这是0即可
if(a!=nullptr){
std::cout<<"分配成功";
}
下面的写法会导致程序使用了不该使用的内存空间
// 让系统分配1个字节的内存
int* a=(int*)malloc(1);
if(a!=0){
// 分配一个int整数11,因为int占用4个字节,所以多用了3个字节
// 这属于非法占用,很可能会导致原本使用那3个字节的其他程序出错
a[0] = 11;
// 自己非法占用,不会报错的
std::cout << a[0] << std::endl;//11
}
二:calloc函数,请求系统分配内存
// 表示需要2块连续的内存,每块内存占用4个字节
// 对比malloc更友好的表示参数意义和可读性
int* a=(int*)calloc(2,4);
// 这里需要注意,打印出0,calloc在分配完内存之后,会把分配给我的内存
// 自动清0,而malloc则不会清0
std::cout << a[0] << std::endl;
std::cout << a[1] << std::endl;
// 此处与malloc相同
a[0] = 11;
a[1] = 22;
std::cout << a[0] << std::endl;
std::cout << a[1] << std::endl;
三:realloc函数,重新分配内存
原来小,分配个大的
// 申请4个字节的内存
int* a=(int*)malloc(4);
*a = 666;
// 突然发现4个字节太小,那么此时,我要用原来的内存,去"以旧换新",换新的内存,并且新的内存当中,会保留原来的值,到新的内存当中
int* b = (int*)realloc(a,8);
// 如果是1表示true,说明是追加了一块新的内存,原来4个字节,那么新分配的8字节是在原来4字节后面追加的
// 如果是0表示false,说明当追加4个字节的时候,地方不够,只能将原来的4字节复制出来,找一片满足8字节的连续空间,然后在这个空间获取8字节
std::cout<<(a==b)<< (char)10;
// 此处依然打印出666,说明把原来的值赋值过来了
std::cout << b[0] << (char)10;
// 此处打印个其他值(这个值是其他程序曾经使用过的,并不会想calloc那样清0)
std::cout << b[1] << (char)10;
原来大,分配个小的
int* a=(int*)malloc(1000);
// 虽然原来是1000,后分配的是4,理论上来说是不需要改变a的地址的,因为直接把a的内存干掉996个字节,即可
// 但是事实上不一定这样做,依然有可能重新划分一个新的区域4个字节,给b
int* b = (int*)realloc(a,4);
// 所以此处打印1和0都有可能
std::cout<<(a==b)<< (char)10;
四:free函数,回收内存
int* a=(int*)malloc(5);
std::cout<< a << (char)10;
// 直接传入指针a,调用free方法,将a的5个字节回收,此方法没有失败这一说
free(a);
// 打印a的值,发现a值没有变化,这是正常的,此时a叫做"悬挂指针"
std::cout<< a << (char)10;
// 为了避免我们再次操作悬挂指针a,所以良好的习惯是将a置成0
a = 0;
五:new关键字,请求系统分配内存
new关键字是c++独有的,c语言中没有这种用法,下面是让系统分配4个字节的内存给我,但是这种写法不常用
// 这种写法表示分配4个字节内存,同malloc,失败返回0
int* a = new int;
// 打印指针
std::cout << a << (char)10;
// 打印指针所指的值,此处写a[1]是错误的,只能写a[0],因为只有一个int
// 而不是多个int
std::cout << a[0] << (char)10;
// 这种写法表示分配12个字节内存
int* a = new int[3];
a[0] = 111;
a[1] = 222;
a[2] = 333;
std::cout << a << (char)10;
// 打印指针所指的值
std::cout << a[0] << (char)10;
std::cout << a[1] << (char)10;
std::cout << a[2] << (char)10;
通过查看汇编语言,发现new关键字的底层依然是malloc实现的
六:delete关键字,回收内存
c++独有的关键字,c语言中不存在delete
特别注意:new关键字出来的内存,尽量要用delete,成对出现的
int* a = new int;
delete a;
// 千万注意,这种方式delete后面多出一个中括号
// 如果不加中括号,程序依然可以运行,但是内存会有问题
// 具体在面向对象相关文章中再阐述
int* b = new int[3];
delete[] b;
日记:
1.多次释放内存在多线程环境中很可能会出问题,所以切记千万不要多次free或者delete同一个指针
2.对于new与delete,这里面的算法会尽量避免内存碎片的问题
3.c语言的东西,尽量不要用c++来后续处理,比如malloc申请内存之后使用delete释放,这涉及到未来的面向对象