在 C++ 中检查变量类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/332852/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Check variable type in C++
提问by Fatmarik
So I am currently learning C++ and decided to make a program that tests my skills I have learned so far. Now in my code I want to check if the value that the user enters is a double, if it is not a double I will put a if loop and ask them to reenter it. The problem I have is how do I go about checking what type of variable the user enters, ex- if a user enters a char or string, I can output an error message. Here is my code:
所以我目前正在学习 C++ 并决定制作一个程序来测试我迄今为止所学的技能。现在在我的代码中,我想检查用户输入的值是否是双精度值,如果不是双精度值,我将放置一个 if 循环并要求他们重新输入它。我遇到的问题是如何检查用户输入的变量类型,例如,如果用户输入字符或字符串,我可以输出错误消息。这是我的代码:
//cubes a user entered number
#include <iostream>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
double user;
cin >> user; //user entering the number
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
Edit: I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
编辑:我不得不说我刚刚开始,对你的代码一无所知,但我会查看你的链接。顺便说一句,我还没有学会如何使用模板,我正在学习处理数据,只在我的 C++ Primer Plus 5th edition 中的第 3 章。
回答by Johannes Schaub - litb
Safe C++ Way
安全的 C++ 方式
You can define a function for this using std::istringstream
:
您可以使用以下方法为此定义一个函数std::istringstream
:
#include <sstream>
bool is_double(std::string const& str) {
std::istringstream ss(str);
// always keep the scope of variables as close as possible. we see
// 'd' only within the following block.
{
double d;
ss >> d;
}
/* eat up trailing whitespace if there was a double read, and ensure
* there is no character left. the eof bit is set in the case that
* `std::ws` tried to read beyond the stream. */
return (ss && (ss >> std::ws).eof());
}
To assist you in figuring out what it does (some points are simplified):
为了帮助您弄清楚它的作用(简化了一些要点):
- Creation of a input-stringstream initialized with the string given
- Reading a double value out of it using
operator>>
. This means skipping whitespace and trying to read a double. - If no double could be read, as in
abc
the stream sets the fail-bit. Note that cases like3abc
will succeed and will notset the fail-bit. - If the fail-bit is set,
ss
evaluates to a zero value, which means false. - If an double was read, we skip trailing whitespace. If we then are at the end of the stream (note that
eof()
will return trueif we tried to read past the end.std::ws
does exactly that),eof
will return true. Note this check makes sure that3abc
will not pass our check. - If both cases, right and left of the
&&
evaluate to true, we return true to the caller, signaling the given string is a double.
- 创建使用给定字符串初始化的输入字符串流
- 使用
operator>>
. 这意味着跳过空格并尝试读取双精度值。 - 如果无法读取双精度值,则在
abc
流中设置失败位。请注意,像这样的情况3abc
会成功并且不会设置失败位。 - 如果设置了失败位,则
ss
计算为零值,这意味着false。 - 如果读取了双精度值,我们将跳过尾随空格。然后如果我们是在流结束(注意,
eof()
将返回真,如果我们试图读取过去的结束。std::ws
正是这么做的),eof
将返回true。请注意,此检查确保3abc
不会通过我们的检查。 - 如果两种情况,左右两边的
&&
求值为true,我们将 true 返回给调用者,表示给定的字符串是双精度值。
Similar, you check for int
and other types. If you know how to work with templates, you know how to generalize this for other types as well. Incidentally, this is exactly what boost::lexical_cast
provides to you. Check it out: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.
类似地,您检查int
和其他类型。如果您知道如何使用模板,那么您也知道如何将其推广到其他类型。顺便说一句,这正是boost::lexical_cast
为您提供的。检查一下:http: //www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm。
C Way One
C方式一
This way has advantages (being fast) but also major disadvantages (can't generalized using a template, need to work with raw pointers):
这种方式有优点(速度快)但也有主要缺点(不能使用模板进行概括,需要使用原始指针):
#include <cstdlib>
#include <cctype>
bool is_double(std::string const& s) {
char * endptr;
std::strtod(s.c_str(), &endptr);
if(endptr != s.c_str()) // skip trailing whitespace
while(std::isspace(*endptr)) endptr++;
return (endptr != s.c_str() && *endptr == '#include <cstdio>
bool is_double(std::string const& s) {
int n;
double d;
return (std::sscanf(s.c_str(), "%lf %n", &d, &n) >= 1 &&
n == static_cast<int>(s.size()));
}
');
}
strtod
will set endptr
to the last character processed. Which is in our case the terminating null character. If no conversion was performed, endptr is set to the value of the string given to strtod
.
strtod
将设置endptr
为处理的最后一个字符。在我们的例子中是终止空字符。如果未执行任何转换,则 endptr 设置为提供给 的字符串值strtod
。
C Way Two
C 方式二
One might thing that std::sscanf
does the trick. But it's easy to oversee something. Here is the correct way to do it:
一件事可以解决std::sscanf
问题。但监督某事很容易。这是正确的方法:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
double cube(double n);
int main()
{
while(true)
{
cout << "Enter the number you want to cube: ";
string user;
cin >> user;
try
{
// The following instruction tries to parse a double from the 'user' string.
// If the parsing fails, it raises an exception of type bad_lexical_cast.
// If an exception is raised within a try{ } block, the execution proceeds
// with one of the following catch() blocks
double d = lexical_cast <double> (user);
cout << "The cube of " << d << " is " << cube(d) << "." << endl;
break;
}
catch(bad_lexical_cast &e)
{
// This code is executed if the lexical_cast raised an exception; We
// put an error message and continue with the loop
cout << "The inserted string was not a valid double!" << endl;
}
}
return 0;
}
double cube (double n)
{
return n*n*n;
}
std::sscanf
will return the items converted. Although the Standard specifies that %n
is not included in that count, several sources contradict each other. It's the best to compare >=
to get it right (see the manpage of sscanf
). n
will be set to the amount of the processed characters. It is compared to the size of the string. The space between the two format specifiers accounts for optional trailing whitespace.
std::sscanf
将返回转换后的项目。尽管该标准规定%n
不包括在该计数中,但有几个来源相互矛盾。最好进行比较>=
以使其正确(请参阅 的联机帮助页sscanf
)。n
将设置为已处理字符的数量。它与字符串的大小进行比较。两个格式说明符之间的空格是可选的尾随空格。
Conclusion
结论
If you are a beginner, read into std::stringstream
and do it the C++ way. Best not mess with pointers until you feel good with the general concept of C++.
如果您是初学者,请阅读std::stringstream
并按照 C++ 方式进行操作。最好不要乱用指针,直到您对 C++ 的一般概念感到满意为止。
回答by Federico A. Ramponi
There is no suitable way to check if a string reallycontains a double within the standard library. You probably want to use Boost. The following solution is inspired by recipe 3.3 in C++ Cookbook:
在标准库中没有合适的方法来检查字符串是否真的包含双精度值。您可能想使用Boost。以下解决方案的灵感来自C++ Cookbook 中的配方 3.3 :
//cubes a user entered number
#include <iostream>
#include <cstdio>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
string user;
cin >> user; //user entering the number
// Convert the number to a double.
double value;
if(sscanf(user.c_str(), "%lf", &value) != 1)
{
cout << "Bad! " << user << " isn't a number!" << endl;
return 1;
}
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
回答by strager
sscanfcan do what you want; it returns the number of arguments properly processed. This should get you started:
sscanf可以为所欲为;它返回正确处理的参数数量。这应该让你开始:
bool is_double(const char* strIn, double& dblOut) {
char* lastConvert = NULL;
double d = strtod(strIn, &lastConvert);
if(lastConvert == strIn){
return false;
} else {
dblOut = d;
return true;
}
}
Other methods posted in other answers have their advantages and disadvantages. This one has issues with trailing characters and isn't "C++"-y.
其他答案中发布的其他方法各有优缺点。这个有尾随字符问题,不是“C++”-y。
回答by Fatmarik
I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
我不得不说我刚刚开始,对你的代码一无所知,但我会查看你的链接。顺便说一句,我还没有学会如何使用模板,我正在学习处理数据,只在我的 C++ Primer Plus 5th edition 中的第 3 章。