前面的示例中使用了数组,但尚未对这个实用而底层的结构给出正式定义。请注意,本节中的“数组”特指原生内置数组,而非std::vector<T>或std::array<T,N>这些更高级的构造。
在C++中,数组是相同类型元素的连续序列。下述代码中,对象a0占据10*sizeof(int)字节内存,而a1占据20*sizeof(std::string)字节:
int a0[10];
std::string a1[20];
对于类型为T的数组,其索引i和i+1处元素之间的字节距离严格等于sizeof(T)。
考虑以下C++(沿袭自C)的数组访问表达式:
arr[i]
其计算结果等价于:
*(arr + i)
由于指针算术是类型化的,表达式中的+i表示“加上i个元素”或“加上i倍单个元素的字节大小”。
数组大小必须为正数,除非为动态分配:
int a0[5]; // Ok
static_assert(sizeof a0 == 5 * sizeof(int));
enum { N = sizeof a0 / sizeof a0[0] }; // N == 5
// int a1[0]; // 不允许:该数组将与内存中的下一个对象地址相同!
int *p0 = new int[5]; // 可以,但你现在需要管理指针指向的内存
int *p1 = new int[0]; // 可以,动态分配的;你仍然需要管理指针指向的内存
// ...
delete [] p1; // 正确
delete [] p0; // 正确;要负起责任
每次调用operator new[]必须返回不同地址,即使数组大小为0,(从技术上讲)每次调用会返回不同对象的地址。