我面临的挑战是找到执行通常需要使用标头(除了iostream
和iomanip
)或高于基本c++知识的任务的方法。如何仅使用逻辑运算符、基本算术(+、-、*、/、%)、if语句和while循环来检查用户输入的数据类型?
显然,输入变量首先有一个声明的数据类型,但是这个问题掩盖了用户输入错误数据类型的可能性。
我尝试了几种方法,包括if (!(cin >> var1))
技巧,但没有正确工作。这可能吗?
int main() {
int var1, var2;
cin >> var1;
cin >> var2;
cout << var1 << " - " << var2 << " = " << (var1-var2);
return 0;
}
可以在这里输入asdf
和5.25
,那么我如何检查输入不是预期的整数,只使用我前面所说的方法?
我知道这个问题在很多方面是模糊的,主要是因为限制是非常具体的,列出我被允许使用的所有东西将是一件痛苦的事情。我想正如评论中提到的部分问题在于如何首先区分数据类型。
您可以使用简单的操作来做到这一点,尽管这可能有点困难,例如,可以使用以下函数来检查输入是否是十进制数。您可以扩展这个想法并检查浮点数之间是否有句号。
如果需要进一步的帮助,请添加注释。
bool isNumber(char *inp){
int i = 0;
if (inp[0] == '+' || inp[0] == '-') i = 1;
int sign = (inp[0] == '-' ? -1 : 1);
for (; inp[i]; i++){
if (!(inp[i] >= '0' && inp[i] <= '9'))
return false;
}
return true;
}
阅读后的一般检查是这样做的:
stream >> variable;
if (not stream.good()) {
// not successful
}
这可以在任何std::ios
上完成。它适用于标准类型(任何数字类型,char
, string
等),止于空格。如果无法读取variable
,则good
返回false。您可以为自己的类定制它(包括控制good
的返回值):
istream & operator>>(istream & stream, YourClass & c)
{
// Read the data from stream into c
return stream;
}
对于您的特定问题:假设您读取字符42
。没有办法区分把它读作-和int
- a double
因为两者都很好。您必须更精确地指定输入格式。
标准库不是魔术-您只需要解析从用户读取的数据,类似于标准库所做的。
首先读取来自用户的输入:
std::string s;
cin >> s;
(如果你想读取整行,你可以使用getline
代替)
然后你可以继续解析它;我们将尝试区分整数(*[+-]?[0-9]+ *
),实数(*[+-][0-9](.[0-9]*)?([Ee][+-]?[0-9]+)? *
),字符串(*"[^"]" *
)和其他任何("坏")。
enum TokenType {
Integer,
Real,
String,
Bad
};
基本构建块是一个"吃掉"连续数字的例程;这将有助于我们与[0-9]*
和[0-9]+
部分。
void eatdigits(const char *&rp) {
while(*rp>='0' && *rp<='0') rp++;
}
同样,跳过空格的例程也很方便:
void skipws(const char *&rp) {
while(*rp==' ') rp++;
// feel free to skip also tabs and whatever
}
然后我们才能解决真正的问题
TokenType categorize(const char *rp) {
首先,我们要跳过空格
skipws(rp);
那么,我们将尝试匹配最简单的内容:字符串
if(*rp=='"') {
// Skip the string content
while(*rp && *rp!='"') rp++;
// If the string stopped with anything different than " we
// have a parse error
if(!*rp) return Bad;
// Otherwise, skip the trailing whitespace
skipws(rp);
// And check if we got at the end
return *rp?Bad:String;
}
然后,关于数字,请注意实数和整数的定义以相同的方式开始;我们有一个共同的分支:
// If there's a + or -, it's fine, skip it
if(*rp=='+' || *rp=='-') rp++;
const char *before=rp;
// Skip the digits
eatdigits(rp);
// If we didn't manage to find any digit, it's not a valid number
if(rp==start) return Bad;
// If it ends here or after whitespace, it's an integer
if(!*rp) return Integer;
before = rp;
skipws(rp);
if(before!=rp) return *rp?Bad:Integer;
如果我们注意到还有东西,我们处理实数:
// Maybe something after the decimal dot?
if(*rp=='.') {
rp++;
eatdigits(rp);
}
// Exponent
if(*rp=='E' || *rp=='e') {
rp++;
if(*rp=='+' || *rp=='-') rp++;
before=rp;
eatdigits(rp);
if(before==rp) return Bad;
}
skipws(rp);
return *rp?Bad:Real;
}
您可以在读取输入后轻松调用此例程。
(注意这里的字符串只是为了好玩,cin
对双引号分隔的字符串没有任何特殊处理)