我正在创建一个简单的CLI计算器工具作为练习。我需要确保n1和n2是数字才能使函数工作;因此,我希望在遇到预定的非数字值时使程序退出。
任何人都可以给我一些指导吗?
此外,如果有人能提供关于我如何做得更好的一般提示,我将不胜感激。我只是在学习c ++。
谢谢!
完整的代码包含在下面。
#include <iostream>
#include <new>
using namespace std;
double factorial(double n) { return(n <= 1) ? 1 : n * factorial(n - 1); }
double add(double n1, double n2) { return(n1 + n2); }
double subtract(double n1, double n2) { return(n1 - n2); }
double multiply(double n1, double n2) { return(n1 * n2); }
double divide(double n1, double n2) { return(n1 / n2); }
int modulo(int n1, int n2) { return(n1 % n2); }
double power(double n1, double n2) {
double n = n1;
for(int i = 1 ; i < n2 ; i++) {
n *= n1;
}
return(n);
}
void print_problem(double n1, double n2, char operatr) {
cout<<n1<<flush;
if(operatr != '!') {
cout<<" "<<operatr<<" "<<n2<<flush;
} else {
cout<<operatr<<flush;
}
cout<<" = "<<flush;
}
int main(void) {
double* n1, * n2, * result = NULL;
char* operatr = NULL;
n1 = new (nothrow) double;
n2 = new (nothrow) double;
result = new (nothrow) double;
operatr = new (nothrow) char;
if(n1 == NULL || n2 == NULL || operatr == NULL || result == NULL) {
cerr<<"\nMemory allocation failure.\n"<<endl;
} else {
cout<<"\nTo use this calculator, type an expression\n\tex: 3*7 or 7! or \nThen press the return key.\nAvailable operations: (+, -, *, /, %, ^, !)\n"<<endl;
do {
cout<<"calculator>> "<<flush;
cin>>*n1;
cin>>*operatr;
if(*operatr == '!') {
print_problem(*n1, *n2, *operatr);
cout<<factorial(*n1)<<endl;
} else {
cin>>*n2;
switch(*operatr) {
case '+':
print_problem(*n1, *n2, *operatr);
cout<<add(*n1, *n2)<<endl;
break;
case '-':
print_problem(*n1, *n2, *operatr);
cout<<subtract(*n1, *n2)<<endl;
break;
case '*':
print_problem(*n1, *n2, *operatr);
cout<<multiply(*n1, *n2)<<endl;
break;
case '/':
if(*n2 > 0) {
print_problem(*n1, *n2, *operatr);
cout<<divide(*n1, *n2)<<endl;
} else {
print_problem(*n1, *n2, *operatr);
cout<<" cannot be computed."<<endl;
}
break;
case '%':
if(*n1 >= 0 && *n2 >= 1) {
print_problem(*n1, *n2, *operatr);
cout<<modulo(*n1, *n2)<<endl;
} else {
print_problem(*n1, *n2, *operatr);
cout<<" cannot be computed."<<endl;
}
break;
case '^':
print_problem(*n1, *n2, *operatr);
cout<<power(*n1, *n2)<<endl;
break;
default:
cout<<"Invalid Operator"<<endl;
}
}
} while(true);
delete n1, n2, operatr, result;
}
return(0);
}
答案 0 :(得分:3)
您要做的是读取输入行或字符串,然后尝试将该行转换为数字形式。 Boost将其包含在lexical_cast
中,但您根本不需要它。我已经回答了两次与您类似的问题here和here。阅读这些帖子以了解正在发生的事情。
这是最终结果:
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
使用我在这些帖子中概述的方式:
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
// conversion failed
}
}
这使用例外。通过捕获bad_cast
例外:
template <typename T>
bool lexical_cast(const std::string& s, T& t)
{
try
{
t = lexical_cast<T>(s);
return true;
}
catch (const std::bad_cast& e)
{
return false;
}
}
int main(void)
{
std::string s;
std::cin >> s;
int i;
if (!lexical_cast(s, i))
{
std::cout << "Bad cast." << std::endl;
}
}
这有助于使Boost的lexical_cast
无法投掷,但如果您自己实施,则没有理由浪费时间抛出并捕获异常。按照彼此的方式实现它们,其中抛出版本使用无抛出版本:
// doesn't throw, only returns true or false indicating success
template <typename T>
const bool lexical_cast(const std::string& s, T& result)
{
std::stringstream ss(s);
return (ss >> result).fail() || !(ss >> std::ws).eof();
}
// throws
template <typename T>
T lexical_cast(const std::string& s)
{
T result;
if (!lexical_cast(s, result))
{
throw std::bad_cast("bad lexical cast");
}
return result;
}
您的代码中存在更多问题:您new
了所有内容!这有什么理由吗?考虑一下代码的任何部分是否会引发异常:现在你跳出main并泄漏所有内容。如果你堆栈分配你的变量,它们将被保证破坏。
答案 1 :(得分:1)
无需提升或编写自己的模板或强迫自己使用异常与错误代码。 cin
只做你想要的一切。
您可以测试if ( cin )
或if ( ! cin )
以确定成功或失败。一次失败(例如,数字输入中的字母)将阻止cin
接受任何更多输入。然后调用cin.clear()
清除错误并继续获取输入,从导致错误的任何文本开始。此外,您可以请求流引发转化错误的例外:cin.exceptions( ios::failbit )
。
所以,你可以这样做:
for (;;) try {
double lhs, rhs;
char oper;
cin.exceptions( 0 ); // handle errors with "if ( ! cin )"
cin >> lhs >> oper; // attempt to do "the normal thing"
if ( ! cin ) { // something went wrong, cin is in error mode
string command; // did user enter command instead of problem?
cin.clear(); // tell cin it's again OK to return data,
cin >> command; // get the command,
if ( command == "quit" ) break; // handle it.
else cin.setstate( ios::failbit ); // if command was invalid,
// tell cin to return to error mode
}
cin.exceptions( ios::failbit ); // now errors jump directly to "catch"
// note that enabling exceptions works retroactively
// if cin was in error mode, the above line jumps immediately to catch
if ( oper != '!' ) cin >> rhs;
// do stuff
} catch ( ios::failure & ) {
cin.clear();
cin.ignore( INT_MAX, '\n' ); // skip the rest of the line and continue
}
这意味着使用iostream进行错误处理。您可以选择使用例外或手动测试,或两者兼而有之。
答案 2 :(得分:0)
您可以使用输入流对象本身来执行简单验证:
What is the best way to do input validation in C++ with cin?
另一种有趣的方法可能是使用Boost.Spirit库构建解析器,尽管它是一种高级技术,大量利用C ++元编程功能。如果您想尝试一下,请查看quick start示例
答案 3 :(得分:-2)
可能很多C ++人都会因此而讨厌我,但即使C ++拥有所有这些新的闪亮字符串,我也尽量保持C ++字符串的感觉干净,在这种情况下,最简单,也是最干净的事情是坚持好'C:
if (sscanf(input, "%d", &integer) != 1) {
// failure to read number
}
// happily continue and process