我需要检查每个分数值,它们需要在0到100之间,如果不是,则需要提示用户重新输入有效值。
我代码:
#include <iostream>
using namespace std;
void sort(int*, int);
void displaySort(int*, int);
int main()
{
int lInput;
cout << "Enter the size of your list: ";
cin >> lInput;
int* lPtr = new int[lInput];
for (int i = 0; i < lInput; i++)
{
cout << "Enter a score: ";
cin >> *(lPtr + i);
if (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Invalid input, enter again: ";
}
}
cout << endl;
sort(lPtr, lInput);
displaySort(lPtr, lInput);
cout << endl;
delete[] lPtr;
system("PAUSE");
return 0;
}
void sort(int* array, int size)
{
int scan, minIndex, minValue;
for (int scan = 0; scan < (size - 1); scan++)
{
minIndex = scan;
minValue = *(array + scan);
for (int i = scan + 1; i < size; i++)
{
if (*(array + i) < minValue)
{
minValue = *(array + i);
minIndex = i;
}
}
*(array + minIndex) = *(array + scan);
*(array + scan) = minValue;
}
}
void displaySort(int* array, int size)
{
cout << "List of scores in ascending order:" << endl;
for (int i = 0; i < size; i++)
{
cout << *(array + i) << " ";
}
}
我现在的方式,它仍然接受无效的数字。我希望它是这样的,如果输入一个无效的数字,它不会接受这个数字,而是要求一个有效的数字。
以下代码
for (int i = 0; i < lInput; i++)
{
cout << "Enter a score: ";
cin >> *(lPtr + i);
if (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Invalid input, enter again: ";
}
}
的问题是,对于无效的输入,您将输出包含错误消息的文本,并提示用户输入新数字,但实际上您不会读取任何新输入。相反,您只需跳转到下一个循环迭代,这实际上意味着您正在接受错误的输入。
解决这个问题的一种方法是创建一个无限循环,直到用户输入有效的输入。当发生这种情况时,您可以使用break
语句跳出该循环。
for (int i = 0; i < lInput; i++)
{
for (;;) //infinite loop, equivalent to while(1)
{
cout << "Enter a score: ";
cin >> *(lPtr + i);
if (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Input must be between 0 and 100, try again!n";
continue;
}
break;
}
}
然而,这段代码的一个问题是它只执行范围检查,但根本不检查输入是否有效。特别是,它不检查流提取操作符>>
是否成功地将用户的输入转换为数字。这可以通过调用cin.fail()
来检查。
最好在范围检查之前执行这个额外的检查,如下所示:
for (int i = 0; i < lInput; i++)
{
//this loop will continue until the input is valid
for (;;) //infinite loop, equivalent to while(1)
{
cout << "Enter a score: ";
cin >> *(lPtr + i);
//check if stream error occurred
if ( cin.fail() )
{
//check if error is recoverable
if ( cin.bad() )
{
throw std::runtime_error( "unrecoverable I/O error" );
}
//print error message
cout << "Input must be a number, try again!n";
//discard bad input (remainder of line)
cin.ignore( std::numeric_limits<std::streamsize>::max(), 'n' );
//clear stream status flags
cin.clear();
continue;
}
if (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Input must be between 0 and 100, try again!n";
continue;
}
//input is valid, so break out of the infinite loop
break;
}
}
注意,上面的代码需要您额外添加#include <limits>
。
然而,这段代码仍然不是很完美。如果输入像12sdlhfh
这样的输入,那么它将接受12
作为有效的输入,但是下一个流提取将失败,因为sdlhfh
不是一个有效的数字,并且它将打印一条错误消息。此错误消息可以通过在每次流提取后丢弃该行的剩余部分来防止,但在这种情况下,这可能不是理想的解决方案,因为您可能想要拒绝输入,如12sdlhfh
。
为了能够拒绝这样的输入,您不应该使用流提取操作符>>
,因为一旦遇到非数字,它将停止读取。相反,您应该始终使用std::getline
一次读取一行,并使用std::stoi
和一些额外的代码验证整行,以验证数字之后没有出现非空白字符。
for (int i = 0; i < lInput; i++)
{
//this loop will continue until the input is valid
for (;;) //infinite loop, equivalent to while(1)
{
std::string line;
std::size_t pos;
cout << "Enter a score: ";
getline( cin, line );
//check if stream error occurred
if ( cin.fail() )
{
//check if error is recoverable
if ( cin.bad() )
{
throw std::runtime_error( "unrecoverable I/O error" );
}
//print error message
cout << "Input error, try again!n";
//clear stream status flags
cin.clear();
continue;
}
//attempt to perform the actual conversion
try
{
*(lPtr + i) = std::stoi( line, &pos );
}
catch ( std::invalid_argument )
{
cout << "Unable to convert input to number, try again!n";
continue;
}
catch ( std::out_of_range )
{
cout << "Range error, try again!n";
continue;
}
//verify that rest of line does not contain any non-whitespace characters
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
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;
}
}
if (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Input must be between 0 and 100, try again!n";
continue;
}
//input is valid, so break out of the infinite loop
break;
continue_outer_loop:
continue;
}
}
注意,上面的代码还需要:#include <string>
和#include <cctype>
。
goto
语句。通常,如果可能,您不应该使用goto
,但对于退出嵌套循环,它是可以接受的。
还请注意,如果使用上面的代码,那么它将与在循环外使用cin >> lInput;
不兼容。混合std::getline
和std::istream::operator>>
通常不会工作,因为std::istream::operator>>
将把换行符留在缓冲区中,所以下次调用std::getline
可能只会检索到空行。
试试这个-
int main()
{
int lInput;
cout << "Enter the size of your list: ";
cin >> lInput;
int* lPtr = new int[lInput];
for (int i = 0; i < lInput; i++)
{
cout << "Enter a score: ";
cin >> *(lPtr + i);
while (*(lPtr + i) < 0 || *(lPtr + i) > 100)
{
cout << "Invalid input, enter again: ";
cin >> *(lPtr + i);
}
}
cout << endl;
sort(lPtr, lInput);
displaySort(lPtr, lInput);
cout << endl;
delete[] lPtr;
system("PAUSE");
return 0;
}