动态分配内存
C++内存分配有两种方式:静态分配和动态分配
静态分配 指在编译时为程序中的数据对象分配相应的存储空间,C语言风格中常见的变量,数组,指针定义等均是静态分配方式。
由于是在编译时为程序中的数据分配相应的存储空间,因此就要求在编译时空间大小必须是明确的,所以数组的长度必须是常量。而编译一旦完成,运行期间这个数组的长度就固定不变。
动态分配 是程序运行期间根据实际需要动态地申请或者释放内存的方式,它不像数组等静态内存分配方式那样需要预先分配存储空间,而是根据程序的需要适时分配,且分配的大小就是程序要求的大小。
因此,动态分配方式有如下特点:
- 不需要预先分配存储空间
- 分配的空间可以根据程序的需要扩大或缩小
new与delete运算
int *p1,*p2;
char *str1,*str2;
p1 = new int; //分配一个整型空间,若成功,则p1指向该空间,否则p1为NULL
p2 = new int(10); //分配一个整型空间,且给这个整型赋初值10,即*p2为10
str1 = new char[100]; //分配一个字符数组(字符串)空间,即str1为字符串指针
str2 = new char[10][100]; //分配一个二维字符数组(字符串数组)空间,即str2为字符串数组指针
delete p1; //释放指向p1指向的整型空间
delete []str1; //释放str1指向的字符串空间
总结:
-
new运算结果是指向分配得到的内存空间的指针,如果没有足够的内存空间可以分配,其运算结果是一个0值指针
-
销毁对象后,指针p1变成没有定义,然而它仍然存放先前所指向的对象(已销毁)的地址,因此,指针p1不再有效,称这样的指针为迷途指针。通常在delete运算之后将指针重设为0值指针,避免迷途指针
-
用new创建的动态对象使用结束后,必须用delete销毁它
-
delete只能删除由new创建的动态对象,否则将导致程序错误
动态内存的应用
-
静态内存管理由编译器进行,程序员只做对象定义(相当于分配),而动态内存管理按程序员人为的指令进行
-
动态内存分配和释放必须对应,即有分配就必须有释放,不释放内存会产生“内存泄漏”,后果是随着程序运行多次,可以使用的内存空间越来越少;另一方面,再次释放已经释放的内存空间,会导致程序出现崩溃性错误
-
静态分配内存的生命期由编译器自动确定,要么是程序运行执行期,要么是函数执行期。动态分配内存的生命期由程序员决定,即从分配时开始,至释放时结束。特别地,动态分配内存的生命期允许跨过多个函数
-
静态分配内存的对象有初始化,动态分配内存一般需要人为的指令赋初值
-
避免释放内存后出现“迷途指针”,应及时设置为空指针
动态内存举例:
#include<iostream>
using namespace std;
int *f1(int n) { //分配n个整型内存,返回首地址
int *p;
p = new int[n]; //分配
for(int i=0;i<n;i++)
p[i] = i; //赋初始值
return p; //动态分配的指针返回是有意义的
}
void f2(int *p,int n) { //输出动态内存中的n个数据
while(n--)
cout<<*p++<<" ";
}
void f3(int *p) {
delete []p; //释放内存
}
int main()
{
int *pi;
int n;
cin>>n;
pi = f1(n); //分配
f2(pi,n); //输出
f3(pi); //释放
return 0;
}
动态分配数组和字符串
使用动态内存,可以轻而易举地解决这样的问题:在程序运行时产生任意大小的"数组"
动态分配一维或多维数组的方法是由指针管理数组,二维以上数组按一维数组方式来处理,具体步骤:
- 定义指针p
- 分配数组空间,用来存储数组元素,空间大小按元素个数计算
- 按一维数组方式使用这个数组(例如输入,输出等)
注:若是一维数组,则元素为p[i];若是二维数组,则元素为p[i*m+j],其中m为列元素个数,以此类推 - 释放数组空间
例:计算N*N二维数组的元素平均值
#include<iostream>
using namespace std;
double AVE(double *A,int N) { //计算N*N二维数组元素的平均值
int sum=0;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
sum = sum + *(A+i*N+j);
return sum/(N*N);
}
int main()
{
int n;
cin>>n;
double *A = new double[n*n]; //分配数组A[n][n]
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>*(A+i*n+j); //输入数据到A[i][j]
cout<<"det A="<<AVE(A,n)<<endl;
delete []A; //释放数组
return 0;
}
动态分配字符串
实际编程中,字符串类型表示文字信息数据,其特点是字符长度不固定。通过动态分配字符串,根据程序的需要确定字符串的实际长度。
动态分配字符串的方法是由字符指针管理字符串,具体步骤为:
- 定义字符指针
- 分配字符串空间,用来存储字符串
- 使用这个字符串(例如输入输出等)
- 释放字符串空间
char *p = new char[1005]; //分配字符串空间
cin >> p; //输入字符串
cout << p; //输出字符串
delete []p; //释放字符串空间