7.2.5 传递给函数的数组的处理
非引用数组形参的类型检查只是确保实参是和数组元素具有同样类型的指针,而不会检查实参实际上是否指向指定大小的数组。
任何处理数组的程序都要确保程序停留在数组的边界内。
第一种方法是在数组本身放置一个标记来检测数组的结束,C风格字符串是一种字符数组,并且以空字符null作为结束的标记。处理C风格字符串的程序就是使用这个标记停止数组元素的处理。
1. 使用标准库规范
第二种方法是传递指向数组第一个和最后一个元素的下一个位置的指针。
void print(const int *first, const int *end)
{
for(; first!=end; ++first)
{
cout << *first << endl;
}
}
2. 显式传递表示数组大小的形参
void print(const int first[], const size_t len)
{
for(const int *end = first + len; first!=end; ++first)
{
cout << *first << endl;
}
}
7.2.6 main:处理器命令行选项
主函数的实参是可选的,用来确定程序要执行的操作。
第二个形参argv是一个C风格字符串数组。第一个形参argc则用于传递该数组中字符串的个数。
当将实参传递给主函数main时,argv中第一个字符串通常是程序的名字。接下来的元素将额外的可选字符串传递给主函数main。
7.2.7 含有可变形参的函数
在无法列举出传递给函数的所有实参的类型和数目时,可以使用省略符形参。省略符暂停了类型检查机制。它们的出现告知编译器,当调用函数时,可以有0或多个实参,而实参的类型未知。
void Method1(...){}
void Method2(int *i, ...){}
7.3 return语句
return语句用于结束当前正在执行的函数,并将控制权返回给调用此函数的函数。
void Method1(){
return;
}
int Method2(){
return 0;
}
7.3.1 没有返回值的函数
不带返回值的return语句只能用于返回类型为void的函数。在返回类型为void的函数中,return语句返回语句不是必需的,隐式的return发生在函数的最后一个语句完成时。
一般情况下,返回类型是void的函数使用return语句是为了引起函数的强制结束。
返回类型为void的函数通常不能使用第二种形式的return语句,但是,它可以返回另一个类型同样为void的函数的调用结果。
7.3.2 具有返回值的函数
return语句的第二种形式提供了函数的结果。任何返回类型不是void的函数都必须返回一个值,而且这个返回值的类型必须和函数的返回类型相同,或者能隐式转化为函数的返回类型。
在含有return语句的循环后没有提供return语句是很危险的,因为大部分的编译器不能检测出这个漏洞,运行时会出现什么问题是不确定的。
1. 主函数的main的返回值
允许主函数main没有返回值就可结束。如果程序控制执行到主函数main的最后一个语句都还没有返回,那么编译器会隐式地插入返回0的语句。
2. 返回非引用类型
函数的返回值用于初始化在调用函数处创建的临时对象。在求解表达式时,如果需要一个地方存储其运算结果,编译器会创建出一个没有命名的对象,这就是临时对象。
如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。当函数返回非引用类型时,其返回值既可以是局部对象,也可以是求解表达式的结果。
3. 返回引用
当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。
4. 千万不要返回局部对象的引用
理解返回引用至关重要的是:千万不能返回局部变量的引用
当函数执行完毕时,将释放分配给局部对象的存储空间。此时,对局部对象的引用就会指向不确定的内存。
5. 引用返回左值
如果不希望引用返回值被修改,返回值应该声明为const。
const int &Method(){}
6. 千万指向局部对象的指针
和返回局部对象的引用一样,返回指向局部对象的指针也是错误的。一旦函数结束,局部对象被释放,返回的指针就变成了指向不再存在的对象的垂悬指针。
7.3.3 递归
直接或间接调用自己的函数称为递归函数(recursion function).
递归函数必须定义一个终止条件:否则,函数就会“永远”递归下去,这意味着函数会一直调用自身直到程序栈耗尽。
主函数main不能调用自身。
const int Method(int v1, int v2)
{
if (v2 != 0)
return Method(v2, v1%v2);
return v1;
}