C++二维动态数组的申请与_释放一维数组是指针,可将二维数组看作是指针的指针:每一行是一个一维数组,而列是指向行的指针。
在动态创建时,先分配指向行的指针空间,再循环维每一行申请空间。
#include <iostream>using namespace std;int main(){//[3]4] //三行四列的二维数组int x,y;int i,n,k;x=3;y=4;int **p;p = new int*[x]; //行 //申请行的空间//每行的列申请空间for(i=0; i<x;i++){p[i] = new int [y];}//赋值,k=0;for(i=0;i<x;i++){for(n=0;n<y;n++){p[i][n] = k;k++;}}//显示刚才的赋值for(i=0;i<x;i++){for(n=0;n<y;n++){cout << p[i][n] << "\t"; }cout << endl;}//删除刚才申请的内存for(i=0;i<x;i++){delete [] p[i];}delete [] p;return 0;今天归纳总结了一下,希望以后的朋友可以少走些弯路:)一:关于指针和堆的内存分配先来介绍一下指针:指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量。
既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的PC机上,都是4个字节大小,里边只是存储了一个变量的地址而已。
不管什么类型的指针,char * ,int * ,int (*) ,string * ,float * ,都是说明了本指针所指向的地址空间是什么类型而已,了解了这个基本上所有的问题都好象都变的合理了。
在C++中,申请和释放堆中分配的存贮空间,分别使用new和delete的两个运算符来完成:指针类型指针变量名=new 指针类型 (初始化);delete 指针名;例如:1、 int *p=new int(0);它与下列代码序列大体等价:2、int tmp=0, *p=&tmp;区别:p所指向的变量是由库操作符new()分配的,位于内存的堆区中,并且该对象未命名。
下面是关于new 操作的说明:部分引自<<C++面向对象开发>>1、new运算符返回的是一个指向所分配类型变量(对象)的指针。
对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。
2、一般定义变量和对象时要用标识符命名,称命名对象,而动态的称无名对象(请注意与栈区中的临时对象的区别,两者完全不同:生命期不同,操作方法不同,临时变量对程序员是透明的)。
3、堆区是不会在分配时做自动初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。
new表达式的操作序列如下:从堆区分配对象,然后用括号中的值初始化该对象。
下面是从堆中申请数组1、申请数组空间:指针变量名=new 类型名[下标表达式];注意:“下标表达式”不是常量表达式,即它的值不必在编译时确定,可以在运行时确定。
这就是堆的一个非常显著的特点,有的时候程序员本身都不知道要申请能够多少内存的时候,堆就变的格外有用。
2、释放数组空间:delete [ ]指向该数组的指针变量名;注意:方括号非常重要的,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的,会产生回收不彻底的问题(只回收了第一个元素所占空间),我们通常叫它“内存泄露”,加了方括号后就转化为指向数组的指针,回收整个数组。
delete [ ]的方括号中不需要填数组元素数,系统自知。
即使写了,编译器也忽略。
<<Think in c++>>上说过以前的delete []方括号中是必须添加个数的,后来由于很容易出错,所以后来的版本就改进了这个缺陷。
下面是个例子,VC上编译通过#include<iostream>using namespace std;//#include <iostream.h> //for VC#include <string.h>void main(){int n;char *p;cout<<"请输入动态数组的元素个数"<<endl;cin>>n; //n在运行时确定,可输入17p=new char[n]; //申请17个字符(可装8个汉字和一个结束符)的内存空间strcpy(pc,“堆内存的动态分配”);//cout<<p<<endl;delete []p;//释放pc所指向的n个字符的内存空间return ; }通过指针使堆空间,编程中的几个可能问题1.动态分配失败。
返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
data = new double [m]; //申请空间if ((data ) == 0)…… //或者==NULL2.指针删除与堆空间释放。
删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针,不能再通过p使用该空间,在重新给p 赋值前,也不能再直接使用p。
3.内存泄漏(memory leak)和重复释放。
new与delete 是配对使用的,delete只能释放堆空间。
如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,而这个时候又去释放的话,会导致一个很难查出来的运行时错误。
所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
4.动态分配的变量或对象的生命期。
无名变量的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。
我们也称堆空间为自由空间(free store)就是这个原因。
但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错,所以永远不要在函数体内申请空间,让调用者释放,这是一个很差的做法。
你再怎么小心翼翼也可能会带来错误。
类在堆中申请内存:通过new建立的对象要调用构造函数,通过deletee删除对象要调用析构函数。
CGoods *pc;pc=new CGoods; //分配堆空间,并构造一个无名对象//的CGoods对象;…….delete pc; //先析构,然后将内存空间返回给堆;堆对象的生命期并不依赖于建立它的作用域,所以除非程序结束,堆对象(无名对象)的生命期不会到期,并且需要显式地用delete语句析构堆对象,上面的堆对象在执行delete 语句时,C++自动调用其析构函数。
正因为构造函数可以有参数,所以new后面类(class)类型也可以有参数。
这些参数即构造函数的参数。
但对创建数组,则无参数,并只调用缺省的构造函数。
见下例类说明:class CGoods{char Name[21];int Amount;float Price;float Total_value;public:CGoods(){}; //缺省构造函数。
因已有其他构造函数,系统不会再自动生成缺省构造,必须显式声明。
CGoods(char* name,int amount ,float price){strcpy(Name,name);Amount=amount;Price=price;Total_value=price*amount; }……};//类声明结束下面是调用机制:void main(){int n;CGoods *pc,*pc1,*pc2;pc=new CGoods(“hello”,10,118000);//调用三参数构造函数 pc1=new CGoods(); //调用缺省构造函数cout<<”输入商品类数组元素数”<<endl;cin>>n;pc2=new CGoods[n];//动态建立数组,不能初始化,调用n次缺省构造函数……delete pc;delete pc1;delete []pc2; }申请堆空间之后构造函数运行;释放堆空间之前析构函数运行;再次强调:由堆区创建对象数组,只能调用缺省的构造函数,不能调用其他任何构造函数。
如果没有缺省的构造函数,则不能创建对象数组。
---------------------下面我们再来看一下指针数组和数组指针―――――――――――――如果你想了解指针最好理解以下的公式:(1)int*ptr;//指针所指向的类型是int(2)char*ptr;//指针所指向的的类型是char(3)int**ptr;//指针所指向的的类型是int* (也就是一个int * 型指针)(4)int(*ptr)[3];//指针所指向的的类型是int()[3] //二维指针的声明(1)指针数组:一个数组里存放的都是同一个类型的指针,通常我们把他叫做指针数组。
比如 int * a[10];它里边放了10个int * 型变量,由于它是一个数组,已经在栈区分配了10个(int * )的空间,也就是32位机上是40个byte,每个空间都可以存放一个int型变量的地址,这个时候你可以为这个数组的每一个元素初始化,在,或者单独做个循环去初始化它。
例子:int * a[2]={ new int(3),new int(4) }; //在栈区里声明一个int * 数组,它的每一个元素都在堆区里申请了一个无名变量,并初始化他们为3和4,注意此种声明方式具有缺陷,VC下会报错例如:int * a[2]={new int[3],new int[3]};delete a[0];delet a[10];但是我不建议达内的学生这么写,可能会造成歧义,不是好的风格,并且在VC 中会报错,应该写成如下:int * a[2];a[0]= new int[3];a[1]=new int[3];delete a[0];delet a[10];这样申请内存的风格感觉比较符合大家的习惯;由于是数组,所以就不可以delete a;编译会出警告.delete a[1];注意这里是一个数组,不能delete [] ;(2)数组指针:一个指向一维或者多维数组的指针;int * b=new int[10]; 指向一维数组的指针b ;注意,这个时候释放空间一定要delete [] ,否则会造成内存泄露, b 就成为了空悬指针.int (*b2)[10]=new int[10][10]; 注意,这里的b2指向了一个二维int型数组的首地址.注意:在这里,b2等效于二维数组名,但没有指出其边界,即最高维的元素数量,但是它的最低维数的元素数量必须要指定!就像指向字符的指针,即等效一个字符串,不要把指向字符的指针说成指向字符串的指针。