动态内存
一般来说,变量的内存都是静态分布的,编译器在编译时会给每一个变量分配固定的内存大小。
例如:
当我们定义数组时一定会说明数组的大小
int a[1000];
可是我们并不是任何时候都知道数组要开多大的。
程序堆栈区
每一个程序在计算机中都会占用一块内存,这块内存用来存放代码和数据,每一个程序除了代码占据的内存外,都有一个称为堆栈的内存块,用来存储程序块的非静态局部变量。当进入一个程序块时,这个程序块中局部变量就会在堆栈的顶部分配一块内存,称为变量入栈;当退出这个程序块时,这个程序的局部变量在栈顶的内存就会被移除(释放),称为变量出栈。
例如:
int main()
{
int a{3},b{4};
{
int c{5};
}
a=2;
}
new 和delete运算符
计算机中除了被分配给运行程序的内存以外,还有很多空闲的内存称为自由内存或者堆存储区(简称堆区),堆区是所用程序共享的自由存储区。任何程序都可以向操作系统申请这块堆区的内存。C++中可以通过new运算符来向操作系统申请一块堆区内存,并通过delete来释放一块内存。
对于一个数据类型T,new T用于申请一个T类型大小元素的内存,而new T[size]用于申请可存储size个T类型元素的一块内存。new T和new T[size]都返回分配内存块的起始地址,返回值类型是T*,即为T的指针类型。如果失败就返回0.
int main()
{
double *p{nullptr};
p=new double ;
if(!p)return 1;
double *q{nullptr};
q=new double[3];
if(!q)return 1;
*p=3.14;
*q=3.15;
*(q+1)=3.16;
*(q+2)=3.17;
*(q+3)=3.18;//超过了三个内存,就错误了。q+3的内存不属于该程序。
}
上述程序分配了2块内存,然后可以通过解引用运算符*访问指针指向的内存。对指针可以加减整数进行偏移,但如果超出了分配内存块的范围,则访问非法。
对一个指针p,因为p[i]就是* (p+i),因此当然可以通过下标访问指针指向的动态
内存。
int main()
{
for(auto i=0;i<3;i++)
q[i]+=2;
for(auto i=0;i<3;i++)
std::cout<<q[i];
}
输出:
5.15 5.16 5.17
对于动态分配的内存,当不再使用时,应该及时的释放掉。以便程序的其他部分或者其他程序能使用这个内存。一个或者多个程序如果不断申请动态内存而没有及时释放,就会使自由内存越来越少,最后导致内存耗尽无法运行。假设指针变量P指向动态内存的起始地址,对于new T分配的一个T元素内存,用delete P释放P指向的T元素占据的内存。对于new T[size]分配的一个多个T元素的内存,用delete []p释放p 指向的多个T元素占用的内存,如果写成了delete p,释放的将是第一个T元素占用的内存,其他元素的内存是不会释放的,这就造成了内存泄漏。
delete p;
delete[] q;
动态内存表示多维数组
假如学生成绩分析程序中每个学生的成绩不是一个值而是多个值,包含平时成绩,实验成绩,期末成绩,总评成绩,一个班级所有学生的成绩可以用一个二维数组表示:
double scores[100][4];
int n=0;
那么是否可以直接用动态内存来表示这种二维数组呢?如写成下面的代码:
int n=0;
int cols;
std::cin>>n>>cols;
double *scores=new double[n][cols];
答案是否定的。new只能分配一维的一组数据元素而不能直接分配二维数组这种动态空间,这是因为内存本身就是一维的。
前面说过,C++内存的多维数组实质也是一维数组,即double scores[ 100 ] [ 4] 其实是一个大小为100的一维数组,每一个元素的类型是double [4],即每一个元素也是一个大小为4的一维数组。因此,可以用new分配类型是double [4]的一组数据元素空间,即:
double (*scores)[4]=new double[n][4];
当然 也可以用auto 简化指针类型的声名:
auto scores{new double[n][4]};
注意:因为4是文字量,所以double [4]就是一个编译时大小确定的数组类型,
当然可以用new申请这种类型的一维数组new double[n][4].对于变量cols,
double[cols]并不是一个大小确定的数据类型,所以不能用new来申请这种类型的
一维数组空间,即new double[n][cols]是非法的。
可以编写如下基于动态内存分配的学生成绩分析程序框架:
#include <iostream>
using namespace std;
int main()
{
int n=0;//学生人数
int cols;//成绩个数
cout<<"学生人数是";
cin>>n;
auto scores{new double [n][4]};
cout<<"输入平时,实验,期末,总评成绩";
for(auto i=0;i!=n;i++)
{
cin>>scores[i][0]>>scores[i][1]>>scores[i][2]>>scores[n][3];
}
}