第6章 6.1 函数基础
一个典型的 函数定义 包括以下几个部分: 返回类型、 函数名字、由0个或多个形参组成的 列表 以及 函数体。其中,形参以 逗号 隔开,形参列表位于 一对圆括号 之内。
【调用函数】
函数的调用完成 两项 工作:
(1)用实参初始化函数对应的形参;
(2)将控制权转移给 被调函数。此时 主调函数 的执行被中断,被调函数 开始执行。
举个例子:
int function(int a) {
int t = 1; //局部变量
while(a > 1) {
t = t + a;
a--;
}
return t;
}
int main() {
int i = function(5);
cout << i << endl;
}
上例中,执行函数的第一步是(隐式地)定义并初始化形参列表。因此,当调用 function 函数时,首先创建一个名为 a 的 int 变量,然后将它初始化为调用时所用的实参 5.
【函数的形参列表】
函数的形参列表可以为空,但是不能省略。
要想定义一个不带形参的函数,可以使用两种方法:书写一个空的形参列表、使用关键字 void 表示函数没有形参:
// 空列表
void function1() {}
// 使用关键字void
void function2(void) {}
6.1.1 局部对象
形参 和 函数体内部定义的变量 统称为 局部变量。局部变量仅在函数的作用域内可见,同时局部变量会 隐藏 在外层作用域中同名的其它所有声明中。
在所有函数体之外定义的对象 存在于 程序的整个执行过程中。此类对象 在程序启动时 被创建, 直到 程序结束 才销毁。
【自动对象】
对于 普通局部变量 对应的对象来说,当函数的控制路径 经过变量定义语句时创建对象,当 到达定义所在的块末尾时销毁它,这种 只存在于块执行期间的对象 称为 自动对象。当块执行结束后,块中创建的自动对象的值就变成 未定义的。
函数的 形参 是一种自动对象:函数开始时为形参申请存储空间;因为形参定义在函数体作用域之内,所以一旦函数终止,形参就会被销毁。
自动对象的初始化 分为下面几种情况:
(1)形参对应的自动对象:用传递给函数的实参来初始化形参对应的自动对象;
(2)局部变量对应的自动对象:
A. 如果变量定义本身含有初始值,就用这个初始值进行初始化;
B. 如果变量定义本身不含初始值,则执行 默认初始化(内置类型的未初始化局部变量将产生未定义的值)。
【局部静态对象】
将 局部变量 定义成 static 类型,就可以令 局部变量的 生命周期 贯穿 函数调用及之后的时间。局部静态对象在程序执行路径第一次经过对象定义语句时初始化( **只初始化一次 **),并且直到程序终止才被销毁,在此期间 即使对象所在的函数结束执行也不会对它有影响。如果局部变量没有被初始化,它将执行值初始化(内置类型的局部静态变量初始化为0)。
例如:
void display() {
static int i = 0; // 该值只初始化一次,且该函数调用结束后,这个值仍然有效
i++;
cout << i << endl;
}
int main()
{
int k;
for(k=0; k<10; ++k) {
display();
}
return 0;
}
// 这段程序将输出从 1 到 10 的数字
6.1.2 函数声明
函数的名字必须在使用之前进行声明。类似于变量,函数只能定义一次,但可以声明多次。如果一个函数永远不会被用到,则可以 只有声明没有定义。
函数的声明与函数的定义非常类似,唯一的区别是 函数声明无须函数体,用一个分号替代即可*。因为函数的声明不包含函数体,因此也就 无需形参的名字。函数声明也称为 函数原型。
例子:
void display(int); // 函数声明
int main()
{
int k;
for(k=0; k<10; ++k) {
display(k);
}
return 0;
}
void display(int i) { // 函数定义
cout << i << endl;
}
【在头文件中进行函数声明】
函数应该 在头文件中声明,在源文件中定义。
要注意的是,定义函数的头文件应该被包含到定义函数的源文件中,编译器负责验证函数的定义和声明是否匹配。