【问题标题】:Check if scores are between 0 and 100 using pointers使用指针检查分数是否在 0 到 100 之间
【发布时间】:2021-11-15 10:21:32
【问题描述】:

我需要检查每个分数值,它们需要介于 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 循环内的while 循环,由有效标志控制,以便在输入值时再次提示用户输入相同的索引槽超出范围。
  • 附注:*(&lt;pointer&gt; + &lt;index&gt;) 可以而且应该写成&lt;pointer&gt;[i]。因此,这同样适用于您的 lPtrarray 指针,例如:lPtr[i]array[scan]array[i]array[minIndex] 等。

标签: c++ sorting pointers display


【解决方案1】:

在下面的代码中

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;
    }
}

但是,此代码的一个问题是它只执行范围检查,而根本不检查输入是否有效。特别是,它不会检查流提取运算符&gt;&gt; 是否成功地将用户的输入转换为数字。这可以通过调用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 &lt;limits&gt;

但是,这段代码仍然不是很完美。如果输入12sdlhfh 等输入,那么它将接受12 作为有效输入,但下一次流提取将失败,因为sdlhfh 不是有效数字,并且会打印错误消息。可以通过在每次提取流后丢弃该行的其余部分来防止此错误消息,但在这种情况下,这可能不是理想的解决方案,因为您可能希望拒绝输入,例如 12sdlhfh

为了能够拒绝此类输入,您不应使用流提取运算符&gt;&gt;,因为它会在遇到非数字时立即停止读取。相反,您应该始终使用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 &lt;string&gt;#include &lt;cctype&gt;

上面的代码使用了一个goto 语句。通常,如果可能,您不应使用gotobut for exiting nested loops, it is acceptable

另外请注意,如果您使用上述代码,那么它将与在循环外使用cin &gt;&gt; lInput; 不兼容。混合std::getlinestd::istream::operator&gt;&gt; 通常不会起作用,因为std::istream::operator&gt;&gt; 会将换行符留在缓冲区中,所以下一次调用std::getline 可能只会检索一个空行。

【讨论】:

    【解决方案2】:

    试试这个 -

    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;
    }
    
    

    【讨论】:

    • 这解决了您的问题吗?
    • 请点赞并接受我的回答
    • @ATSpiro:如果答案解决了您的问题,那么您可能需要考虑接受答案。有关更多信息,请参阅此官方帮助页面:What should I do when someone answers my question?
    • 在您的代码中,您只检查用户输入的值是否在 0 到 100 之间,而不是检查是否输入了有效值。在我看来,这没有多大意义。您可能需要考虑在进行范围检查之前检查cin.fail(),并在任一检查失败时重新提示用户。
    • 做。或者不要。没有尝试。也没有解释提问者的问题是什么,或者您的建议如何解决该问题。这使得这是一个纯代码的答案,从长远来看,这些并不是特别有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 2010-12-07
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    相关资源
    最近更新 更多