数组的存储空间必须在程序运行前申请,即数组的大小在编译前必须是已知的常量表达式。空间申请得太大会造成浪费,空间申请得太小会造成数据溢出而使得程序异常。所以,为了解决这个问题,需要能够在程序运行时根据实际情况申请内存空间。
在C++中,允许在程序运行时根据自己的需要申请一定的内存空间,将其称为堆内存空间(Heap)。
获得堆内存空间:
用操作符new来动态地申请堆内存空间,其语法格式为:new 数据类型[表达式];其中,表达式可以是一个正整型常量,也可以是一个有确定值的正整型变量,其作用类似声明数组时的元素个数,所以两旁的中括号不可省略。如果只申请一个变量的空间,则可以写作:new 数据类型;
使用new操作符后,会返回一个对应数据类型的指针,该指针指向了空间的首元素。所以,在使用new操作符之前需要声明一个对应类型的指针,来接受它的返回值。
如下面程序段:
int* iptr=NULL; //声明一个指针
int size; //声明整型变量,用于输入申请空间的大小
cin >>size; //输入一个正整数
iptr=new int[size]; //申请堆内存空间,接受new的返回值
// iptr=new int; //只申请一个变量的空间
因为数组名和指向数组首元素的指针是等价的。所以对于iptr,可以认为是一个大小为size的整型数组。于是,就实现了在程序运行时,根据实际情况来申请内存空间。释放内存:
当一个程序运行完毕之后,它所使用的数据就不再需要。由于内存是有限的,所以它原来占据的内存空间也应该释放给别的程序使用。对于普通变量和数组,在程序结束运行以后,系统会自动将它们的空间回收。然而人为申请的堆内存空间,大多数系统都不会将它们自动回收。如果不人为地对它们进行回收,只“借”不“还”,那么系统资源就会枯竭,计算机的运行速度就会越来越慢,直至整个系统崩溃。这种只申请空间不释放空间的情况称为内存泄露(Memory Leak)。
确认申请的堆内存空间不再使用后,可以使用delete操作符来释放堆内存空间,其语法格式为:
delete [] 指向堆内存首元素的指针;
如果申请的是一个堆内存变量,则delete后的[]可以省略;如果申请的是一个堆内存数组,则该[]不能省略,否则还是会出现内存泄露。另外,由于delete后的指针就是通过new获得的指针,因此如果该指针的数据被修改或丢失,也可能造成内存泄露。
//下面来看一段程序,实践堆内存的申请和回收:
#include<iostream>
using namespace std;
int main()
{
int size;
double sum=0;
int *heapArray=NULL;
cout<<"请输入元素个数:";
cin>>size;
heapArray=new int[size];
cout <<"请输入各元素:" <<endl;
for (int i=0;i<size;++i)
{
cin>>heapArray[i];
sum+=heapArray[i];
}
cout <<"这些数的平均值为" <<sum/size <<endl;
delete [] heapArray;
return 0;
}
//运行结果:
//请输入元素个数:5
//请输入各元素:
//1 3 4 6 8
//这些数的平均值为4.4
可见,申请的堆内存数组在使用上和一般的数组并无差异。需要记住的是,申请了资源用完后就一定要释放。
那么,能不能申请一个二维的堆内存数组呢?事实上,new 数据类型[表达式][表达式]的写法是不允许的。所以,如果有需要,最简单的方法就是用一个一维数组来代替一个二维数组。