1、数组的概念
数组是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问。与vector不同的地方是,数组的大小确定不变,不能随意向数组中添加元素。如果不清楚元素的确切个数,请使用vector。
2、定义和初始化内置数组
数组的声明a[d],a表示数组名,d表示数组的维度。维度说明了数组中元素的个数。因此必须大于0.维度必须是一个常量表达式。
unsigned int cnt = 40;//不是常量表达式
constexpr unsigned int cnt = 40;// 常量表达式
注意:定义数组的时候必须指定数组的类型,不允许用auto关键字由初始值的列表推断类型。另外和vector一样,数组的元素为对象,不存在引用的数组。
l 显示初始化数组元素
可以对数组的元素进行列表初始化,此时忽略数组的维度。如果没有指明维度,编译器会自动计算初始值的数量。如果指明了维度,初始值的数量不能超过指定的大小。
int a[3] = {1,3,5};
int a[] = {1,3,5};//与上面等价
l 字符数组的特殊性
字符数组有一种额外的初始化形式。我们可以用字符串字面值对此类数组初始化。当使用这种方式时,一定要注意字符串字面值的结尾处还有一个空字符,这个空字符也会像字符串的其他字符一样被拷贝到字符数组中去。
char a1[] = {'c','+','+'}; //列表初始化,没有空字符
char a2[] = {'c',+'','+','\0'}; //列表初始化,有空字符
char a3[] = ''C++''; //自动添加表示字符串结束的空字符
const char a4[6] = "Daniel";//错误:没有空间可存放空字符!数组大小至少为7
l 不允许拷贝和赋值
不能讲数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
int a[] = {0,1,3};//含有3个整数的数组
int a2[] = a;//错误:不允许使用一个数组初始化另一个数组
a2 = a;//错误:不能把一个数组直接赋值给另一个数组
l 理解复杂的数组声明
和vector一样,数组能存放大多数类型的对象。例如,可以定义一个存放指针的数组。又因为数组本身就是对象,所以允许定义数组的指针及数组的引用。
int *ptrs[10];//ptrs是含有10个整型指针的数组
int &refs[10];//错误:不存在引用的数组
int (*Parray)[10] = &arr;//Parray指向一个含有10个整数的数组
int(&arrRef)[10] = arr;//arrRef引用一个含有10个整数的数组
int*(&arry)[10] = ptrs;//array是数组的引用,该数组含有10个指针。
l 访问数组元素
与标准库类型vector和string一样,数组的元素也能使用范围for语句或下标运算符来访问。在使用数组下标的时候,通常将其定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计的足够大以便能表示内存中任意对象的大小。
int scores[5] = {1,3,4,5,6};
第一种方式:
for(auto i:scores){
cout<<i<<endl;
}
第二种方式:
for(int i = 0;i<5;i++){
cout<<a[i]<<endl;
}
3、指针和数组
通常情况下,使用地址符来获取指向某个对象的指针。取地址符可以用于任何对象。数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。因此,像其他对象一样,对数组的元素使用取地址符就能得到该元素的指针。
string nums[] = {“one”,”two”,”three0”};//数组的元素是string对象 string *p = &nums[0];//p指向nums的第一个元素
另外还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
string *p2 = nums;//等价于p2 = &nums[0];
在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
int ia[] = {0,1,2,3,4,5,6,7,8,9};//ia是一个含有10个整数的数组
auto ia2(ia);//ia2是一个整型指针,指向ia的第一个元素
ia2 = 42;//错误:ia2是一个指针,不能用int值给指针赋值
auto ia2(&ia[0]);//显然ia2的类型是int*。
decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9};//ia3是一个含有10个整数的数组。
ia3 = p;//错误:不能用整型指针给数组赋值
ia3[4] = 1;//正确:把i的值赋给ia3的一个元素
引用
引用为对象起了另外一个名字,引用类型引用另外一种类型。通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名:
int val = 1024;
int &refval = ival;//refval指向ival(是ival的另一个名字)
int &refval2;//报错:引用必须被初始化
一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。
l 引用即别名
引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。
l 引用的定义
允许在一个语句中定义多个引用,其中每个引用标识符都必须以符号&开发;
int i = 1024,i2 = 2048;//i和i2都是int
int &r = i,r2 = i2;//r都是一个引用,与i绑定在一起,
r2是int
int i3 = 1024,&ri = 3;//r3是int,ri是一个引用,与i3绑定在一起
int &r3 = i3,&r4 = 12;//r3和r4都是引用
int &refVal4 = 10;//错误:引用类型的初始值必须是一个对象
double dval = 3.14;//
int &refVal5 = dval;//错误:此处引用类型的初始值必须是int型对象