### 定义和调用函数

通常情况下，函数包括返回值类型、函数名、参数列表和函数体 4 个部分。其中，返回值类型、函数名和参数列表构成了一个函数原型，而函数体表示函数的实现。在 C++中，函数的定义格式为：

返回值类型 函数名 (参数列表)

{

函数体;

}

通常，函数都有一个返回值，当函数结束时，将返回值返回给调用该函数的语句。但是，函数也可以没有返回值，即返回值类型为 void。函数名可以是任何合法的标识符。函数的参数列表是可选的，如果函数不需要参数，则可以省略参数列表，但是参数列表两边的括号不能省略。函数体描述的是函数的功能，主要由一条或多条语句构成。函数也可以没有函数体，此时的函数称为空函数。空函数不执行任何动作。在开发程序时，当前可能不需要某个功能，但是将来可能需要，此时可以定义一个空函数，在需要的时候为空函数添加实现代码。如果函数有返回值，通常在函数体的末尾使用 return 语句返回一个值，其类型必须与函数定义时的返回值类型相同或兼容。在图 1 中定义一个简单的求和函数 Add。

图 1 函数

在图 1 中，函数 Add 的返回值类型为 int，因此在函数体中需要使用 return 语句设置函数的返回值，即“return nPlus + nSummand;”，return 语句的语法比较灵活，还可以将 return 语句部分的结果或表达式使用括号括起来，例如：

return (nPlus + nSummand);

其作用与“return nPlus + nSummand;”语句是相同的。

在编写函数时，如果函数没有返回值，函数的返回类型为 void。例如，编写一个简单的字符串输出函数。

void OutputString(char *pszText)

{

cout << pszText << endl;

}

由于 OutputString 函数的返回值类型是 void，因此函数没有返回值，在函数体中没有 return 语句。如果要在 OutputString 函数中使用 return 语句也是合法的。例如：

void OutputString(char *pszText)

{

cout << pszText << endl;

return;

}

显然，在 OutputString 函数中使用 return 语句是多此一举，但是并不是说在无返回值的函数中就不需要使用 return 语句。如果在函数体中的某个条件成立时或者某个操作完成时需要提前结束函数，可以应用 reutrn 语句。例如，在一个数组中查找一个等于指定数据的元素，输出元素的下标。当在函数中发现了该元素时，函数的任务就完成了，不需要再遍历其他元素。

void FindElement(int nArray[], int nLen, int nData) //查找数组元素

{

for(int i=0; i<nLen; i++) //遍历数组

{

if (nArray[i] == nData) //判断数据

{

cout << "找到数据"<< nData <<"位于" <<i << "下标位置" << endl;

return; //发现了元素，函数返回

}

}

cout << "没有发现数据" << endl;

}

在无返回值的函数中使用 return 语句不能返回一个值，因为函数本身没有返回值，为函数提供返回值是非法的。例如，下面的语句试图为 OutputString 函数提供一个返回值，导致编译错误。

void OutputString(char *pszText)

{

cout << pszText << endl;

return 0; //错误的语句，当前函数不能有返回值

}

在程序中编写一个函数可以有两种方式，第一种方式是在编写函数的原型时就提供函数的定义（函数体），前面介绍的 OutputString、FindElement 函数就属于该种方式。第 2 种方式是先声明函数，即编写函数原型，然后在其他地方编写函数的定义，也就是函数的实现部分。例如，在 main 函数前先声明一个函数 OutputString，然后在 main 函数中调用 OutputString 函数，而 OutputString 函数的定义放置在 main 函数之后，如图 2 所示。

图 2 声明和定义函数

对于第一种方式，如果 OutputString 的定义出现在 main 函数之后，是无法通过编译的。而采用第 2 种方式，通过在 main 函数前添加 OutputString 函数的声明，则允许在 main 函数中调用 OutputString 函数。

在开发应用程序时，通常将函数的声明放置在头文件（.h 文件）中，将函数的定义放置在源文件中（.cpp 文件）。这样，如果需要在其他文件中访问函数，只需要引用该函数声明的头文件就可以了。

有许多人分不清函数的声明和定义。函数的声明只是告诉编译器函数的返回值类型、函数名和参数列表信息，而函数的定义则提供了函数体的实现，在函数的定义部分除了返回值类型、函数名和参数列表，还需要提供函数体。函数的声明可以进行多次，例如，我们可以在不同的文件中声明同一个函数，甚至可以在同一个文件中多次声明同一个函数，尽管没有必要。但是，同一个函数不能构定义多次，除非他们位于不同的命名空间中。

注意：在声明函数时，参数列表部分可以不指定参数的名称，但是必须指定参数的类型。

例如：

void OutputString(const char *); //在声明函数时不指定参数名称

如果声明的函数有多个参数，参数类型之间使用“,”分隔。例如：

int Add(int , int ); //使用“,”分隔不同的参数

而函数定义必须指定参数名称。如果在编写函数时采用第一种方式，即只提供了函数的定义，而没有函数声明，那么此时的函数定义也可以被用作函数的声明。

在编写函数时，函数的返回值类型可以是整型、实型、字符型、指针类型、引用类型、结构体、共用体等，但是不能够是数组类型。例如，下面的函数声明是非法的。

int[5] GetArray(); //非法的函数声明

如果函数确实需要返回一个数组，可以将指针类型作为函数的返回值。例如：

int* GetArray();

在编写一个函数之后，为了使用该函数，在程序中需要调用函数。调用函数的方式非常简单，其通用的格式为：

函数名(实际参数);

以调用 OutputString 函数为例，可以采用如下的形式。

OutputString("mrkj");

其中，OutputString 表示调用的函数名，“"mrkj"”表示传递给 OutputString 函数的实际参数，函数有几个参数，我们就需要提供几个实际参数。如果函数没有参数，只需要写函数名和括号就可以了。例如：

void ExitApp() //定义一个无参函数

{

exit(0); //退出应用程序

}

ExitApp(); //调用无参函数

在调用无参数函数时，注意不要遗忘括号，这是许多初学者经常犯的错误。对于具有返回值的函数，在调用函数时，需要获得函数的返回值，可以定义一个与函数返回值类型相同的变量，在调用函数时将函数的调用结果赋值给该变量。例如，调用 Add 函数。

int Add(int nPlus, int nSummand) //定义 Add 函数

{

return nPlus + nSummand;

}

int nRet = Add(10, 30); //调用 Add 函数，将返回值赋值给 nRet 变量