C++输入流假设验证及特定输入检测技术咨询
C++输入流验证常见问题解答
问题1:为何input1(值为"1 2 3-")的bad()位未被设置?如何检测此类输入?
bad()标志仅在流底层出现严重完整性错误时才会被触发(比如缓冲区损坏、I/O设备故障),而输入格式错误属于逻辑错误,只会触发fail()标志。
对于"1 2 3-"的场景:流会先成功读取"3",剩下的'-'无法转换为double,此时仅会触发fail(),而非bad()。要检测这类非法尾随字符,可在每次成功读取数值后,检查当前流位置的下一个字符:
if (buffer >> test) { // 读取成功后,跳过当前空白并检查后续字符 buffer >> ws; if (buffer.peek() != EOF && !isspace(buffer.peek())) { // 存在非法非空白字符,判定输入无效 cout << "非法尾随字符" << endl; buffer.setstate(ios::failbit); // 手动设置失败标志,退出循环 break; } }
问题2:流中的空白符作用是什么?是否通常会被忽略?比如input2("1 2-3")的情况。
默认情况下,>>运算符会自动跳过数值前的所有前导空白,但读取数值时,只要匹配到合法的数值格式就会停止,不会强制要求后续字符必须是空白。
对于"1 2-3":读取完1后,流跳过空格,接着读取"2"作为合法double值,剩下的"-3"会在下次循环中被成功读取,最终得到1、2、-3三个值。如果要求数值必须严格用空白分隔,需在每次读取后检查后续字符是否为空白或EOF,否则判定输入非法。
问题3:当流转换失败时,double或int类型变量是否总会被设为0?
不是的,这个行为分C++标准版本:
- C++11之前:转换失败时,数值变量的值是未定义行为,可能保留原值,也可能是随机值。
- C++11及之后:转换失败时,
int会被设为0,double会被设为0.0。
不要依赖这个行为,建议在读取前手动初始化变量,或在转换失败时显式重置变量值。
问题4:能否仅使用流功能检测并禁止input1(最关键)、input2、input7、input5这类输入?
可以,但需要配合额外的检查逻辑,单纯依赖>>运算符无法实现:
- input1("1 2 3-"):每次读取数值后,检查流的下一个字符是否为空白或EOF,若存在非空白非EOF的字符(比如单独的
'-'),判定非法。 - input2("1 2-3"):读取完一个数值后,确保后续字符是空白或EOF,若紧跟非空白字符(比如
2后面的'-'),判定非法。 - input7(".1 - 2 3"):当流触发
fail()时,检查当前缓冲区的字符是否为单独的'-'(无后续数字),若是则判定非法。 - input5(".1 2 3 "):多个空白属于合法分隔符,流会自动处理;如果必须限制空白数量,需手动读取空白字符并计数判断。
附带验证代码(新增检查逻辑)
#include<iostream> #include <sstream> #include <cctype> // 用于isspace using namespace std; int main(){ string input0 = "1 2 3"; // 正常读取,EOF,test保留正确值 -> 符合预期 string input1 = "1 2 3-"; // 读取失败,EOF,test被设为0 -> 为何bad未被设置?如何检测? string input2 = "1 2-3"; // 读取完成,EOF,test得到正确值 -> 不符合预期的行为 string input3 = "1 2 -3 "; // 正常读取,EOF,正确值 -> 符合预期 string input4 = ".1 2---3 "; // 读取失败,缓冲区位置4,test设为0 -> 符合预期 string input5 = ".1 2 3 "; // 正常读取,EOF,正确值 -> 符合预期 string input6 = ".1 2 --3 "; // 读取失败,缓冲区位置4,test设为0 -> 符合预期 string input7 = ".1 - 2 3"; // 读取失败,缓冲区位置2,test设为0 -> 符合预期 istringstream buffer(input7); double test = 0; while (buffer >> test){ cout << "In loop" << endl; cout << "Value of test: " << test << endl; cout << "Buffer position: " << buffer.tellg() << endl; // 新增检查:读取后是否有非法尾随字符 buffer >> ws; // 跳过当前空白 if (buffer.peek() != EOF && !isspace(buffer.peek())) { cout << "发现非法尾随字符" << endl; buffer.setstate(ios::failbit); // 手动设置失败标志,退出循环 break; } } cout << "Out of loop" << endl; cout << test << endl; if (buffer.good()) // 无错误标志 cout << "Good" << endl; if (buffer.bad()) // I/O读写错误(流完整性丢失) cout << "Bad" << endl; if (buffer.fail()) // 逻辑错误(转换失败) cout << "Failed" << endl; if (buffer.eof()) // 到达输入EOF cout << "EOF" << endl; // .clear() 可清除流标志 }
内容的提问来源于stack exchange,提问作者user18348324
相关产品推荐
相关产品推荐

