1.malloc()/free()的用法
在程序运行过程,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存。
在 C 语言中,用 malloc() 和 free() 从堆中分配和释放内存。
malloc() 和 free() 是函数。
1.1 一般使用格式
void *malloc(int NumBytes)
,其中 NumBytes 表示要分配的字节数。分配成功则返回指向被分配内存的指针,分配失败则返回 NULL。当分配的这段内存不再使用的时候,应该用 free() 函数将内存释放掉,供其他地方使用。
void free(void *FirstByte)
,将之前用 malloc() 分配的内存空间还给程序(操作系统),也就是说释放了这块内存,这样这块内存就被系统回收并在需要的时候由系统分配出去再给其他地方使用。
举例1:
#include<iostream>
using namespace std;
int main()
{
int* p = NULL;
p = (int*)malloc(sizeof(int)); // 在堆中分配4个字节
if (p != NULL)
{
*p = 10;
cout << *p << endl; // 10
free(p);
}
return 0;
}
举例2:
#include<iostream>
using namespace std;
int main()
{
int* p = (int*)malloc(100 * sizeof(int)); // 分配能放得下100个整数的内存空间
if (p != NULL)
{
int* q = p;
*q++ = 1;
*q++ = 5;
cout << *p << endl; // 1
cout << *(p + 1) << endl; // 5
free(p);
}
return 0;
}
1.2 初始化
memset() 函数是将较大的数据结构(比如对象、数组等)内存清零的比较快的方法。
#include <iostream>
using namespace std;
int main()
{
int size = sizeof(int) * 10;
int* p = (int*)malloc(size);
// 从p地址开始的连续4个字节中的每一个字节都设置为1
// 00000001 00000001 ... 00000001 00000001
memset(p, 1, size);
cout << *p << endl; // 16843009
return 0;
}
注意:通过 malloc()/free() 分配和释放的对象不会调用其构造函数和析构函数。
#include <iostream>
using namespace std;
struct Person
{
int m_age;
Person()
{
cout << "Person::Person()" << endl;
}
~Person()
{
cout << "Person::~Person()" << endl;
}
void run()
{
cout << "Person::run() - " << m_age << endl;
}
};
int main()
{
Person* p = (Person*)malloc(sizeof(Person));
p->m_age = 10;
p->run();
free(p);
return 0;
}
2.new/delete的用法
在 C++ 中使用 new 和 delete 在堆中分配和释放内存,不再使用 malloc() 和 free() 来分配和释放内存。
new/delete 是关键字或运算符,不是函数。
malloc()/free() 和 new/delete 这两对都用于动态地在堆中分配和释放内存,但是 new/delete 比 malloc()/free() 干了更多的事情。new/delete 具备对堆上所分配内存进行初始化和释放的能力,而这些能力是 malloc()/free() 所不具备的。
2.1 一般使用格式
-
指针变量名 = new 类型标识符;
-
指针变量名 = new 类型标识符(初始值);
-
指针变量名 = new 类型标识符[内存单元个数];
2.2 初始化
举例1:
#include<iostream>
using namespace std;
int main()
{
int* p = new int(18);
if (p != NULL)
{
cout << *p << endl; // 18
delete p; // 释放单个int的空间
}
return 0;
}
举例2:
#include<iostream>
using namespace std;
int main()
{
int* pa = new int[100]; // 开辟一个大小为100的整形数组空间
if (pa != NULL)
{
int* q = pa;
*q++ = 12;
*q++ = 18;
cout << *pa << endl; // 12
cout << *(pa + 1) << endl; // 18
// 释放pa数组空间。new的时候用了[],那么delete就必须用[],delete[]不用写数组大小
delete[] pa;
}
return 0;
}
注意:delete 回收堆空间内存,表示这块堆空间内存可以重新被别人使用,但这块堆空间并不会被清零,指针也不会被置成NULL。
#include <iostream>
using namespace std;
int main()
{
int* p = new int;
*p = 10;
delete p; // 堆空间的这4个字节不会被清零,p也不会被置成NULL
p = nullptr; // 这是个好习惯,表明该指针不指向任何对象了
return 0;
}
注意:不是new出来的内存,不能用delete来释放。
#include <iostream>
using namespace std;
int main()
{
int i = 20;
int* p = &i;
delete p; // 异常
return 0;
}
注意:在下面代码中,多个指针指向同一块内存,导致同一块内存被多次释放。
#include <iostream>
using namespace std;
int main()
{
int* p1 = new int();
int* p2 = p1;
delete p2; // 没问题
delete p1; // 异常,因为p1和p2指向同一块内存
return 0;
}
注意:通过 new/delete 分配和释放的对象会调用其构造函数和析构函数。
#include <iostream>
using namespace std;
struct Person
{
int m_age;
Person()
{
cout << "Person::Person()" << endl;
}
~Person()
{
cout << "Person::~Person()" << endl;
}
void run()
{
cout << "Person::run() - " << m_age << endl;
}
};
int main()
{
Person* p = new Person; // 构造函数被调用
p->m_age = 10;
p->run();
delete p; // 析构函数被调用
return 0;
}