malloc、calloc、realloc、free
- malloc原型:void* malloc(unsigned int size)
- calloc原型:void* calloc(size_t numElements, size_t sizeOfElement)
两个函数返回值均为系统分配的地址,失败返回NULL
malloc最大分配空间:
64位的,操作系统保留一部分内存(大概2G),还有差不多6G可以申请。32位可分配大致2G不到的内存(32位最大可识别内存4G,除去系统保留就是不到2G)。
另外,程序是32位或者是64位并不是由你的操作系统决定,而是编译器决定,准确的说是决定于编译器和编译选项,64位系统照样可以跑32位的程序。
malloc和calloc一个很重要的区别是:malloc分配后的空间里是随机值,而calloc会初始化为0
-
realloc原型:void* realloc(void *ptr, size_t new_Size)
realloc用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作)。ptr为指向原来空间基址的指针, new_size为接下来需要扩充容量的大小。
分以下三种情况:
①如果size较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容,并返回原动态空间基地址。
②如果size较大,原来申请的空间后面没有足够大的空间扩容,系统将重新申请一块(20+size)*sizeof(int)的内存,并把原来空间的内容拷贝过去,原来空间free。
③如果size非常大,系统内存申请失败,返回NULL,原来的内存不会释放。 -
free的调用形式为free(void*ptr):释放ptr所指向的一块内存空间。 malloc和calloc申请的空间都要free,防止泄露。记得释放后把ptr指向NULL,避免野指针。
char* p;
p=(char*)malloc(20*sizeof(char)); //malloc的参数size是需要内存空间的长度:
char* p;
p=(char*)calloc(20,sizeof(char)); //calloc第一个参数是元素个数,第二个是地址单位元素长度:
#include<iostream>
#include<cstdlib>
using namespace std;
int main() {
int *c_p, *m_p;
m_p = (int*)malloc(10 * sizeof(int));
c_p = (int*)calloc(10, sizeof(int));
cout << "malloc: ";
for (int i = 0; i < 10; i++)
cout << m_p[i] << " ";
cout << endl << "calloc: ";
for (int i = 0; i < 10; i++)
cout << c_p[i] << " ";
cout << endl;
getchar();
return 0;
}
#include<iostream>
#include<cstdlib>
using namespace std;
int main() {
int *p, *r_p;
p = (int*)malloc(10 * sizeof(int));
r_p = (int*)realloc(p, 100);
cout << "p: " << p << endl << "r_p: " << r_p << endl;
getchar();
return 0;
}
new和delete
只要告诉new为哪种数据类型分配内存,new会找到一个正确的内存块并返回指针:
int *p = new int;
使用delete会释放指针指向的内存,但不会删除指针本身。
delete p;
new和delete要成对使用,防止内存泄露。
下面两种情况注意:
// delete只能用于new分配的内存,因此下面这么做是不可以的
int test=5;
int *p=&test;
delete p;
// 但这么做是可以的
int *p=new int;
int *ps=p;
delete ps;
// 使用new时,可以在运行阶段根据需求建立数组。被称为动态联编,数组也叫动态数组。
int *p = new int[10];
delete [] p;
malloc和new的区别:
①malloc/free是库函数,而new和delete是C++的操作符。
②一个很大的区别是,malloc只负责分配内存,而new在分配后会调用默认构造函数,delete会调用默认析构函数。或者new还可以调用自定义的构造函数。因此malloc比较适合内部数据类型,对非内部数据动态对象,不太好初始化和销毁。
③上面提到的能否在运行时动态建立数组。
不能连续delete或者free一个指针,但delete和free对空指针操作不会出错。
C++允许重载new/delete操作符,特别的,布局new的就不需要为对象分配内存,而是指定了一个地址作为内存起始区域,new在这段内存上为对象调用构造函数完成初始化工作,并返回此地址。而malloc不允许重载。
memset和memcpy
原型: void *memset(void *s, int ch, size_t n) 其中:
s:为指针或是数组
ch:是赋给buffer的值
n:长度,要用sizeof(type)*num
功能:将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向s的指针,它是对较大的结构体或数组进行清零操作的一种最快方法。
头文件是:<memory.h>或<string.h>
注意:memset是一个一个字节初始化的,char的话本身为一个字节。但像int之类的,如果不是初始化为0,可能不是你想要的结果。
原型:void memcpy(voiddest, const void *src, size_t n);
功能:由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。返回一个指向dest的指针。
#include<string.h>
注意:
①source和destin所指内存区域不能重叠。
②与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。
③如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。
malloc_trim()
使用 malloc_trim()可把之前分配的内存还给系统。