在C++中,函数可以返回一个值,这个值被称为函数的返回值。函数的返回值可以是任何合法的数据类型,包括基本数据类型(如整数、浮点数、字符等)和用户自定义的数据类型(如结构体、类对象等)。
考虑以下程序:
#include <iostream>
int main()
{
// get a value from the user
std::cout << "Enter an integer: ";
int num{};
std::cin >> num;
// print the value doubled
std::cout << num << " doubled is: " << num * 2 << '\n';
return 0;
}
这个程序由两个概念部分组成:首先,我们从用户那里获取一个值。然后告诉用户这个值的两倍是多少。
虽然这个程序很简单,我们不需要将它分成多个函数,但如果我们想要呢?从用户那里获取一个整数值是一个明确定义的任务,我们希望我们的程序执行这个任务,因此可以编写一个函数来实现。
那么让我们编写一个程序来执行此操作:
// This program doesn't work
#include <iostream>
void getValueFromUser()
{
std::cout << "Enter an integer: ";
int input{};
std::cin >> input;
}
int main()
{
getValueFromUser(); // Ask user for input
int num{}; // How do we get the value from getValueFromUser() and use it to initialize this variable?
std::cout << num << " doubled is: " << num * 2 << '\n';
return 0;
}
这个程序是一个不错的尝试,但还不够完善。
当调用 getValueFromUser
函数时,用户会如预期地被要求输入一个整数。但是当 getValueFromUser
结束并控制返回到 main
时,用户输入的值丢失了。变量 num
永远不会被初始化为用户输入的值,因此程序总是打印出答案 0。
我们需要的是一种方式,让 getValueFromUser
将用户输入的值返回给 main
,以便 main
可以使用该数据。
返回值
当您编写用户定义的函数时,您需要确定您的函数是否会将值返回给调用者。要将值返回给调用者,需要做两件事。
首先,您的函数必须指示将返回什么类型的值。这是通过设置函数的返回类型来完成的,返回类型是在函数名称之前定义的类型。在上面的示例中,函数getValueFromUser
的返回类型为void
(意味着不会向调用者返回任何值),而函数main
的返回类型为(意味着将向调用者返回int
类型的值)。int
请注意,这并不能确定返回什么具体值——它只确定将返回什么类型的值。
其次,在返回值的函数内部,我们使用return 语句来指示返回给调用者的特定值。函数返回的具体值称为返回值。当执行return语句时,函数立即退出,并且返回值从函数复制回调用者。这个过程称为按值返回。
让我们看一个返回整数值的简单函数,以及调用它的示例程序:
#include <iostream>
// int is the return type
// A return type of int means the function will return some integer value to the caller (the specific value is not specified here)
int returnFive()
{
// the return statement indicates the specific value that will be returned
return 5; // return the specific value 5 back to the caller
}
int main()
{
std::cout << returnFive() << '\n'; // prints 5
std::cout << returnFive() + 2 << '\n'; // prints 7
returnFive(); // okay: the value 5 is returned, but is ignored since main() doesn't do anything with it
return 0;
}
输出:
5
7
执行从 的顶部开始main
。在第一个语句中,对函数调用returnFive
进行求值,从而导致函数returnFive
被调用。函数将 backreturnFive
的具体值返回5
给调用者,然后通过 打印到控制台std::cout
。
在第二次函数调用中,对函数调用returnFive
进行求值,这导致函数returnFive
被再次调用。函数returnFive
将返回值返回5
给调用者。计算表达式5 + 2
以产生结果7
,然后通过 打印到控制台std::cout
。
returnFive
在第三个语句中,再次调用函数,导致值5
返回给调用者。但是,函数main
对返回值不执行任何操作,因此不会发生进一步的情况(返回值被忽略)。
注意:除非调用者通过将返回值发送到控制台,否则不会打印返回值std::cout
。在上面的最后一种情况下,返回值没有发送到std::cout
,因此没有打印任何内容。
当被调用函数返回一个值时,调用者可以决定在表达式或语句中使用该值(例如,将其分配给变量,或将其发送到std::cout
)或忽略它(不执行任何其他操作)。
修复本课开头介绍的程序
#include <iostream>
int getValueFromUser() // this function now returns an integer value
{
std::cout << "Enter an integer: ";
int input{};
std::cin >> input;
return input; // return the value the user entered back to the caller
}
int main()
{
int num { getValueFromUser() }; // initialize num with the return value of getValueFromUser()
std::cout << num << " doubled is: " << num * 2 << '\n';
return 0;
}
当该程序执行时,中的第一条语句main
将创建一个int
名为 的变量num
。当程序进入初始化时num
,它会看到有一个函数调用getValueFromUser()
,因此它将执行该函数。函数getValueFromUser
,要求用户输入一个值,然后将该值返回给调用者 ( main
)。该返回值用作变量 的初始化值num
。
回顾 main()
现在,您具备了理解主函数(main
)实际工作原理的概念工具。当程序被执行时,操作系统会调用 main
函数。然后,执行会跳转到 main
的顶部。main
中的语句按顺序执行。最后,main
返回一个整数值(通常是0),您的程序终止。main
返回的值有时称为状态码(有时也称为退出码,或极少数情况下称为返回码),因为它用于指示程序是否成功运行。
根据定义,状态码为0意味着程序成功执行。
如果程序正常运行,您的main
函数返回值应该为0
。
没有返回值的返回值函数将产生未定义的行为
有返回值的函数称为返回值函数。如果返回类型不是 ,则函数是有返回值的void
。
返回值函数必须返回该类型的值(使用 return 语句),否则将导致未定义的行为。
下面是一个产生未定义行为的函数示例:
#include <iostream>
int getValueFromUserUB() // this function returns an integer value
{
std::cout << "Enter an integer: ";
int input{};
std::cin >> input;
// note: no return statement
}
int main()
{
int num { getValueFromUserUB() }; // initialize num with the return value of getValueFromUserUB()
std::cout << num << " doubled is: " << num * 2 << '\n';
return 0;
}
编译器生成警告,因为getValueFromUserUB
被定义为返回int
但未提供 return 语句。运行这样的程序会产生未定义的行为,因为getValueFromUserUB()
是一个不返回值的返回值函数。
在大多数情况下,编译器会检测您是否忘记返回值。但是,在某些复杂的情况下,编译器可能无法正确确定您的函数是否在所有情况下都返回值,因此您不应依赖于此。
确保具有非 void 返回类型的函数在所有情况下都返回一个值。无法从返回值函数返回值将导致未定义的行为。
如果没有提供 return 语句,函数 main 将隐式返回 0
返回值函数必须通过 return 语句返回值的规则的唯一例外是main()
函数。如果没有提供 return 语句,该函数main()
将隐式返回0
。也就是说,最好的做法是从 main 显式返回一个值,既可以显示您的意图,也可以与其他函数保持一致(如果未指定返回值,它将表现出未定义的行为)。
函数只能返回单个值
返回值函数每次调用时只能将单个值返回给调用者。
请注意,return 语句中提供的值不必是文字 – 它可以是任何有效表达式的结果,包括变量,甚至是对另一个返回值的函数的调用。在getValueFromUser()
上面的示例中,我们返回一个变量input
,其中保存用户输入的数字。
有多种方法可以解决函数只能返回单个值的限制,我们将在以后的课程中介绍这一点。
函数重用
现在我们可以举例说明函数重用的一个很好的例子。考虑以下程序:
#include <iostream>
int main()
{
int x{};
std::cout << "Enter an integer: ";
std::cin >> x;
int y{};
std::cout << "Enter an integer: ";
std::cin >> y;
std::cout << x << " + " << y << " = " << x + y << '\n';
return 0;
}
虽然这个程序可以工作,但它有点多余。事实上,这个程序违反了良好编程的核心原则之一:不要重复自己(通常缩写为DRY)。
为什么重复的代码不好?如果我们想将文本“Enter an integer:”更改为其他内容,我们必须在两个位置更新它。如果我们想初始化 10 个变量而不是 2 个怎么办?这将是大量冗余代码(使我们的程序变得更长且更难理解),并且有很大的空间出现拼写错误。
让我们更新这个程序以使用我们getValueFromUser
上面开发的函数:
#include <iostream>
int getValueFromUser()
{
std::cout << "Enter an integer: ";
int input{};
std::cin >> input;
return input;
}
int main()
{
int x{ getValueFromUser() }; // first call to getValueFromUser
int y{ getValueFromUser() }; // second call to getValueFromUser
std::cout << x << " + " << y << " = " << x + y << '\n';
return 0;
}
输出:
Enter an integer: 5
Enter an integer: 7
5 + 7 = 12
在这个程序中,我们调用了getValueFromUser
两次,一次初始化变量x
,一次初始化变量y
。这使我们不必重复代码来获取用户输入,并减少出错的可能性。
这是模块化编程的本质:能够编写一个函数,测试它,确保它工作,然后知道我们可以根据需要多次重用它。
如果您需要多次执行某件事,请考虑如何修改代码以删除尽可能多的冗余。变量可以用来存储需要多次使用的计算结果(这样我们就不必重复计算)。函数可用于定义我们想要多次执行的语句序列。循环(我们将在后面的章节中介绍)可用于多次执行一条语句。
原创文章,作者:jkhxw,如若转载,请注明出处:https://www.jkhxw.com/cpp-return-values/