这里有两个问题,一个与如何获得最小有关,另一个与如何获得正确的输入有关。
对于第一个问题,让我提出一个递归的方法:
// this is trivial
double smallest(double x, double y)
{ return (x<y)? x: y; }
// the smalles of three is the smallest between the smallest of two and the third
double smallest(double x, double y, double z)
{ return smallest(smallest(x,y),z); }
对于第二个问题,每个变量都有相同的问题,所以让我们为它创建一个函数:
#include <iostream>
#include <limits>
#include <string>
double read(std::istream& s, std::ostream& o, const std::string& message)
{
for(;;) //stay here until kiked out
{
double d=0.; //just a safe value - no particular meaning
o << message << std::endl; // prompt the request
bool good(s >> d); //read a double and keep the state
if(!good) s.clear(); //if we failed to read, clean the stream state
//in any case, discard everything unread until the return.
s.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if(good) return d; //if reading succeeded, return.
//overwise loop back
}
}
这是基于这样一个事实std::cin
,即设置为“坏”的状态是无法在给定变量中读取输入。
我们只是阅读,如果失败,则一次又一次地重做。但是首先我们必须清除状态,这样才能解锁输入。独立 og 好一个坏的阅读,然后我们必须丢弃可以在该行中输入的所有“额外”(想想123asdf
:我们成功阅读123
,但我们必须丢弃abc
)阅读成功我们只是返回它,否则我们循环一遍又一遍,直到我们得到它。
程序本身,此时将简化为:
int main()
{
double x = read(std::cin, std::cout, "Enter first value");
double y = read(std::cin, std::cout, "Enter second value");
double z = read(std::cin, std::cout, "Enter third value");
std::cout << "the smallest numer is: " << smallest(x,y,z) << std::endl;
return 0;
}
可以这样运行:
Enter first value
7
Enter second value
5.2yyyy
Enter third value
sf3
Enter third value
455
the smallest numer is: 5.2
更高级的技术可以将函数转换为操纵器类,如下所示:
class read_value
{
public:
read_value(double& d, const std::string& prompt_, std::ostream& out_ = std::cout)
:z(d), prompt(prompt_), outstream(out_)
{}
friend std::istream& operator>>(std::istream& s, const read_value& a)
{
for(;;)
{
a.outstream << a.prompt << std::endl; // prompt the request
bool good(s >> a.z); //read a double and keep the state
if(!good) s.clear(); //if we failed to read, cleanr the stream state
//in any case, discard everything unread until the return.
s.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if(good) return s; //if reading succeeded, return.
//overwise loop back
}
}
private:
double& z;
std::string prompt;
std::ostream& outstream;
};
让程序更惯用的形式:
int main()
{
double x,y,z;
std::cin >>
read_value(x,"Enter first value") >>
read_value(y,"Enter second value") >>
read_value(z,"Enter third value");
std::cout << "the smallest numer is: " << smallest(x,y,z) << std::endl;
return 0;
}
另一点可能是用户可以通过从不输入一个好的序列来永远循环。
我们可以修复最大尝试限制,在 for 循环中引入一个计数器,如果循环终止而不返回,则将输入设置为“失败”:
friend std::istream& operator>>(std::istream& s, const read_value& a)
{
for(int i=0; i<10; ++i)
{
... //same as before
}
return s; //s will be returned in failed state
}
然后检查主程序:
int main()
{
double x,y,z;
std::cin >>
read_value(x,"Enter first value") >>
read_value(y,"Enter second value") >>
read_value(z,"Enter third value");
if(!std::cin)
{
std::cout << "bad input." << std::endl;
return -1; //report as "program failed"
}
std::cout << "the smallest numer is: " << smallest(x,y,z) << std::endl;
return 0; //succeeded
}
.