数组 (C++)
数组是相同类型的对象序列,它们占据一块连续的内存区。 传统的 C 样式数组是许多 bug 的根源,但至今仍很常用,尤其是在较旧的代码库中。 在新式 C++ 中,我们强烈建议使用 std::vector
或 std::array
,而不是本部分所述的 C 样式数组。 这两种标准库类型都将其元素存储为连续的内存块。 但是,它们提供更高的类型安全性,并支持保证指向序列中有效位置的迭代器。
堆栈声明
在 C++ 数组声明中,数组大小在变量名称之后指定,而不是像在其他某些语言中那样的在类型名称之后指定。 以下示例声明了要在堆栈上分配的 1000 个双精度值的数组。 元素数量必须以整数文本或常量表达式的形式提供。 这是因为,编译器必须知道要分配多少堆栈空间;它不能使用在运行时计算的值。 为数组中的每个元素分配默认值 0。 如果你不指定默认值,则每个元素最初包含恰好位于该内存位置的任意随机值。
constexpr size_t size = 1000;
// Declare an array of doubles to be allocated on the stack
double numbers[size] {
0};
// Assign a new value to the first element
numbers[0] = 1;
// Assign a value to each subsequent element
// (numbers[1] is the second element in the array.)
for (size_t i = 1; i < size; i++)
{
numbers[i] = numbers[i-1] * 1.1;
}
// Access each element
for (size_t i = 0; i < size; i++)
{
std::cout << numbers[i] << " ";
}
数组中的第一个元素是第 0 个元素。 最后一个元素是 (n-1) 元素,其中 n 是数组可以包含的元素数量。 声明中的元素数量必须是整数类型,且必须大于 0。 你需要负责确保程序永远不会将大于 (size - 1)
的值传递给下标运算符。
仅当数组是 struct
或 union
中的最后一个字段并启用了 Microsoft 扩展(未设置 /Za
或 /permissive-
)时,零大小的数组才是合法的。
分配和访问基于堆栈的数组的速度比基于堆的数组更快。 但是,堆栈空间是有限的。 数组元素的数量不能太大,以免占用过多的堆栈内存。 多大的数量算作“太大”取决于程序。 可以使用分析工具来确定数组是否太大。
堆声明
你可能需要一个太大的、以致无法在堆栈上分配的数组,或者需要一个其大小在编译时未知的数组。 可以使用 new[\]
表达式在堆上分配此数组。 运算符返回指向第一个元素的指针。 下标运算符处理指针变量的方式与处理基于堆栈的数组的方式相同。 还可以使用指针算术将指针移到数组中的任意元素。 你需要负责确保:
- 始终保留原始指针地址的副本,以便可以在不再需要数组时删除内存。
- 不会将指针地址递增或递减至超过数组边界。
以下示例演示在运行时如何在堆上定义一个数组。 其中演示了如何使用下标运算符和指针算术来访问数组元素:
void do_something(size_t size)
{
// Declare an array of doubles to be allocated on the heap
double* numbers = new double[size]{
0 };
// Assign a new value to the first element
numbers[0] = 1;
// Assign a value to each subsequent element
// (numbers[1] is the second element in the array.)
for (size_t i = 1; i < size; i++)
{
numbers[i] = numbers[i - 1] * 1.1;
}
// Access each element with subscript operator
for (size_t i = 0; i < size; i++)
{
std::cout << numbers[i] << " ";
}
// Access each element with pointer arithmetic
// Use a copy of the pointe