c++在堆区中创建数组的一些注意事项

Q1:我们为什么好端端的不在栈中创建数组,偏要跑到堆区中哪?

R1:栈中的空间是有限的,在面对一些长度很大的数组的时候,会有力不从心的感觉,所以我们选择了在堆区中。

 

1.写法

 

1.1堆区创建一维数组的写法

类型名 * 指针名=new 类型名[数组长度]

eg:  int *p=new int[10]

这就表示我们在堆区中创建了个int类型的一维数组,长度是10,并且用int类型的指针指向他来便于我们后期维护。

注意:前后类型最好一致,或者可以转换。如果前面是string,后面是int这显然不行。

 1.2堆区创建二维数组的写法

创建方法一:总感觉这个方法是在为了创建而创建,使用起来并不方便,也可能是我还没找到正确的打开方式。

类型名 (*指针名)[列数]=new 类型名[行数][列数]

eg:int (*p)[5]=new int[10][5];   这就表示我们在堆区创建了一个十行五列的int类型数组,但是这里仅仅是定义了,还没有赋值,不能直接用。

注意:1.括号很重要,千万别忘了,很容易错写成int *p[10]=new int[10][5];  这两个意思是完全不同的,下边这个连编译都通不过,毫无逻辑可言。

           2.这两个位置的数字必须相同。

 创建方法二:new/delete

int **Array = new int *[ArrayRow];
for (int i = 0; i < ArrayRow; i++)
{
    Array[i] = new int[ArrayCol]();                            // 初始化 0
}

for(i = 0; i < ArrayRow; i++)                                  // 释放内存
{  
    delete[] Array[i];  
}   
delete[] Array;  
 

创建方法三:

malloc/free:

int **Array = (int**)malloc(ArrayRow * sizeof(int *));        // 先行
for (int i = 0; i < ArrayRow; i++)
{
    Array[i] = (int*)malloc(ArrayCol * sizeof(int));        // 后列
    memset(Array[i], 0, ArrayCol * sizeof(int));            // 初始化 0
}

for (int i = 0; i < 3; i++)                                    // 释放内存
{
    free(Array[i]);
}
free(Array);                                    
 

 

 

2.用法

2.1一维的用法

1.for循环赋值
    //把指针设置为const类型,防止p后面被改变,这点很重要,之后在下面会特别介绍,防止指针中途改变从而导致最后无法被析构
	int *const p=new int[10];


    //为一维数组赋值
	for(int i=0;i<10;i++){
		p[i]=i+1;
	}

   //调用一维数组
	for(int i=0;i<10;i++){
		cout<<p[i]<<endl;
	}

   //用完记得删除
	delete[]p;

2.初始阶段初始化

int* Array = new int[ArraySize];					// 仅在自由存储区中申请内存,不初始化
int* Array = new int[ArraySize]();					// 初始化数组全为 0
int* Array = new int[5]{ 1,2,3,4,5 };				// 初始化数组为 1,2,3,4,5
int* Array = new int[5]{ 1 };						// 初始化数组为 1,0,0,0,0
delete[] Array;										// 释放内存

2.2二维的用法

C++又规定了数组名代表数组首元素地址,因此array[0]代表一维数组array[0]中第0行第0列元素的地址,即&array[0][0],array[1]的值是&array[1][0],array[2]的值是&array[2][0]。

#include<iostream>//预处理
using namespace std;//命名空间 
int main()//主函数 
{
	//堆区申请内存,创建一个二维数组并为其初始化值。 
	int(*p)[4]=new int[3][4] { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
	int i, j;//定义代表行数和列数的整型变量 
	cout << "输入行号列号:";//提示语句 
	cin >> i >> j;//键盘输入行数和列数 
	cout << *(*(p + i) + j) << endl;//偏移量计算访问法 
	cout << p[i][j] << endl;//不妨称之为几何访问法, 
	return 0; 
}

 

 

 

3.为什么要把指针设置为const?

原回答网址:

https://blog.youkuaiyun.com/charlessimonyi/article/details/8277616

常见的通过偏移量来访问的两种方式:

*(pa+2)=15;

pa[2]=15;

下面问题来了:

pa++;

*(pa)=10

这样看上去,对pa指针自加后pa指针指向了数组的第二个元素,然后对第二个元素赋值为10,编译没有错,也能成功赋值。

但要注意!我们在堆中创建的东西用完后需要用delete来释放,对于堆中数组,这样来释放:

delete [] pa;

由于我们刚才对pa进行了自加,这里用delete释放的时候就会出错,因为pa自加后就没有指向数组第一个元素的地址了,系统无法正确的释放我们在堆中创建的数组所占的内存空间。就会出现卡死等异常情况。所以千万不要改变pa指针。

为了防止对pa指针的误操作,最好的办法是将它申明为常指针,我们在一开始堆中创建数组的时候就这样:

int *const pa = new int[10];

将pa申明为常指针后,我们就无法改变pa指针了,比如无法pa++;无法pa+=2;但是我们仍然可以正常的访问和修改pa指向的数组元素的值,pa[1]=10;

delete [] pa;

pa=NULL;

最后,在堆中创建的东西,用完后都要delete以免发生内存泄露。delete释放后指针要及时指向NULL,防止野指针出现。

善用const,可以给我们写程序减少麻烦,尤其是写大型程序的时候。

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值