数组作为形参知识点
1.数组的维度必须是一个常量表达式
int main(void)
{
constexpr int i = 20;
int j = 5;//不是常量表达式
int arr1[i];//正确
int arr2[j];//错误
system("pause");
return 0;
}
2.默认情况下,数组的元素被默认初始化。而且需要注意的是,和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组有未定义的值。
什么是默认初始化?
如果定义变量时没有指定初值,则变量被默认初始化,此时变量被赋予默认值。默认值到底是什么有两个决定因素,一是变量类型;二是定义变量的位置。如果是内置类型的变量未被初始化,它的值由定义的位置决定。定义于任何函数体之外的变量被初始化为0.定义于函数体内部的内置类型变量将不被初始化。一个未被初始化的内置类型变量的值是未定义的。如果试图拷贝或以其他方式访问此类值将引发错误。
#include<iostream>
using namespace std;
int main(void)
{
int arr[5];
cout << arr[2] << endl;
system("pause");
return 0;
}
#include<iostream>
using namespace std;
int arr[5];
int main(void)
{
cout << arr[2] << endl;
system("pause");
return 0;
}
3.定义数组的时候必须指定数组的类型,不允许用auto关键字由初始值的列表推断类型。
auto int arr[5] = { 1,2,3,4,5 };//错误
4. 数组的两个特殊性质
(1)不允许拷贝数组
(2)使用数组时(通常)会将其转换为指针
比如当使用数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组
int i = 6;
int *p = &i;
int arr[] = { 1,2,3 };
auto a(arr);
a = p;//正确
但是当使用关键字decltype关键字时上述转换不会发生
int i = 6;
int *p = &i;
int arr[] = { 1,2,3 };
decltype(arr) a;
a = p;//错误,不能把整型指针给数组赋值
a[1] = 6;//正确
5.由于4的两个性质,所以我们无法以值传递的方式使用数组参数。因为数组会被转换为指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的地址
//尽管形式不同,但下面3个fcn函数是等价的,每个函数
//都有一个const int*类型的形参,所以不属于重载
void fcn(const int*){}
void fcn(const int[]) {}
void fcn(const int[10]){}
6.C++允许将形参定义成数组的引用,此时引用形参绑定到对应的实参上,但是,不同于5,此时的数组不是以指针形式存在
也就是说:
//属于重载,因为维度的不同
void fcn(int (&arr)[10]){}
void fcn(int (&arr)[20]){}
#include<iostream>
using namespace std;
void print(int(&arr)[5])
{
for (auto elem : arr)
cout << elem << endl;
}
int main(void)
{
int a1[3] = { 1,2,3 };
int a2[5] = { 1,2,3,4,5 };
//print(a1);错误:实参不是含有5个整数的数组
print(a2);
system("pause");
return 0;
}
返回数组指针知识点
因为数组不能被拷贝,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。
1.使用类型别名
//下面两者的arr都是类型别名,它表示的类型是含有10个整数的数组
typedef int arr[10];
using arr = int[10];
//fun返回一个指向含有10个整数的数组的指针
arr* func(int i);
2.直接返回
int(*func(int i))[10];
fun(int i)表示调用func函数需要int类型的实参。
(*func(int i))表示函数返回一个指针
int (*func(int i))[10]表示返回的指针是指向一个int类型的数组
插叙:如何阅读C++中的复杂声明
黄金法则:从标识符开始(或者最内层的结构,如果不存在标识符的话,通常出现于函数指针),首先向右看,直到遇到 ) 括号或者结束,看到什么就说出来;然后向左看,直到遇到 ( 括号或者回到行首,看到什么就说出来。跳出一层括号,重复上述过程:右看看,说出来;左看看,说出来。直到你说出变量的类型或者返回值(针对函数指针),也就表示你把声明都读完了。
int (*(*vtable)[])();
这是一个指针,指向一个数组,数组的每个元素是一个指向返回值是int类型函数的指针
3.使用尾置返回类型
C++11新标准中的方法,任何函数的定义都能使用尾置返回类型,但是这种形式对于返回类型比较复杂的函数声明最有效。
//fun接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int(*)[10];
4.使用decltype
int arr[] = { 1,2,3,4,5 };
decltype(arr) *func(int i);
注意:前面说过,decltype所说明的arr是一个数组,要想func返回指针必须在函数声明时加一个*