Chapter 7: Arrays

数据是一种用于存储具有相同数据类型的值集合的数据结构。

数组声明与分配

要声明一个数组,你可以像普通变量声明那样,但是你需要在数组名之后添加一个方括号。括号中包含数组中元素的数量。

int myArray[3]; // integer array with 3 elements

这些元素的默认值与变量相同-全局数组中的元素被初始化为其默认值,而局部数组中的元素未被初始化。

数组赋值

要为元素赋值,你可以通过在方括号中放置元素的索引,一次访问一个元素,索引由零开始。

myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;

或者,你可以在数组声明的同时将值包含在花括号中进行赋值。如果指定数组的长度大于初始值的数量,其余的值会被初始化为零。数组的长度可以留空,从而允许数组的尺寸由赋值的个数进行确定。

int myArray[3] = { 1, 2, 3 };
int myArray[] = { 1, 2, 3 };

一旦数组元素初始化,可以通过引用你希望的元素的索引进行访问。

int x = myArray[0]; // 1

多维数组

通过添加多个方括号可以生成多维数组。类似于一维数组,它们可以一次填充一个或是在声明时一次填充所有值。

int myArray[2][2] = { { 0, 1 }, { 2, 3 } };
myArray[0][0] = 0;
myArray[0][1] = 1;

额外的花括号是可选的,但是包含它们是一个好主意,因为它可以使得代码更易于阅读。

int myArray[2][2] = { 0, 1, 2, 3 }; // alternative

动态数组

由于前面的数组由静态数组构成,其尺寸必须在执行之前确定。所以尺寸必须是一个常数值。要创建直到运行时尺寸才可知的数组,你需要使用动态内存,这是使用new关键字分配,并且必须赋给一个指针。

int* p = new int[3]; // dynamically allocated array

C++中的数组是指向数组中第一个元素的常量指针。所以数组元素的引用可以通过指针算术运算实现。通过将指针增加1,你移动到数组中的下一个元素,因为对指针地址的修改隐式与指针的数组类型的尺寸相乘。

*(p+1) = 10; // p[1] = 10;

数组尺寸

类似于其它的指针,指针可能超出数组的正确范围,从而重写某些相邻内存。这是应该避免的情况,因为这会导致不可预期的结果或崩溃程序。

int myArray[2] = { 1, 2 };
myArray[2] = 3; // error: out of bounds

要确定一个普通(静态分配)数组的长度,你可以使用std::size函数。

#include <iostream> // std::size
int main()
{
    int myArray[2] = { 1, 2 };
    int length = std::size(myArray); // 2
}

此方法不能用于动态分配的数组。确定动态分配的数组的尺寸的唯一方法通过分配时使用的变量来确定。

int size = 3;
int* p = new int[size]; // dynamically allocated array

当你完成动态数组的使用,你必须记住删除它。这是通过使用delete关键字与方括号来实现的。

delete[] p; // release allocated array
p = nullptr; // mark pointer as unused

向量

向量是一个表示可变数组的窗口类。向量的元素类型是在类名后的尖括号中指定的,因为向量是所谓的模板类。

#include <vector> // std::vector
using namespace std;
int main()
{
    vector<int> myVector;
}

向量要优于动态数组,因为它有多种优点,包括按需增长或缩小的能力。向量会在超出其作用域时隐式自动销毁,所以无需手动删除。下面的示例演示了如何赋值,修改与读取向量的元素。

#include <vector>
using namespace std;
int main()
{
    vector<int> v;
    // Assign three elements with value two
    v.assign(3, 2); // [2, 2, 2]
    // Add 4 at last position
    v.push_back(4); // [2, 2, 2, 4]
    // Change first element
    v[0] = 1; // [1, 2, 2, 4]
    // Change second element (bound checked)
    v.at(2) = 3; // [1, 2, 3, 4]
    // Remove second element
    v.erase(v.begin()+1); // [1, 3, 4]
    // Remove last element
    v.pop_back(); // [1, 3]
    // Get vector length
    int len = v.size(); // 2
    // Print first and second elements
    cout << v.at(0) << v[1]; // "13"
}