from http://www.learncpp.com/cpp-tutorial/14-a-first-look-at-functions/
一个函数是有许多语句的顺序组合用来完成一项特殊的功能。你已经知道每个程序都需要一个入口函数,main()。但是,大多数程序中含有更多的函数,它们的工作方式与main类似。
通常你的程序需要中断正在执行的语句暂时去处理一些其他的事情。在现实生活中,你经常这么做。举个例子,当你记起你需要打个电话的时候,你也许正在读一本书。你放好书签,打电话,当你打完电话后,再继续读你的书。
C++程序的工作方式类似这么一个过程。当一个程序遇到一个函数调用的时候,会顺序的执行函数中的语句。函数调用就是告诉CPU终端当前的函数,执行其他的函数。CPU在当前执行点放置一个“书签”,然后执行调用函数中的语句。当这个调用函数执行完成后,CPU又返回到原来放置书签的地方,恢复执行。
这里有个新函数声明和调用的例子:
1: //#include <stdafx.h> // Visual Studio users need to uncomment this line
2: #include <iostream>
3:
4: // Declaration of function DoPrint()
5: void DoPrint()
6: {
7: using namespace std; // we need this in each function that uses cout and endl
8: cout << "In DoPrint()" << endl;
9: }
10:
11: // Declaration of main()
12: int main()
13: {
14: using namespace std; // we need this in each function that uses cout and endl
15: cout << "Starting main()" << endl;
16: DoPrint(); // This is a function call to DoPrint()
17: cout << "Ending main()" << endl;
18: return 0;
19: }
这个程序会产生下列输出:
Starting main()
In DoPrint()
Ending main()
这个程序从main()函数的顶端开始执行,第一行执行打印出 Starting main()。第二行是调用DoPrint函数。在这个点,main函数中的执行语句中断,CPU掉到DoPrint()函数。DoPrint函数的第一行被执行输出 In DoPrint()。当DoPrint函数执行完后,main函数恢复执行。因此,main函数中的下个语句被执行输出 Ending main()。
函数能够被多次调用:
1: //#include <stdafx.h> // Visual Studio users need to uncomment this line
2: #include <iostream>
3:
4: // Declaration of function DoPrint()
5: void DoPrint()
6: {
7: using namespace std;
8: cout << "In DoPrint()" << endl;
9: }
10:
11: // Declaration of main()
12: int main()
13: {
14: using namespace std;
15: cout << "Starting main()" << endl;
16: DoPrint(); // This is a function call to DoPrint()
17: DoPrint(); // This is a function call to DoPrint()
18: DoPrint(); // This is a function call to DoPrint()
19: cout << "Ending main()" << endl;
20: return 0;
21: }
函数产生如下的结果:
Starting main() In DoPrint() In DoPrint() In DoPrint() Ending main()
在这个例子中函数main中断了三次。
main函数并不是惟一一个能够购调用其他函数的函数。在下面的例子中,DoPrint()函数调用了第二个函数,DoPrint2()。
1: //#include <stdafx.h> // Visual Studio users need to uncomment this line
2: #include <iostream>
3:
4: void DoPrint2()
5: {
6: using namespace std;
7: cout << "In DoPrint2()" << endl;
8: }
9:
10: // Declaration of function DoPrint()
11: void DoPrint()
12: {
13: using namespace std;
14: cout << "Starting DoPrint()" << endl;
15: DoPrint2(); // This is a function call to DoPrint2()
16: DoPrint2(); // This is a function call to DoPrint2()
17: cout << "Ending DoPrint()" << endl;
18: }
19:
20: // Declaration of main()
21: int main()
22: {
23: using namespace std;
24: cout << "Starting main()" << endl;
25: DoPrint(); // This is a function call to DoPrint()
26: cout << "Ending main()" << endl;
27: return 0;
28: }
产生的输出如下:
Starting main() Starting DoPrint() In DoPrint2() In DoPrint2() Ending DoPrint() Ending main()
返回值
如果你还记得,但main函数执行完成后,它使用return语句返回一个值给操作系统。你写的函数也能够返回一个数值给调用者。我们通过在函数声明中改变函数的返回类型来实现。返回类型为void意味着函数没用返回一个值。返回类型为int意味着函数返回整型给调用者。
1: // void means the function does not return a value to the caller
2: void ReturnNothing()
3: {
4: // This function does not return a value
5: }
6:
7: // int means the function returns an integer value to the caller
8: int Return5()
9: {
10: return 5;
11: }
让我们在程序里使用这些函数:
1: cout << Return5(); // prints 5
2: cout << Return5() + 2; // prints 7
3: cout << ReturnNothing(); // This will not compile
在第一个语句中,Return5被执行,函数返回5给调用者,然后再输出这个值。
在第二个语句中,Return5被执行,函数返回5给调用者。表达式5 + 2产生7。7在传到cout。
在第三个语句中,ReturnNothing()返回void。将void传给cout是不合理的,当你编译这行的时候,编译器将会产生一条错误。
一个通常被问到的问题是,“我的函数能否通过return语句返回多个值呢?”这个回答是,不能。函数通过return语句只能返回一个值。但是,存在解决这个问题的方法,我们会在深入了解函数的章节中讨论。
返回到main函数
现在,你已经了解了main函数如何执行的基本概念。当一个程序执行的时候,操作系统产生一个main函数的调用。执行转到main函数的顶部。main函数中的语句被顺序执行。最后,main函数返回一个整型值给操作系统。这是main函数声明为int main()的原因。
一些编译器对于void main()的声明不会给出错误信息。技术上来讲,这是不合理的。当编译器看到void main()函数时,它被解释为:
1: int main()
2: {
3: // your code here
4: return 0;
5: }
你应该将main函数声明为int型,当你返回一个值时应该是0(当出现错误的时候,返回其他的整数)。
参数
在返回值的部分,你了解到函数能够返回一个值给调用者。参数是允许调用者将信息传递给函数。这允许写成的函数能够完成一般化的任务,不必担心使用的特殊的值,将确切的变量的值交给调用给予。
通过例子能够更好的理解。这里有个简单的例子,两个参数相加,返回和:
1: //#include <stdafx.h> // Visual Studio users need to uncomment this line
2: #include <iostream>
3:
4: // add takes two integers as parameters, and returns the result of their sum
5: // add does not care what the exact values of x and y are
6: int add(int x, int y)
7: {
8: return x + y;
9: }
10:
11: int main()
12: {
13: using namespace std;
14: // It is the caller of add() that decides the exact values of x and y
15: cout << add(4, 5) << endl; // x=4 and y=5 are the parameters
16: return 0;
17: }
当add函数被调用的时候,x被赋值为4,y被赋值为5.函数执行x+y,结果为9,将这个值返回给调用者。然后将9传到cout,输出到屏幕。
输出:
9
看一下函数的其他调用:
1: //#include <stdafx.h> // Visual Studio users need to uncomment this line
2: #include <iostream>
3:
4: int add(int x, int y)
5: {
6: return x + y;
7: }
8:
9: int multiply(int z, int w)
10: {
11: return z * w;
12: }
13:
14: int main()
15: {
16: using namespace std;
17: cout << add(4, 5) << endl; // evalutes 4 + 5
18: cout << add(3, 6) << endl; // evalues 3 + 6
19: cout << add(1, 8) << endl; // evalues 1 + 8
20:
21: int a = 3;
22: int b = 5;
23: cout << add(a, b) << endl; // evaluates 3 + 5
24:
25: cout << add(1, multiply(2, 3)) << endl; // evalues 1 + (2 * 3)
26: cout << add(1, add(2, 3)) << endl; // evalues 1 + (2 + 3)
27: return 0;
28: }
输出:
9 9 9 8 7 6
前三个调用是直接的。
地四处调用也是相对简单的:
1: int a = 3;
2: int b = 5;
3: cout << add(a, b) << endl; // evaluates 3 + 5
在这个例子中,add调用,x=a,y=b。因为a = 3,b = 5,add(a,b)=add(3,5),它的结果为8.
让我们看一下第一个有点技巧性的语句:
1: cout << add(1, multiply(2, 3)) << endl; // evalues 1 + (2 * 3)
当CPU试着调用函数add时,x = 1, y = multiply(2,3)。y不是一个整数,是一个函数调用。因此在CPU调用add函数之前,先调用multiply(),其中z = 2,w = 3。multiply(2,3)的值为6,讲这个值赋值给y。因此x = 1,y = 6,add(1,6)被调用,产生7。将7传给cout。
或用简单的方式表示(用=>符号表示求值):
add(1, multiply(2,3))=>add(1,6)=>7
下面语句中add函数的一个参数调用了add函数:
1: cout << add(1, add(2, 3)) << endl; // evalues 1 + (2 + 3)
但是这个语句的执行与上述一致。
简单表示:
add(1,add(2,3))=>add(1,5)=>6
有效地使用函数
对于新手遇到的一个艰巨的问题(处理语言上的)是了解什么时候或怎样有效的使用一个函数。通过函数能够是你的程序分解为易管理的、易重复调用的部分,它们能够很容易的组合在一起实现更大的更复杂的功能。把你的程序分解成小的部分,程序整体的复杂性将会减少,这使得程序变得更加容易编写和修改。
当你学习C++的时候,你会写很多包含3个基本功能的程序:
1. 读取用户输入的数据
2. 从输入的值中计算结果
3. 打印出计算值
对于简单的程序,用户输入数据的读取一般在main()函数中完成。但是,步骤2是函数重要的部分。函数将用户输入的作为参数,返回计算得到的结果。计算得到的结果能够打印出(直接在main()函数中,或是当计算结果很复杂、有特殊打印需求是,可以通过其他函数打印)。
一个好的规则是每个函数完成一项(仅一项)功能。新的程序员常常将第2步和第3步结合到一起。但是,计算数值结果和打印是两种不同的任务,这违背了仅实现一项功能的建议。理想上,一个函数计算结果,并返回,让调用者决定如何处理这个返回值。