跳到主要内容
注意

请注意,本文尚未完成!您可以通过编辑此文档页面来提供帮助。

函数

在本课程中,您将学习如何通过可重用性来让程序执行操作。

动机

使用函数的一个优点是减少代码中的重复。请参阅下面的示例,有函数和无函数的版本。此时您无需理解带有函数的示例的表示法——我们将在本课程后面解释它。

#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';
}

在上面的示例中,我们创建了一个数字数组并对其进行修改,每次都显示其内容。两个版本之间的区别在于,第一个版本包含我们多次复制粘贴的代码片段。在第二个更正确的版本中,我们**一次性教导程序如何显示数字数组**,然后在需要时重复使用它。

函数还有许多其他用途,我们将在本课中展示其中一些。但现在我们需要回到基础知识。

简介

定义

函数是我们可以多次重用的独立代码片段。

从我们学习之初,我们就在程序中包含了一个特殊的函数,即 main

int main() {
// program code
}

运行程序的计算机找到 main 函数,然后执行它,逐行执行其中的每个语句。

创建函数

我们将从最简单的功能开始,逐渐转向越来越高级的功能。

无参数

最简单函数的方案

如上所示,在定义我们自己的函数时,我们必须注意其名称和函数体,并遵循语法。在 void 关键字之后,我们写入函数名称,然后放置空括号(我们将在本课程后面讨论),然后不带分号地放置代码块,我们称之为函数体

命名

函数命名遵循与变量命名相同的规则。

现在我们已经定义了函数。这意味着我们可以在任何时候调用它。我们这样做:

调用 print 函数
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)

返回语句

我们可以通过使用以下语句,让程序提前从函数返回:

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 类型不能用于创建变量

❌ 非法使用
void variable;

变量本质上存储一个值,如果它是 void 类型,这是不可能的。

用法

让我们实现上面图中所示的函数。它将计算从 fromto(包括)范围内所有数字的总和。

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;
}

确保顺序始终匹配很麻烦,有时甚至不可能。为了修复上面示例中的错误,我们必须使用所谓的函数声明

到目前为止,在创建函数时,我们使用了函数定义,它除了声明之外,还包含其完整的实现(函数体)。声明函数看起来像定义它,但不提供其函数体。我们还需要注意在声明后加一个分号。

🔵 定义
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);

规则是,要使用函数,必须事先**声明**。定义必须出现,但它在使用的之前还是之后并不重要。这里有两个例子:

#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;
}
单一定义规则(ODR

定义在代码中**只能出现一次**(可以有多个声明)。

总结

  • 我们使用函数将代码**分组**成**命名**块。
  • 函数可以被**调用**(执行)来运行它们内部的代码。
  • 函数可以**返回**一个值。
  • 函数可以**接受**参数。
  • 函数可以独立地**声明**和**定义**。
注意

请注意,本文尚未完成!您可以通过编辑此文档页面来提供帮助。

函数

在本课程中,您将学习如何通过可重用性来让程序执行操作。

动机

使用函数的一个优点是减少代码中的重复。请参阅下面的示例,有函数和无函数的版本。此时您无需理解带有函数的示例的表示法——我们将在本课程后面解释它。

#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';
}

在上面的示例中,我们创建了一个数字数组并对其进行修改,每次都显示其内容。两个版本之间的区别在于,第一个版本包含我们多次复制粘贴的代码片段。在第二个更正确的版本中,我们**一次性教导程序如何显示数字数组**,然后在需要时重复使用它。

函数还有许多其他用途,我们将在本课中展示其中一些。但现在我们需要回到基础知识。

简介

定义

函数是我们可以多次重用的独立代码片段。

从我们学习之初,我们就在程序中包含了一个特殊的函数,即 main

int main() {
// program code
}

运行程序的计算机找到 main 函数,然后执行它,逐行执行其中的每个语句。

创建函数

我们将从最简单的功能开始,逐渐转向越来越高级的功能。

无参数

最简单函数的方案

如上所示,在定义我们自己的函数时,我们必须注意其名称和函数体,并遵循语法。在 void 关键字之后,我们写入函数名称,然后放置空括号(我们将在本课程后面讨论),然后不带分号地放置代码块,我们称之为函数体

命名

函数命名遵循与变量命名相同的规则。

现在我们已经定义了函数。这意味着我们可以在任何时候调用它。我们这样做:

调用 print 函数
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)

返回语句

我们可以通过使用以下语句,让程序提前从函数返回:

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 类型不能用于创建变量

❌ 非法使用
void variable;

变量本质上存储一个值,如果它是 void 类型,这是不可能的。

用法

让我们实现上面图中所示的函数。它将计算从 fromto(包括)范围内所有数字的总和。

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;
}

确保顺序始终匹配很麻烦,有时甚至不可能。为了修复上面示例中的错误,我们必须使用所谓的函数声明

到目前为止,在创建函数时,我们使用了函数定义,它除了声明之外,还包含其完整的实现(函数体)。声明函数看起来像定义它,但不提供其函数体。我们还需要注意在声明后加一个分号。

🔵 定义
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);

规则是,要使用函数,必须事先**声明**。定义必须出现,但它在使用的之前还是之后并不重要。这里有两个例子:

#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;
}
单一定义规则(ODR

定义在代码中**只能出现一次**(可以有多个声明)。

总结

  • 我们使用函数将代码**分组**成**命名**块。
  • 函数可以被**调用**(执行)来运行它们内部的代码。
  • 函数可以**返回**一个值。
  • 函数可以**接受**参数。
  • 函数可以独立地**声明**和**定义**。