请注意,本文尚未完成!您可以通过编辑此文档页面来提供帮助。
函数
在本课程中,您将学习如何通过可重用性来让程序执行操作。
动机
使用函数的一个优点是减少代码中的重复。请参阅下面的示例,有函数和无函数的版本。此时您无需理解带有函数的示例的表示法——我们将在本课程后面解释它。
- ⚠ 无函数
- 🟢 有函数
#include <iostream>
#include <vector>
int main()
{
std::vector<int> numbers = {1, 4, 13, 15};
for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';
numbers.push_back(13);
for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';
numbers.push_front(3);
for (int i : numbers) {
std::cout << i << ' ';
}
std::cout << '\n';
}
#include <iostream>
#include <vector>
void print(std::vector<int> vec)
{
for (int i : vec) {
std::cout << i << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> numbers = {1, 4, 13, 15};
print(numbers);
numbers.push_back(13);
print(numbers);
numbers.push_front(3);
print(numbers);
}
在上面的示例中,我们创建了一个数字数组并对其进行修改,每次都显示其内容。两个版本之间的区别在于,第一个版本包含我们多次复制粘贴的代码片段。在第二个更正确的版本中,我们**一次性教导程序如何显示数字数组**,然后在需要时重复使用它。
函数还有许多其他用途,我们将在本课中展示其中一些。但现在我们需要回到基础知识。
简介
函数是我们可以多次重用的独立代码片段。
从我们学习之初,我们就在程序中包含了一个特殊的函数,即 main
。
int main() {
// program code
}
运行程序的计算机找到 main
函数,然后执行它,逐行执行其中的每个语句。
创建函数
我们将从最简单的功能开始,逐渐转向越来越高级的功能。
无参数

如上所示,在定义我们自己的函数时,我们必须注意其名称和函数体,并遵循语法。在 void
关键字之后,我们写入函数名称,然后放置空括号(我们将在本课程后面讨论),然后不带分号地放置代码块,我们称之为函数体。
函数命名遵循与变量命名相同的规则。
现在我们已经定义了函数。这意味着我们可以在任何时候调用它。我们这样做:
print();
请注意,函数调用后我们放置了分号,因为这也是语句的结束。
让我们编写一个示例函数,它显示 10 个偶数并使用它几次。
#include <iostream>
// Function definition
void print_10_even_numbers()
{
for (int i = 0; i < 10; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}
int main()
{
// Calling the function
print_10_even_numbers();
print_10_even_numbers();
print_10_even_numbers();
}
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18
0 2 4 6 8 10 12 14 16 18
带参数

函数的行为可以取决于参数。如果你想让函数显示任意数量的偶数,我们可以在函数中创建一个参数来控制它。参数是函数内部的变量,我们在括号内创建它。
#include <iostream>
void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}
int main()
{
print_even_numbers(10);
print_even_numbers(5);
print_even_numbers(3);
}
以上表示
print_even_numbers(10);
意味着在调用时,函数内部的 how_many
参数将被赋值为 10
。我们可以向函数传递任意数量的参数。用逗号分隔它们。
#include <iostream>
void print_bigger_number(int a, int b)
{
if (a > b)
std::cout << a << '\n';
else
std::cout << b << '\n';
}
int main() {
print_bigger_number(3, 5);
print_bigger_number(5, 3);
print_bigger_number(3, 10);
}
请注意,我们用逗号分隔函数参数,**每次都指定其类型**。初学者常犯的错误是在后续参数中省略类型。
- ❌ 错误
- ✔ 正确
void print_bigger_number(int a, b)
void print_bigger_number(int a, int b)
返回语句
我们可以通过使用以下语句,让程序提前从函数返回:
return;
遇到它时,程序会停止执行函数中的后续指令,并返回到调用它的位置。让我们回顾一下我们之前创建的函数——print_even_numbers
void print_even_numbers(int how_many)
{
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}
如果我们将负数传递给 how_many
会发生什么?
print_even_numbers(-10);
执行具有此类参数值的函数毫无意义,因此我们可以在一开始就检测到这一点并使用 return
void print_even_numbers(int how_many)
{
if (how_many <= 0)
return;
for (int i = 0; i < how_many; i++)
std::cout << (i * 2) << ' ';
std::cout << '\n';
}
现在,如果我们将小于或等于零的值传递给函数参数,函数将在开始时终止。
返回值

函数执行后可以产生一个结果。如果我们用现实生活中的类比来理解这一点会更容易。父亲派他的孩子去商店买 10 个鸡蛋。当孩子回来时,他会想知道孩子是否成功买到了他要求的那么多。同样地,我们在代码中执行一些函数时,我们想知道结果,即返回值。
返回值类型
需要指定返回值的类型。我们将其指定在函数名之前,例如:
int sum(int from, int to)
void print(int number)
请注意,我们引入了一种新类型:void
。如果我们在返回类型的位置写入它,这意味着该函数不返回任何值,即我们不需要知道它的结果。请注意,我们在本课前面的部分中使用 void
正是出于这个原因。
void
类型不能用于创建变量
void variable;
变量本质上存储一个值,如果它是 void
类型,这是不可能的。
用法
让我们实现上面图中所示的函数。它将计算从 from
到 to
(包括)范围内所有数字的总和。
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
我们可以使用返回值,例如,将其写入变量中
int s = sum(10, 100);
...或在表达式中使用(例如,作为函数参数)
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
要求
一个返回值的函数(任何非 `void` 类型)在执行结束时**必须**返回某个值。
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
// ❌ No return statement!
}
main
函数是一个例外,尽管它返回 int
类型,但在省略 return
时会自动返回 0
。
int main() {
// No "return" statement
}
我们将在将来详细介绍 main
函数。
声明和定义
为了使用上面的 sum
函数,我们需要确保它在调用它的位置之前,例如
- ❌ 错误
- ✔ 正确
#include <iostream>
int main()
{
// Error: used before the definition
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
#include <iostream>
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}
确保顺序始终匹配很麻烦,有时甚至不可能。为了修复上面示例中的错误,我们必须使用所谓的函数声明。
到目前为止,在创建函数时,我们使用了函数定义,它除了声明之外,还包含其完整的实现(函数体)。声明函数看起来像定义它,但不提供其函数体。我们还需要注意在声明后加一个分号。
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
int sum(int from, int to);
规则是,要使用函数,必须事先**声明**。定义必须出现,但它在使用的之前还是之后并不重要。这里有两个例子:
- ✔ 确定
- ✔ OK(定义在前)
- ✔ OK(多次声明)
#include <iostream>
// 🟣 Declaration
int sum(int from, int to);
int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}
// 🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
#include <iostream>
// 🟣 Declaration
int sum(int from, int to);
// 🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}
#include <iostream>
// 🟣 Declarations
int sum(int from, int to);
int sum(int from, int to); // OK, multiple declarations are acceptable
int sum(int from, int to); // but unnecessary 🤔
int main()
{
std::cout << "Sum of the numbers in range [10; 100] equals: " << sum(10, 100);
}
// 🔵 Definition
int sum(int from, int to)
{
int result = 0;
for (int i = from; i <= to; i++)
result += i;
return result;
}
定义在代码中**只能出现一次**(可以有多个声明)。
总结
- 我们使用函数将代码**分组**成**命名**块。
- 函数可以被**调用**(执行)来运行它们内部的代码。
- 函数可以**返回**一个值。
- 函数可以**接受**参数。
- 函数可以独立地**声明**和**定义**。