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.csdn.net/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,可以给我们写程序减少麻烦,尤其是写大型程序的时候。