数组就是一些列具有相同类型变量集合,便于维护。可以将数组理解为一个变量的集合的变量。
数组声明
数组在声明的时候需要指定出数组中元素的类型和数组的大小。
int arr[5];
数组即指针
int main(int argc, char const *argv[])
{
int arr[5];
std::cout << arr << std::endl;
std::cin.get();
}
运行代码,我们发现 arr 是一个内存地址,定义一个数组 arr 实际是一个指针类型,是一个数组的指针。
0x7ffeeafaa7f0
visual studio IDE 提供根据内存地址查看内存的功能,可以查看到数组是连续的内存的根据内存元素类型(也就是占用内存大小)以及数组的长度乘积所定。这里每个 int 占 4 字节。
数组还是一个有序的元素集合,这表示我们通过下标可以访问到数组的元素,在 c++ 下标是从 0 开始计算的,也有的语言是从 1 开始计算。
arr[0] = 1;
数组越界
当我们访问到那些不受我们控制的内存(arr[-1], arr[5]
),编译时候就会抛出警告,不过编译还是成功。不过既然我们做出规定还是应该按规定办事,要不可能在以后存在隐患和问题,难于调试。
arr[-1] = 1;
arr[5] = 1;
warning: array index 5 is past the end of the array (which contains 5 elements)
[-Warray-bounds]
数组的遍历
for (int i = 0; i < 5; i++)
{
std::cout << arr[i] << std::endl;
}
进一步证明数组就是指针
int main(int argc, char const *argv[])
{
int arr[5];
int *prt = arr;
for (int i = 0; i < 5; i++)
{
std::cout << prt[i] << std::endl;
}
std::cout << arr << std::endl;
std::cin.get();
}
定义一个指针变量然后将数组 arr 赋值给这个变量。然后遍历 prt 可以得到同上面相同结果。
int main(int argc, char const *argv[])
{
int arr[5];
int *prt = arr;
for (int i = 0; i < 5; i++)
{
prt[i] = 2;
}
*(prt + 2) = 5;
for (int i = 0; i < 5; i++)
{
std::cout << prt[i] << std::endl;
}
std::cin.get();
}
在上面代码中我们可以通过移动指针位置来修改指定位置数组的值,prt + 2
为指针为 2 的元素然后,通过*(prt+2)
进行对其赋值,输入结果如下。
2
2
5
2
2
这里是 int 类型指针所以内存存储单元为 4 字节,所以指针移动 2 表示移动了 8 字节,已经知道字符是占一个字节,所以将指针修改用于存储字符(char*)
,现在是按字符的字节数来移动指针所以移动 8 字节。然后将其转换为指向数据类型为 int 的指针。
*(int *)((char *)prt + 8) = 5;
栈与堆
之前我们所定义数组都是位于栈内存而非堆内存,如果我们用 new 所创建的数组都是位于堆内存而非栈内存。
int main(int argc, char const *argv[])
{
int arr[5];
int *another_arr = new int[5];
std::cin.get();
}
栈:是一种连续储存的数据结构,具有先进后出的性质。通常的操作有入栈(圧栈)、出栈和栈顶元素。想要读取栈中的某个元素,就要将其之前的所有元素出栈才能完成。类比现实中的箱子一样。
堆:是一种非连续的树形储存数据结构,每个节点有一个值,整棵树是经过排序的。特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。常用来实现优先队列,存取随意。
数组位于堆还是位于栈内存区别在于其生命周期。
int *another_arr = new int[5];
delete[] another_arr;
因为位于堆内存,所需需要手动释放内存,这里因为是数组所以通过delete[]
来代替delete
释放数组another_arr
。
class Tut
{
int arr[5];
Tut()
{
for (int i = 0; i < 5; i++)
{
arr[i] = 2;
}
}
};
上面 Tut 类中定义了一个数组,并且在构造函数对其进行赋值。然后我们打开内存查看器,就会发现这个数组内存地址位于该类中。
class Tut
{
int *arr = new int[5];
Tut()
{
for (int i = 0; i < 5; i++)
{
arr[i] = 2;
}
}
};
如果修改通过 new 在 Tut 类中创建数组就会发现,在类中仅有数组的指针地址,我们需要通过该地址可以访问到数组内存。
在 c++ 中我们无法通过 size 来像其他语言那样获取到数组的大小。
arr->size();
我们可以通过下面方法来间接获取数组的大小,通过数组所占字节数/数组元素类型所占的字节数,不过并不推荐这样使用我们需要自己来维护数组的大小。
int arr[5];
int count = sizeof(arr) / sizeof(int);
std::cout << count << std::endl;
推荐自己控制数组的大小
class Tut
{
static const int size = 5;
int arr[size];
Tut()
{
for (int i = 0; i < size; i++)
{
arr[i] = 2;
}
}
};
c++11
在 c++11版本支持标准库中的数组,而且也提供了便于操作的一些方法。
#include <iostream>
#include <array>
class Tut
{
static const int size = 5;
int arr[size];
std::array<int, 5> another;
Tut()
{
for (int i = 0; i < another.size(); i++)
{
another[i] = 2;
}
}
};
不过更多便利就是意味着更多性能的代价,个人推荐使用原生数组而不是c++ 提供数组。
网友评论