C++之动态内存
-
了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:
- 栈:在函数内部声明的所有变量都将占用栈内存。
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。
-
在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。
-
如果您不再需要动态分配的内存空间,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。
-
在介绍动态内存之前,先小讲一下数组和指针。
1. 指针
- 先引说一下数组吧,数组是一个可以存储固定大小的相同类型元素的集合,定义及初始化如下:
//定义大小为10的double类型数组,默认元素为0
double balance[10];
//***********初始化***************************
double balance[5]={
1.,20.,3.,15.,6};
//或者省略大小,自动计算
double balance[]={
1.,20.,3.,15.,6};
//数组值读取:
// 输出数组中每个元素的值
for ( int j = 0; j < 10; j++ )
{
cout << balance[ j ] << endl;
}
//多维数组
int a[3][4] = {
{
0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{
4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{
8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
//或者
int a[3][4] = {
0,1,2,3,4,5,6,7,8,9,10,11};
- 读取数组地址:
int var1;
char var2[10];
cout << "var1 变量的地址: ";
cout << &var1 << endl;
cout << "var2 变量的地址: ";
cout << &var2 << endl;
printf:
var1 变量的地址: 0xbfebd5c0
var2 变量的地址: 0xbfebd5b6
- 指针与数组功能差不多,也是作为储存数据的集合,不同的是,指针是一个变量,而且它的值为另一个变量的地址,即内存的直接地址,定义如下:
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
使用指针指向变量:
#include <iostream>
using namespace std;
int main ()
{
int var = 20; // 实际变量的声明
int *ip; // 指针变量的声明
ip = &var; // 在指针变量中存储 var 的地址
cout << "Value of var variable: ";
cout << var << endl;
// 输出在指针变量中存储的地址
cout << "Address stored in ip variable: ";
cout << ip << endl;
// 访问指针中地址的值
cout << "Value of *ip variable: ";
cout << *ip << endl;
return 0;
}
printf:
Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20
使用指针指向数组:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {
10, 100, 200};
int *ptr;
// 指针中的数组地址
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "var[" << i << "]的内存地址为 ";
cout << ptr << endl;
cout << "var[" << i << "] 的值为 ";
cout << *ptr << endl;
// 移动到下一个位置
ptr++;
}
return 0;
}
printf:
var[0]的内存地址为 0x7fff59707adc
var[0] 的值为 10
var[1]的内存地址为 0x7fff59707ae0
var[1] 的值为 100
var[2]的内存地址为 0x7fff59707ae4
var[2] 的值为 200
2. 动态内存
2.1 new 和 delete 运算符
使用new分配内存:
double* pvalue = NULL; // 初始化为 null 的指针
pvalue = new double; // 为变量请求内存
//检查
if( !(pvalue = new double ))
{
cout << "Error: out of memory." <<endl;
exit(1);
}
malloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。
new 与malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。
在任何时候,当您觉得某个已经动态分配内存的变量不再需要使用时,您可以使用 delete 操作符释放它所占用的内存,如下所示:
delete pvalue; // 释放 pvalue 所指向的内存
2.2 数组的动态内存分配
- 为字符数组分配内存
char* pvalue = NULL; // 初始化为 null 的指针
pvalue = new char[20]; // 为变量请求内存
- 删除内存
delete [] pvalue; // 删除 pvalue 所指向的数组
- 一维数组
// 动态分配,数组长度为 m
int *array=new int [m];
//释放内存
delete [] array;
- 二维数组
int **array;
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{
array[i] = new int [n];
}
//释放
for( int i=0; i<m; i++ )
{
delete [] array[i];
}
delete [] array;
- 三维数组
#include <iostream>
using namespace std;
int main()
{
int i,j,k; // p[2][3][4]
int ***p;
p = new int **[2];
for(i=0; i<2; i++)
{
p[i]=new int *[3];
for(j=0; j<3; j++)
p[i][j]=new int[4];
}
//输出 p[i][j][k] 三维数据
for(i=0; i<2; i++)
{
for(j=0; j<3; j++)
{
for(k=0;k<4;k++)
{
p[i][j][k]=i+j+k;
cout<<p[i][j][k]<<" ";
}
cout<<endl;
}
cout<<endl;
}
// 释放内存
for(i=0; i<2; i++)
{
for(j=0; j<3; j++)
{
delete [] p[i][j];
}
}
for(i=0; i<2; i++)
{
delete [] p[i];
}
delete [] p;
return 0;
}
2.3 对象的动态内存分配
- 定义一个结构体对象测试动态内存
#include <iostream>
using namespace std;
class Box
{
public:
Box() {
cout << "调用构造函数!" <<endl;
}
~Box() {
cout << "调用析构函数!" <<endl;
}
};
int main( )
{
Box* myBoxArray = new Box[4];
delete [] myBoxArray; // 删除数组
return 0;
}
如果要为一个包含四个 Box 对象的数组分配内存,构造函数将被调用 4 次,同样地,当删除这些对象时,析构函数也将被调用相同的次数(4次)。
当上面的代码被编译和执行时,它会产生下列结果:
调用构造函数!
调用构造函数!
调用构造函数!
调用构造函数!
调用析构函数!
调用析构函数!
调用析构函数!
调用析构函数!