如何使 cin 只接受整数输入
how to make cin only take integer inputs
我是编程新手,我们需要创建一个程序,当用户输入错误的输入时不会退出,但到目前为止我只学到了基础知识。当数字高于和低于 100 时我已经解决了但是当用户不小心插入一个非整数时,它将进入错误循环。顺便说一句,这是一个普通的计算器。
#include <iostream>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
cout << "how many numbers will you input?: ";
cin >> n;
while ( n > 100 || n <= 0 )
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for ( int i = 0; i < n; ++i )
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
#include <iostream>
#include <limits>
using namespace std;
int avg(int sum, int n)
{
int average;
average = sum/n;
cout<<"Avg = "<<average;
}
int main()
{
int n;
cout << "how many numbers will you input?: ";
cin >> n;
int w = n;
int num[w];
int sum;
while(n>100||n<=0)
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(int i = 0; i < n; ++i)
{
cout << i + 1 << "Enter number: ";
cin >> num[i];
if(!cin)
{
cout << "Wrong Choice. " << endl;
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
n++;
continue;
}
else
{
sum += num[i];
}
}
cout<<"Sum = "<<sum<<endl;
avg(sum,w);
}
如果std::istream::operator >>
fails, it will set failbit. Therefore, you should check failbit
(for example by calling std::cin.fail()
)先看是否转换成功,再使用转换结果。
如果由于输入错误导致转换失败,那么下一次调用 std::istream::operator >>
将自动失败,因为设置了 failbit
。这就是你陷入无限循环的原因。如果你想在转换失败后再次尝试输入,你将首先必须使用函数 std::cin.clear()
.
清除 failbit
此外,您必须丢弃导致转换失败的错误输入,否则,下次您调用 std::istream::operator >>
时,转换将因同样的原因再次失败。为了清除错误的输入,你可以使用std::cin.ignore()
,像这样:
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
要使用 std::numeric_limits
,您必须 #include <limits>
。
对您的代码执行这些修复后,它应该如下所示:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
bool input_ok;
//repeat until input is valid
do
{
cout << "How many numbers will you input? ";
cin >> n;
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else if ( n > 100 || n <= 0 )
{
cout << "Error: Number should in range of (1 to 100) only!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
for ( int i = 0; i < n; ++i )
{
do
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
该程序具有以下行为:
How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5
如您所见,该程序现在可以正常工作,因为它现在可以处理错误的输入,例如 test
。它拒绝该输入并重新提示用户进行新输入。
但是,此程序的一个问题是它接受 4abc
作为数字 4
的有效输入。相反,拒绝此类输入可能是合适的。解决此问题的一种方法是检查该行的其余部分,而不是简单地丢弃它。
另一个问题是此解决方案包含大量代码重复。除了范围检查之外,两个 do
...while
循环几乎相同。因此,最好将此循环放入一个函数中,可以从您的代码中的多个位置调用它。
但是,我通常不建议您使用 std::istream::operator >>
,因为它的行为并不总是直观的。例如,如上所述:
- 它并不总是读取整行输入,因此您必须明确丢弃该行的剩余部分。
- 它接受
4abc
作为数字 4
的有效输入。
根据我的经验,如果您想对整数输入进行正确的输入验证,通常最好编写自己的函数来使用 std::getline
and converts it with std::stoi
读取整行输入。如果输入无效,则该函数应自动重新提示用户。
在下面的示例中,我调用此函数 get_int_from_user
。
如果你想额外保证输入在一定范围内,那么你可以在无限循环中调用函数get_int_from_user
,一旦确定输入有效就跳出那个循环.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
int get_int_from_user( const std::string& prompt );
int main()
{
int nums[100];
int n;
double sum;
//repeat loop forever, until input is good
for (;;) //equivalent to while(true)
{
n = get_int_from_user( "How many numbers will you input? " );
if ( 1 <= n && n <= 100 )
//input is good
break;
std::cout << "Error! Number should in range of (1 to 100) only.\n";
}
//read one number per loop iteration
for( int i = 0; i < n; i++ )
{
std::ostringstream prompt;
prompt << "Enter number #" << i + 1 << ": ";
nums[i] = get_int_from_user( prompt.str() );
sum += nums[i];
}
std::cout << "Average: " << sum / n << '\n';
}
int get_int_from_user( const std::string& prompt )
{
std::string line;
std::size_t pos;
int i;
//repeat forever, until an explicit return statement or an
//exception is thrown
for (;;) //equivalent to while(true)
{
//prompt user for input
std::cout << prompt;
//attempt to read one line of input from user
if ( !std::getline( std::cin, line ) )
{
throw std::runtime_error( "unexpected input error!\n" );
}
//attempt to convert string to integer
try
{
i = std::stoi( line, &pos );
}
catch ( std::invalid_argument& )
{
std::cout << "Unable to convert input to number, try again!\n";
continue;
}
catch ( std::out_of_range& )
{
std::cout << "Out of range error, try again!\n";
continue;
}
//The remainder of the line is only allowed to contain
//whitespace characters. The presence of any other
//characters should cause the entire input to get rejected.
//That way, input such as "6sdfj23jlj" will get rejected,
//but input with trailing whitespace will still be accepted
//(just like input with leading whitespace is accepted by
//the function std::stoi).
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
std::cout << "Invalid character found, try again!\n";
//we cannot use "continue" here, because that would
//continue to the next iteration of the innermost
//loop, but we want to continue to the next iteration
//of the outer loop
goto continue_outer_loop;
}
}
//input is valid
return i;
continue_outer_loop:
continue;
}
}
该程序具有以下行为:
How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5
如您所见,它现在可以正确拒绝输入 4abc
。
我相信使用函数 get_int_from_user
会使 main
中的代码更清晰。
请注意,上面的代码使用了一个 goto
语句。在大多数情况下,您应该避免使用 goto
、but for breaking out of nested loops, it is considered appropriate.
我是编程新手,我们需要创建一个程序,当用户输入错误的输入时不会退出,但到目前为止我只学到了基础知识。当数字高于和低于 100 时我已经解决了但是当用户不小心插入一个非整数时,它将进入错误循环。顺便说一句,这是一个普通的计算器。
#include <iostream>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
cout << "how many numbers will you input?: ";
cin >> n;
while ( n > 100 || n <= 0 )
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for ( int i = 0; i < n; ++i )
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
#include <iostream>
#include <limits>
using namespace std;
int avg(int sum, int n)
{
int average;
average = sum/n;
cout<<"Avg = "<<average;
}
int main()
{
int n;
cout << "how many numbers will you input?: ";
cin >> n;
int w = n;
int num[w];
int sum;
while(n>100||n<=0)
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(int i = 0; i < n; ++i)
{
cout << i + 1 << "Enter number: ";
cin >> num[i];
if(!cin)
{
cout << "Wrong Choice. " << endl;
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
n++;
continue;
}
else
{
sum += num[i];
}
}
cout<<"Sum = "<<sum<<endl;
avg(sum,w);
}
如果std::istream::operator >>
fails, it will set failbit. Therefore, you should check failbit
(for example by calling std::cin.fail()
)先看是否转换成功,再使用转换结果。
如果由于输入错误导致转换失败,那么下一次调用 std::istream::operator >>
将自动失败,因为设置了 failbit
。这就是你陷入无限循环的原因。如果你想在转换失败后再次尝试输入,你将首先必须使用函数 std::cin.clear()
.
failbit
此外,您必须丢弃导致转换失败的错误输入,否则,下次您调用 std::istream::operator >>
时,转换将因同样的原因再次失败。为了清除错误的输入,你可以使用std::cin.ignore()
,像这样:
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
要使用 std::numeric_limits
,您必须 #include <limits>
。
对您的代码执行这些修复后,它应该如下所示:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
bool input_ok;
//repeat until input is valid
do
{
cout << "How many numbers will you input? ";
cin >> n;
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else if ( n > 100 || n <= 0 )
{
cout << "Error: Number should in range of (1 to 100) only!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
for ( int i = 0; i < n; ++i )
{
do
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
该程序具有以下行为:
How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5
如您所见,该程序现在可以正常工作,因为它现在可以处理错误的输入,例如 test
。它拒绝该输入并重新提示用户进行新输入。
但是,此程序的一个问题是它接受 4abc
作为数字 4
的有效输入。相反,拒绝此类输入可能是合适的。解决此问题的一种方法是检查该行的其余部分,而不是简单地丢弃它。
另一个问题是此解决方案包含大量代码重复。除了范围检查之外,两个 do
...while
循环几乎相同。因此,最好将此循环放入一个函数中,可以从您的代码中的多个位置调用它。
但是,我通常不建议您使用 std::istream::operator >>
,因为它的行为并不总是直观的。例如,如上所述:
- 它并不总是读取整行输入,因此您必须明确丢弃该行的剩余部分。
- 它接受
4abc
作为数字4
的有效输入。
根据我的经验,如果您想对整数输入进行正确的输入验证,通常最好编写自己的函数来使用 std::getline
and converts it with std::stoi
读取整行输入。如果输入无效,则该函数应自动重新提示用户。
在下面的示例中,我调用此函数 get_int_from_user
。
如果你想额外保证输入在一定范围内,那么你可以在无限循环中调用函数get_int_from_user
,一旦确定输入有效就跳出那个循环.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
int get_int_from_user( const std::string& prompt );
int main()
{
int nums[100];
int n;
double sum;
//repeat loop forever, until input is good
for (;;) //equivalent to while(true)
{
n = get_int_from_user( "How many numbers will you input? " );
if ( 1 <= n && n <= 100 )
//input is good
break;
std::cout << "Error! Number should in range of (1 to 100) only.\n";
}
//read one number per loop iteration
for( int i = 0; i < n; i++ )
{
std::ostringstream prompt;
prompt << "Enter number #" << i + 1 << ": ";
nums[i] = get_int_from_user( prompt.str() );
sum += nums[i];
}
std::cout << "Average: " << sum / n << '\n';
}
int get_int_from_user( const std::string& prompt )
{
std::string line;
std::size_t pos;
int i;
//repeat forever, until an explicit return statement or an
//exception is thrown
for (;;) //equivalent to while(true)
{
//prompt user for input
std::cout << prompt;
//attempt to read one line of input from user
if ( !std::getline( std::cin, line ) )
{
throw std::runtime_error( "unexpected input error!\n" );
}
//attempt to convert string to integer
try
{
i = std::stoi( line, &pos );
}
catch ( std::invalid_argument& )
{
std::cout << "Unable to convert input to number, try again!\n";
continue;
}
catch ( std::out_of_range& )
{
std::cout << "Out of range error, try again!\n";
continue;
}
//The remainder of the line is only allowed to contain
//whitespace characters. The presence of any other
//characters should cause the entire input to get rejected.
//That way, input such as "6sdfj23jlj" will get rejected,
//but input with trailing whitespace will still be accepted
//(just like input with leading whitespace is accepted by
//the function std::stoi).
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
std::cout << "Invalid character found, try again!\n";
//we cannot use "continue" here, because that would
//continue to the next iteration of the innermost
//loop, but we want to continue to the next iteration
//of the outer loop
goto continue_outer_loop;
}
}
//input is valid
return i;
continue_outer_loop:
continue;
}
}
该程序具有以下行为:
How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5
如您所见,它现在可以正确拒绝输入 4abc
。
我相信使用函数 get_int_from_user
会使 main
中的代码更清晰。
请注意,上面的代码使用了一个 goto
语句。在大多数情况下,您应该避免使用 goto
、but for breaking out of nested loops, it is considered appropriate.