数组
数组是一个比较特殊的内置类型,数组的大小固定,程序的运行性能较好但是灵活性降低。
数组在定义时,数组的维度必须是已知的,所以需要是常量表达式(否则可以动态new一个数组)
unsigned cnt = 42; //是常量表达式
constexpr unsigned sz = 42; //不是常量表达式
默认情况下,数组的元素被默认初始化。
字符数组的特殊性
char a1[]={'C','+','+'}; //列表初始化,没有空字符
char a2[]={'C','+','+','\0'}; //列表初始化,有空字符
char a3[]="C++";
不允许拷贝和赋值
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
int a[]={1,2,3};
int a2[]=a; //错误,不允许使用一个数组初始化另一个数组
复杂的数组声明
[]的优先级比*高 ,
int *ptrs[10]; //ptrs是一个含有10个元素的数组,元素类型为int指针,可以简称为指针(的)数组。
int &refs[10]; //错误,不存在引用的数组。
不存在引用(的)数组可以这样理解,引用就是变量的别名,不是一个对象。这样引用本身是不占内存空间的(在实现时常常利用指针)。因此,声明引用数组没有办法分配空间,所以不能声明和定义引用数组。
int (*Parray)[10] = &arr; //Parry指向一个含有10个整数的数组,简称数组的指针
int (&arrRef)[10] = arr; //arrRef是一个含有10个整数的数组的引用,简称数组的引用。
传引用参数
把引用作为形参,这样对形参的操作实际上是作用在引用所引用的对象上。
使用引用避免拷贝
拷贝大的类型对象或者容器对象比较低效(值传递,需要值拷贝),甚至有些类类型(IO类型)根本就不支持拷贝操作。
使用引用形参返回额外信息
尽量使用常量引用
把函数不会改变的形参定义成(普通的)引用是一种常见的错误,这么做带给函数的调用者一种误导,即函数可以修改它的实参的值。另一方面,使用普通的引用,我们不能把const对象,字面值或者需要类型转换的对象传递给普通的引用。
指针形参
因为数组是以指针的形式传递给函数的,所以一开始函数并不知道数组的确切尺寸,调用者应该为此提供一些额外的信息。管理指针形参有三种常用的技术。
1、使用标记指定数组长度
数组有一个结束标记
2、使用标准库规范
void print(const int *beg, const int *end){
while(beg !=end)
cout <<*beg++<<endl;
}
int j[2]= {0,1};
print(begin(j),end(j));
3、显式传递一个表示数组大小的形参
void print(const int[], size_t size){
}
数组引用形参
前面说了可以有数组的引用,但是不能有引用的数组。所以形参可以是数组的引用。此时,引用形参绑定到对应的实参上,就是绑定到对应的数组上。
void print(int (&arr)[10]{
for(auto elem:arr)
cout <<elem<<endl;
}
上面的例子有一个局限就是执政将函数作用于大小为10的数组。
使用函数模板可以给引用类型的形参传递任意大小的数组。
template<unsigned N, unsigned M>
void print(const int (&p1)[N],const int (&p2)[M]){
cout << p1[0] <<" " <<p2[0];
}
多维数组
c++中没有多维数组的概念,多维数组就是数组的数组。按照从内向外的阅读顺序有助于更好地理解其真实含义。
在c++11中增加了范围for的使用
二重for来处理二维数组
size_t cnt=0;
int ia[r][c];
for(size_t i=0; i!=r; ++i)
for(size_t j=0; j!=c; ++j){
ia[i][j]=cnt;
++cnt;
}
使用范围for
size_t cnt=0;
int ia[r][c];
for(auto &row : ia)
for(auto &col : row){
col = cnt;
++cnt;
}
注意使用引用类型
int a[3][4];
int (*a)[4]; //一个指针,它指向一个含有四个int型元素的数组
int a[4]; //一个四个元素的数组,元素的类型为int
void print(int (*a)[4]) //用括号将指针括起来
{
printf("%d\n",a[0][0]);
}
int main()
{
int a[3][4] = {1,2,3,4,5,6};
print(a);
return 0;
}
因此二维数组作为函数参数正确写法如下所示:
void Func(int array[3][10]);
void Func(int array[ ][10]);
因为数组的行数无关紧要,所以还可以写成如下形式:
void Func(int (*array)[10]); 注意*array需要用括号括起来。
这种形式的声明参数是一个指针,它指向具有10个元素的一维数组。因为[]的优先级比*的优先级高,故*array必须用括号括起来,否则变成了
void Func(int *array[10]);
这时候参数相当于是声明了一个数组,该数组有10个元素,其中每个元素都是一个指向整型对象的指针。