数组是一种复合类型:a[d],其中a是数组的名字,d是数组的维度。与vector不同的地方是,数组的大小确定不变,不能随意向数组中增加元素。且数组的维度必须是一个常量表达式。
一、定义和初始化内置数组
1.1显示初始化数组元素
const unsigned sz = 3;
int ia1[sz] = {0, 1, 2}; // 含有三个元素,分别是0, 1, 2
int a2[] = {0, 1, 2}; // 维度是3的数组
int a3[5] = {0, 1, 2}; // 等价于 a3[] = {0, 1, 2, 0, 0}
int a4[2] = {0, 1, 2}; // 错误:初始值太多
1.2字符数组的特殊性
字符数组有一种额外的初始化形式,可以用字符串字面值对此类数组初始化。当使用这种方式时,一定要注意字符串字面值的结尾处还有一个空字符。
char a1[] = {'C', '+‘, ’+‘}; // 列表初始化,没有空字符
char a2[] = "C++"; // 自动添加表示字符串结束的空字符
const char a3[5] = "renle"; // 错误:没有空间可存放空字符!
1.3不允许拷贝和赋值
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值:
int a[] = {0, 1, 2};
int a2[] = a; // 错误:不允许使用一个数组初始化另一个数组
a2 = a; // 错误:不能把一个数组直接赋值给另一个数组
1.4复杂的数组声明
int *ptrs[10]; // ptrs是含有10个整型指针的数组
int &refs[10] = /*?*/; // 错误:不存在引用的数组
int (*parray)[10] = &arr; // parray指向含有10个整型的数组
int (&arrref)[10] = arr; // arrref引用一个含有10个整数的数组
二、访问数组元素
在使用数组下标时,通常将其定义为size_t类型。
2.1指针和数组
int a[] = {1,2,3,4};
int *p = &a[0]; p指向a的第一个元素
int *p2 = a; // 等价于p2 = &a[0]
使用auto变量作为初始值时,推断得到的类型是指针,而非数组:
int ia[] = {1, 2, 3, 4, 5, 6, 7, 8};
auto ia2(ia); // ia2是一个整型指针,指向ia的第一个元素,相当于auto ia2(&ia[0])
2.2指针也是迭代器
int arr[] = {0, 1, 2, 3, 4};
int *p = arr; // p指向arr的第一个元素
++p; // p指向arr[1]
2.3标准库函数begin和end
数组的begin和end与vector的不同,不过数组毕竟不是类类型,因此这两个函数不是成员函数。
int ia[] = {0, 1, 2, 3, 4, 5};
int *beg = begin(ia); // 指向ia首元素的指针
int *last = end(ia); // 指向arr尾元素的下一位置的指针
2.4指针运算
constexpr size_t sz = 5;
int arr[sz] = {1, 2, 3, 4, 5};
int *ip = arr; // 等价于int *ip = &arr[0]
int *ip2 = ip + 4; // ip2指向arr的尾元素arr[4]
指针加上一个整数所得的结果还是一个指针,假设结果指针指向了一个元素,则允许解引用该结果指针:
int ia[] = (0, 2, 4, 6, 8}; // 含有5个整数的数组
int last = *(ia+4); 正确:把last初始化为8,也就是ia[4]的值
2.5下标和指针
int i = ia[2]; // ia转换成数组首元素的指针, ia[2]得到(ia + 2)的元素
只要指针指向的是数组中的元素,都可以执行下标运算:
int *p = &ia[2]; // p指向索引为2的元素
int j = p[1]; // 为ia[3]表示的那个元素
int k = p[-2]; // 为ia[0]表示的那个元素
2.6使用数组初始化vector对象
int int_arr[] = {0,1,2,3,4};
vector<int>ievc(begin(int_arr),end(int_arr));