去哪找想做网站的客户,宜春网络营销是什么,国内免费云主机,杭州恒彩装饰公司怎么样在C中动态内存的分配技术可以保证程序在允许过程中按照实际需要申请适量的内存#xff0c;使用结束后还可以释放#xff0c;这种在程序运行过程中申请和释放的存储单元也称为堆。 申请和释放过程一般称为建立和删除。
在C程序中#xff0c;建立和删除堆对象使用两个运算符中动态内存的分配技术可以保证程序在允许过程中按照实际需要申请适量的内存使用结束后还可以释放这种在程序运行过程中申请和释放的存储单元也称为堆。 申请和释放过程一般称为建立和删除。
在C程序中建立和删除堆对象使用两个运算符new和delete。
1.运算符new的功能是动态分配内存或者称为动态创建堆对象语法形式为
new 数据类型(初始化列表参数);该语句在程序运行过程中申请分配用于存放指定类型数据的内存空间并根据初始化参数列表中给出的值进行初始化。如果内存申请成功new运算符便返回一个指向新分配内存首地址的类型的指针可以通过这个指针对该内存空间进行访如果申请失败会抛出异常。
1对于基本类型的对象
如果建立的对象是一个基本类型的变量初始化过程就是赋值例如
int *p;
pnew int(2);动态分配了用于存放int型数据的内存空间并将初值2存入该空间中然后将首地址赋给指针p。
【注意】对于基本数据类型如果不希望在内存分配后设定初值可以把括号省去例如
int *pnew int;如果保留括号但括号中不写任何数值则表示用0对该对象初始化例如
int *pnew int();2对于类类型的对象 要根据初始化参数列表的参数类型和个数调用该类的构造函数。
在用new建立一个对象时如果该类存在用户自定义的默认构造函数则“new T”和“new T()”这两种写法的效果时相同的都会调用这个默认的构造函数。但若用户没有定义默认的构造函数使用“new T”创建对象时会调用系统生成的隐含的默认构造函数使用“new T()”创建对象时系统除了执行默认构造函数会执行的操作外还会为基本数据类型和指针类型的成员用0赋初值而且这一过程是递归的。也就是说如果该对象的某个成员对象也没有用户自定义的默认构造函数那么对该成员的基本数据类型和指针类型的成员同样会被以0赋初值。
2.运算符delete是用来删除由new建立的对象释放指针所指向的内存空间。
格式为
delete 指针名;如果删除的是对象该对象的析构函数将被调用。对于new建立的对象只能用delete进行一次删除操作如果同一内存空间多次使用delete进行删除将会导致运行错误。
【注意】用new分配的内存必须用delete加以释放否则会导致动态内存分配的内存无法回收使得程序占据的内存越来越大这叫做“内存泄漏”。
【例】动态创建对象
class Point
{
public:Point() :x(0), y(0){cout 调用默认构造函数 endl;}Point(int x, int y) :x(x), y(y){cout 调用构造函数 endl;}~Point(){cout 调用析构函数 endl;}int getX() { return x; }int getY() { return y; }void move(int newX, int newY){x newX;y newY;}
private:int x, y;
};int main()
{cout 创建第一个对象 endl;Point* p1 new Point;//动态创建对象没有给出参数列表因此调用默认的构造函数delete p1;//删除对象自动调用析构函数cout 创建第一个对象 endl;Point* p2 new Point(1,2);//动态创建对象并给出参数列表因此调用有参数的构造函数delete p2;//删除对象自动调用析构函数return 0;
}运行结果 3.使用运算符new也可以创建数组对象这时需要给出数组的结构说明。用new运算符动态创建一维数组的语法形式为
new 类型名[数组长度]其中数组长度指出了数组元素的个数它可以是任何能够得到正整数值得表达式。
用new动态创建一维数组时在方括号后面仍然可以加小括号“”但小括号内不能带参数。是否加“”得区别在于不加“”则对数组每个元素得初始化与执行“new T”时所进行得初始化方式相同加“”则与执行“new T”所进行初始化得方式相同。例如如果这样动态生成一个整型数组
int *pnew int[10]();则可以方便地为动态创建的数组用()初始化。
如果是用new建立得数组用delete删除时在指针名前面要加“[]”格式如下
delete []指针名;【例】动态创建对象数组
class Point
{
public:Point() :x(0), y(0){cout 调用默认构造函数 endl;}Point(int x, int y) :x(x), y(y){cout 调用构造函数 endl;}~Point(){cout 调用析构函数 endl;}int getX() { return x; }int getY() { return y; }void move(int newX, int newY){x newX;y newY;cout ( x , y) endl;}
private:int x, y;
};int main()
{Point* p new Point[2];p[0].move(5, 10);p[1].move(15, 20);cout 删除对象 endl;delete[]p;return 0;
}运行结果 这是利用动态内存分配操作实现了数组得动态创建使得数组元素得个数可以根据运行时得需要而确定。但是建立和删除数组得过程使得程序略显繁琐更好得方法是将数组得建立和删除封装起来形成一个动态数组类。
另外在动态数组类中通过类得成员函数访问数组元素可以每次在访问之间检查一下下标是否越界使得数组下标越界得错误能够及早发现。这种检查可以通过C的assert来进行。assert的含义是“断言”它是标准C的cassert头文件中定义的一个宏用来判断一个条件表达式的值是否为true如果不为true则程序会中止并且报错这样就很容易将错误定位。一个程序一般可以以两种模式编译——调试debug模式和发行release模式assert只在调试模式下生效而在发行模式下不执行任何操作这样兼顾了调试模式的调试需求和发行模式的效率需求。
【注意】由于assert只在调试模式下生效一般用assert只是检查程序本身的逻辑错误而用户的不当输入造成的错误则应当用其他方式加以处理。
【例】动态数组类
class Point
{
public:Point() :x(0), y(0){cout 调用默认构造函数 endl;}Point(int x, int y) :x(x), y(y){cout 调用构造函数 endl;}~Point(){cout 调用析构函数 endl;}int getX() { return x; }int getY() { return y; }void move(int newX, int newY){x newX;y newY;cout ( x , y ) endl;}
private:int x, y;
};
//动态数组类
class Arr
{
public:Arr(int size) :size(size){points new Point[size];}~Arr(){cout 删除对象 endl;delete[]points;}//获得下标为index的数组元素Point element(int index){assert(index 0 index size);//如果数组下标越界程序中止return points[index];}
private:Point* points;//指向动态数组的首地址int size;//数组大小
};int main()
{int count;cout 请输入要创建的对象的个数;cin count;Arr points(count);//创建对象数组points.element(0).move(5,0);//访问数组元素的成员points.element(1).move(15,20);return 0;
}运行结果 在main函数中只是建立一个Arr类的对象对象的初始化参数size指定了数组元素的个数创建和删除对象数组的过程都由Arr类的构造函数和析构函数完成。