数组
int main(){
int example[5];
for(int i = 0; i<5; i++)
{
example[i] = i;
}
}
对于数组,for循环的判断部分一般写小于数组长度。如果写i<=4,性能会有损失,因为需要做小于和等于的判断,另外这个数直接写数组的长度更容易理解。
在release模式下,数组越界不会报错,这导致可能修改其他地方的变量值(访问了不属于该数组的地址)。
1 数组的内存
// example数组首地址
cout<< example<< endl;
// 数组所占内存大小,输出20
cout<< sizeof(example)<< endl;
// 数组索引2对应的元素值,输出2
cout<< example[2]<< endl;
对于上述example数组,这里example相当于数组指针,指向example数组首地址。由于example数组是int,长度为5,因此数组总长度为4*5=20。example数组的内存如下:
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
example[0] |example[1] |example[2] |example[3] |example[4]|
2 数组的访问
用ptr指向example,对数组进行访问,那么以下几个表达式等价:
int* ptr = example;
// 以下表达式等价:
example[2] = 2;
*(ptr + 2) = 2;
*(int*)((char*)ptr + 8) = 2;
- “*(ptr + 2) = 2” :因为ptr是int类型指针,因此偏移的最小单元是4个byte,ptr+2相当于example首地址+2*4,即example[2]的连续4个byte的空间。
- “(int*)((char*)ptr + 8)”:ptr被强制转换为char类型指针,因此偏移最小单元是1个byte,因此此处+8才能访问到example[2]的第0个byte。但char类型指针只能访问数据长度为1byte的空间,因此还要在将其强制转化为int类型指针,才能访问属于example[2]的完整4byte空间。
3 栈和堆上的数组
栈和堆上的数据的区别是,保存在栈上的数据在作用域结束时会自动释放,但堆上的数据则需要手动释放。因此,如果一个函数需要返回在这个函数中创建的数组时,该新生成的数组只能保存在堆上(用new生成)。
内存间接寻址
class Entity
{
public:
// int example[5];
int* example = new int[5];
Entity()
{
for (int i = 0; i < 5; i++)
example[i] = 2;
}
};
int main(){
Entity e;
}
上述代码中,Entity类中有一个example数组。
- 如果example数组保存在栈上(注释部分),实例化以后,e的地址就是数组的起始地址。
- 如果example数组保存在堆上(new),e的地址保存的是一个地址(这里称该地址为address),而address保存着example数组的地址。这种情况下要访问example数组,会比保存在栈上多一次间接寻址(&e->&address)。因此在这种情况下更推荐在栈上创建数组,内存间接寻址会影响性能,所以不推荐。
4 数组长度
原始数组无法直接得到数组长度。(sizeof是占用内存大小,不是数组元素个数)
对于创建在栈上的数组,可以用如下方式得到数组长度。
int example[5];
int length = sizeof(example)/sizeof(int);
但这个方法并不推荐。因为一旦这个变量因为一些原因变成了指针(比如放到函数中),sizeof(example)将变成指针所占内存大小,这里length就会变为1。另外,堆上数组的数组名就是指针,根本用不了这个方法。
可以用如下方式维护数组长度:
class Entity
{
public:
// 这样维护数组长度
static const int exampleSize = 5;
int example[exampleSize];
Entity()
{
for (int i = 0; i < exampleSize; i++)
example[i] = i;
}
};
当然也可以使用array:
#include <array>
class Entity
{
public:
// <类型,长度>
array<int, 5> another;
Entity()
{
// 调用size()
for (int i = 0; i < another.size(); i++)
another[i] = i;
}
};
使用array会有一定代价,array会有单独变量来维护数组长度,并且会做边界检查等,会稍慢。但array会更方便,也会更安全。