数组是一种复合类型,与vector类似数组也是存放类型相同的对象的容器(所以不能存放引用),这些对象没有名字,需要通过其位置访问。数组本身是一个对象。
与vector不同的是数组的大小是固定的,不能随意的向数组中增加元素。
首先是数组的声明,数组的声明形如 a[d] ,其中a是数组的名字,d是数组的维度,维度必须是一个常量表达式,且必须大于0;
默认情况下,数组中的元素会被默认初始化,和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值。在定义数组时,必须指定数组的类型,不允许用auto关键字有初始值的列表推断类型。
在使用字符串字面值对数组初始化的时候,注意字符串字面值的结尾处还有一个空字符,这个空字符也会像被拷贝到字符数组中去。
char a1[] = "C++"; //会添加表示字符串结束的空字符
char a2[] = {'C','+','+','\0'}; //等价于a1,含有显式的空字符
让我们来看看书中几个数组的声明:
int *ptrs[10]; //定义了一个存放了10个指向int类型的指针,名为ptr的数组
int &refs[10] = /* ? */; //illegal,数组中存放的是对象,而引用只是变量的别名,不是一个对象
int(*Parray)[10] = &arr; //从内部向外理解数组的定义,首先看*Parray,这意味着Parray是一个指针,然后看右边,可知Parray指向的是一个大小为10的数组,接下来看左边,可知数组中的元素类型为int,其中arr为数组名,&为取地址运算符
int (&arrRef)[10] = arr; //arrRef是一个绑定了一个含有10个int类型元素的数组,其中arr为数组名
与vector和string一样,数组的元素也可以通过 范围 for 语句或下标运算符来访问,数组的索引从0开始。数组的下标通常被定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计得足够大以便能表示内存中任意对象的大小,在cstddef头文件中定义。
在使用数组的时候编译器一般会把他转换成指针
和其他对象一样,对数组的元素使用取地址符就能得到指向该元素的指针:
string nums[] = {"one","two","three"};
string *p = &nums[0];
然而数组还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
string *p2 = nums; //等价于 string *p2 = &nums[0]
在大多数的表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。(没看懂什么意思)
例如:使用数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组。
int a[10];
auto a2(a); //a2是一个整型指针,指向a第一个元素。等价于 auto a2(&a[0]);
当使用decltype关键字是上述转换不会发生,decltype(a)返回的类型是有10个整数构成的数组。
可以定义一个指向数组的尾后元素的指针来完成对数组的循环,但是这样极容易出错,因为尾后元素不是实际存在的,所以如果对尾指针进行解引用或者递增操作会发生不可预知的错误。
标准库函数begin和end:
begin和end这两个函数被定义在iterator头文件中,作用是返回数组首元素的指针和数组尾后元素的指针。由于数组不是类类型,因此这两个函数不是成员函数,正确的使用形式是将数组作为他们的参数。
指针运算:
两指针相减的结果是他们之间的距离,参与运算的两个指针必须指向同一数组当中的元素,而该结果的类型为 定义在cstddef头文件中的ptrdiff_t类型,它是一种带符号的类型。
如果p是空指针,允许,给p加上或减去一个值为0的整型常量表达式。两个空指针也允许彼此相减,结果当然是0.(有什么用呢?)
对数组执行下标运算其实就是对指向数组元素的指针执行下标运算:
int i= a[2];
//等价于
int *p = a[];
i = *(p+2);
//
int j = p[1]; //等价于*(p+1)
int k = p[-2]; //等价于*(p-2)
有关C风格字符串的问题,问题焦点就是C语言中的字符串是一个元素类型char的数组,而C++中的字符串却是一个string类型,
很多string的内置操作不能用在char上。(猜的)
使用数组初始化vector对象:
只需要指明拷贝区域的首元素地址和尾后地址:
vector<int> ivec(begin(int_arr),end(int_arr));
vector<int> subVec(int_arr + 1,int_arr + 4); //三个元素 int_arr[1]、int_arr[2]、int_arr[3]
多维数组:数组的数组
多维数组的初始化:
int a[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
等价于:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
在遍历多维数组的时候要注意:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针。
所以在下面的代码中,即使我们没有要修改数组元素的值,但是编译器在初始化row时,会自动将这些数组形式的元素转换成指向该数组内首元素的指针:
for (auto row : ia)
for(auto col : row)
本部分留下的问题:
数组不是 类 类型?
如果p是空指针,允许,给p加上或减去一个值为0的整型常量表达式。两个空指针也允许彼此相减,结果当然是0.(有什么用呢?)