这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
函数
看了看C++ Premier Plus在函数上花的篇幅,想在两篇内总结函数的知识点似乎不太现实。。。
函数声明与定义
多数语言的函数声明与使用都很相似,C++也不例外,只是作为强类型语言,C++要求明确地声明函数返回类型与参数列表及类型:
typeName functionName(parameterList){
// ...
}
int bigger(int a, int b) {
if (a > b )
return a;
else
return b;
}
一个C++中函数使用地特性是,需要把函数在文件头部先声明一遍(虽然这种做法叫做prototype,但显然翻译为声明比原型更为合适),如下:
double cube(double x); // function prototype ...
int main() {
...
double q = cube(1.2); // function call
...
}
double cube(double x) // function definition
{
return x * x * x;
}
诶,这个做法不就是JS中常讲地提升吗,变量和函数的定义在编译过程中自动被提升到文件的头部,只是C++中我们需要自己去做这件事。尽管讲JS提升的文章看过不知道多少篇,但从来没一篇说为什么要提升的,而C++ Premier Plus好心地告诉了我原因:尽管对于程序员来说这种提升是个废操作,但对于编译器而言,了解一个函数地的返回值、参数列表有助于其了解函数的返回值要放在哪里(寄存器or内存),进而知道去哪里取值。
那么问题来了,编译器不能自己去找函数定义吗?答案是,C++不想这么做,除了出现在文件下方,函数定义可能在引入的其他文件中,但根本原因是,C++不愿意浪费时间干这种降低编译器效率的事,这是C++的哲学。
函数传值与递归
C++函数的参数实际的行为是:
- 根据函数的形参名称,创造一个同名变量,把传入的值赋给该变量
- 函数内部逻辑执行
- 函数结束执行返回,该变量被释放(对内存地址而言是释放,也可以认为这个变量就被销毁了)
这个说法和
JS中的函数作用域是相似的。事实上,最直白易懂的函数传值讲解就是搞明白递归函数了:
void countdown(int n);
int main() {
countdown(4);
return 0;
}
void countdown(int n) {
using namespace std;
cout << "Counting down ... " << n << " (n at " << &n << ")" << endl;
if (n > 0)
countdown(n-1); // 递归
cout << n << ": end!"; << " (n at " << &n << ")" << endl;
}
//输出
Counting down ... 4 (n at 0012FE0C)
Counting down ... 3 (n at 0012FD34)
Counting down ... 2 (n at 0012FC5C)
Counting down ... 1 (n at 0012FB84)
Counting down ... 0 (n at 0012FAAC)
0: end! (n at 0012FAAC)
1: end! (n at 0012FB84)
2: end! (n at 0012FC5C)
3: end! (n at 0012FD34)
4: end! (n at 0012FE0C)