程序设计应知道的那些事儿之函数
1函数
有时,程序员知道他需要多次使用同一组指令。可以将这些指令组合到一个被称为函数的较小的子程序中。在其他语言中,函数被称为子例程或程序。例如,控制汽车转向的动作实际上包含许多较小的动作:打开适当的转向灯、减速、查看迎面驶来的车辆、向合适的方向打方向盘等。本章开头介绍的驾驶路线说明需要相当多的转向,但是,列出每一个转向的短指令会使人觉得冗长乏味(并且可读性较差)。您可以向函数传递变量作为参数,以便修改函数控制行走的路线。在这个例子中,向函数传递的是转弯的方向。
Function Turn(variable_direction)
{
Activate the variable_direction blinker;
Slow down;
Check for oncoming traffic;
while(there is oncoming traffic)
{
Stop;
Watch for oncoming traffic;
}
Turn the steering wheel to the variable_direction;
while(turn is not complete)
{
if(speed < 5 mph)
Accelerate;
}
Turn the steering wheel back to the original position;
Turn off the variable_direction blinker;
}
这个函数列出了转弯所需的所有指令。一个已知该函数的程序需要转弯时,它只需调用这个函数就可以了。该函数被调用时,会根据传入的参数来执行函数内部的指令,然后,会返回到程序中函数调用之后的位置执行。左或右都可以传递给该函数,这些参数会位函数向相应方向转弯。
在C语言中,默认情况下函数会向调用它的程序返回一个值。对于那些我们熟悉的数学函数来说,这样做很有意义。设想一个计算自然数阶乘的函数——很自然,它会返回阶乘的结果。
在C语言中,函数并不是以function关键字为标识的,而是被声明成它们返回的变量的数据类型。这个格式看起来与变量声明非常类似。如果一个函数打算返回一个整数(也许是计算某一数字x阶乘的函数),则函数看起来如下所示:
int factorial(int x)
{
int i;
for(i=1; i < x; i++)
x*=i;
return x;
}
将这个函数声明为整型是因为佗将从1到x的每个值相乘并返回一个整型值的结果。在函数结尾的return语句回传变量x的值并结束函数。这时,这个阶乘函数可以像整型变量一样在任意能够识别该函数的程序主体中使用。
int a=5,b;
b=factorial(a);
在这个短程序的结尾,变量b的值为120,因为调用阶乘函数时会向它传递参数5,并返回120。
同样,在C语言中编译程序必须在可以使用函数之前先“认识”它。要想使编译程序认识函数,只需通过在程序中使用函数之前写出整个函数或者使用函数原型。函数原型只是一种告诉编译程序的方法,它告诉编译程序有一个与函数原型的名称、返回数据类型和参数都相同的函数存在。实体函数可以位于程序的结尾,但是可以在任何别的地方使用它,这是因为编译程序已经认识它了。Factorial()函数的函数原型的示例看起来就像下面这样:
int factorial(int);
通常,函数原型位于程层序开头部另分,并不需要在原型中实际定义任何变量名名字,因为这些是在实体函数中定义的。编译程序唯一关心的是函数名称、函数的返回数据类型和函数参数的数据类型。
如果一个函数没有任何返回值,则应将其是这样一个实例。但是,tum()函数并没有获得驾驶路线说明所需的所有功能,每次转向都需要一个方向和一个街道名称。这就意味着转向函数应当有两个变量:转向的方向和要转向的銜道。这使得转向函数变得复杂,因为必须在转向之前定位正确的街道。一个更加复杂、使用类C语法的转向函数以伪代码的形式列在下面。
void turn(variable_direction, target_street_name)
{
Look for a street sign;
current_intersection_name = read street sign name;
while(current_intersection_name != target_street_name)
{
Look for another street sign;
current_intersection_name = read street sign name;
}
Activate the variable_direction blinker;
Slow down;
Check for oncoming traffic;
while(there is oncoming traffic)
{
Stop;
Watch for oncoming traffic;
}
Turn the steering wheel to the variable_direction;
while(turn is not complete)
{
if(speed < 5 mph)
Accelerate;
}
Turn the steering wheel right back to the original position;
Turn off the variable_direction blinker;
}
这个函数包括一段程序,这段程序通过寻找路标搜寻正确十字路口、读取每个路标的名称并且将名称存储在一个名为current_intersection_name的变量中。它会继续寻找并读取路标直到找到目标街道,这时,其余的指令就会被执行。现在,可以使用这个转弯函数修改驾驶路线说明的伪代码。
Begin going East on Main Street;
while (there is not a church on the right)
Drive down Main Street;
if (street is blocked)
{
Turn(right, 15th Street);
Turn(left, Pine Street);
Turn(right, 16th Street);
}
else
Turn(right, 16th Street);
Turn(left, Destination Road);
for (i=0; i<5; i++)
Drive straight for 1 mile;
Stop at 743 Destination Road;
伪代码中一般不使用函数,,因为伪代码大多用于程序员在编写可编译代码之前概略地叙述程序思想。因为伪代码实际上并不工作,所以并不需要写出完整的函数——只需略记“这里要做某些复杂的东西”就足够了。但是在像C这样的程序设计语言中,大量地使用了函数。C语言的大多数实用函数来自于称为库的现有函数集合中。