【问题标题】:My function skips a loop parameter in c++我的函数在 C++ 中跳过了一个循环参数
【发布时间】:2019-08-04 13:56:30
【问题描述】:

我的 GetMark() 函数,它应该检查正确的范围,然后返回值,如果对给定数组正确,则在我添加参数之前,当参数超出接受范围时,它会陷入无限循环SearchMark() 函数它工作正常并且只循环直到用户最终在给定范围(0 - 100)内输入一个值,但现在在给出第一个超出范围的值之后,无论输入什么,它都会循环,我会感谢有什么建议。完整代码:

int GetMark(int ModuleIndex) //user input function
{
    bool help;
    if (ModuleIndex < 0 || ModuleIndex >100)
    {
        help = false;
        while (help != true)
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "hey, that's a invalid value, try again!" << endl;
            GetMark(ModuleIndex);
            if ((ModuleIndex > 0) &&( ModuleIndex < 101))
            {
                help = true;
            }
        }
    }

    return ModuleIndex;
}

int SearchMark(int A[], int a) //search grades array for numbers of specific grades
{
    int i = 0;
    int ii = 0;

    while (i < 12)
    {
        if (A[i] == a)
            ii++;
        i++;
    }
    cout << "Mark " << a << " was found: " << ii << " times" << endl;
    return 0;
}



int main()
{
    int marks[12]; 
    int i = 0;
    int sum = 0;
    int grades[12];

    while (i < 12)
    {
        cout << "enter mark (0 - 100): " << endl;
        cin >> marks[i];
        GetMark(marks[i]);
        sum = sum + marks[i];
        if (marks[i] > 69)
        {
            grades[i] = 1;
        }
        else if (marks[i] > 59 && marks[i] < 70)
        {
            grades[i] = 2;
        }
        else if (marks[i] > 49 && marks[i] < 60)
        {
            grades[i] = 22;
        }
        else if (marks[i] > 39 && marks[i < 50])
        {
            grades[i] = 3;
        }
        else if (marks[i] < 35)
        {
            grades[i] = 4;
        }
        i++;
    }
    sum = sum / 12;
    cout << "your average is: " << sum  << endl;




    if (sum > 69)
    {
        cout << "You passed with 1st!" << endl;
    }
    else if ((sum > 59) && (sum < 70))
    {
        cout << "You passed with 2i!" << endl;
    }
    else if ((sum > 49) && (sum < 60))
    {
        cout << "You passed with 2ii!" << endl;
    }
    else if ((sum > 39) && (sum < 50))
    {
        cout << "You passed with 3rd!" << endl;
    }
    else if (sum < 40)
    {
        cout << "Your average is too low! You failed." << endl;
    }


    i = 0;
    while (i < 12)
    {
        if (marks[i] < 35)
        {
            cout << "Referred in module " << i + 1 << " mark too low." << endl;
        }
        i++;
    }

    SearchMark(grades, 1);
    SearchMark(grades, 2);
    SearchMark(grades, 22);
    SearchMark(grades, 3);
    SearchMark(grades, 4);

    return 0;
}`

【问题讨论】:

  • 除了使用递归而不是简单迭代的问题之外,我注意到 ModuleIndex 的值在调用 GetMark 后永远不会改变。因此,如果它超出范围,您只需使用相同的超出范围值一次又一次地无限递归。
  • @L.ScottJohnson 它确实发生了变化,如果超出范围,它每次都会提示用户输入新的输入值
  • 它提示,是的。但它不会读取用户对提示的响应。
  • 代码可以通过彻底改变来优化。为什么这样,例如 `cin >> 标记[i]; GetMark(marks[i])`?
  • 如果被调用,GetMark() 不会读取任何值,并使用传递给它的值递归调用自身。这导致无限递归。递归调用GetMark() 之后的代码永远不会到达。

标签: c++ function loops infinite-loop


【解决方案1】:

该函数的功能过于复杂。只需在值错误时循环,并提示输入新值:

int GetMark(int ModuleIndex) {
    while (ModuleIndex < 0 || ModuleIndex > 100) {
        std::cout << "Invalid value.\n"
        std::cin >> ModuleIndex;
    }
    return ModuleIndex;
}

递归在理论分析中非常方便,但在实践中它几乎总是一个错误。

【讨论】:

  • 谢谢,添加了 cin.ignore() 和 cin.clear() 来增强错误处理,这非常有效:)
  • @Sami -- 是的,我省略了花里胡哨以使逻辑清晰。
【解决方案2】:

您需要允许用户在 GetMarks 中指定新的标记 [i] / ModuleIndex 值。清除 cin 后,从 cin 中读取一个新值。您还需要返回该值,以便可以使用该值而不是原始超出范围的值来更新 main 的标记 [i]。

【讨论】:

  • +1。但是函数确实返回值。问题是(可怕的)递归调用返回的值没有被使用,所以更新的值被丢弃了。
  • 那么你有什么建议?因为我真的想不出一个更好的方法来声明这个函数没有递归......
  • 我建议迭代。 while(ModuleIndex 100) { 读取新的 ModuleIndex }
【解决方案3】:

基本上你需要做的是从这个方法中移除递归,只依赖while循环。而不是调用函数,您需要使用失败的输入再次提示输入,然后再次测试该值以退出循环。

int GetMark(int ModuleIndex) //user input function
{
    bool help;
    if (ModuleIndex < 0 || ModuleIndex >100)
    {
        help = false;
        while (help != true)
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "hey, that's a invalid value, try again!" << endl;
            cout << "enter mark (0 - 100): " << endl;
            cin >> ModuleIndex;
            if ((ModuleIndex > 0) &&( ModuleIndex < 101))
            {
                help = true;
            }
    }
}
    return ModuleIndex;
}

【讨论】:

  • 这仍然读取负值和字符,所以它真的没有任何好处
【解决方案4】:

显然在你getMark 中,在while 循环内,你正在递归调用getMark,并使用相同的无效ModuleIndex 值。所以你需要在递归之前从标准输入中获取它。例如:

int GetMark(int ModuleIndex){
    bool help;
    if (ModuleIndex < 0 || ModuleIndex > 100){
        help = false;
        while (help != true){
                cout << "enter new ModuleIndex: \n";
                cin >> ModuleIndex;
                GetMark(ModuleIndex);
                // ...
        }

        return ModuleIndex;
    }

你的代码不可读,另外你可以使用std::vector类。

我建议测试这段代码:

int GetMarkIndex(const std::vector<double>& vMarks, const double Search) {
    auto beg{ vMarks.begin() }, end{ vMarks.end() };
    while (beg != end && *beg != Search)
        ++beg;
    return beg != end ? beg - vMarks.begin() : -1;
}

int main() {

    std::vector<double> marks(5);
    int value;

    auto i{ 0U };
    auto sz{ marks.size() };
    while (i != sz) {
        std::cout << "Enter marks 1-->100" << std::endl;
        if (cin >> value && value > 0 && value < 101) {
            marks[i] = value;
            ++i;
        }
        else
            std::cout << "Invalid input!" << std::endl;
    }

    for (auto e : marks)
        cout << e << ", ";
    std::cout << std::endl;

    double Search = 15;
    auto index{GetMarkIndex(marks, Search)};

    (index != -1) ? (std::cout << Search << " Found at index: " << index) : (std::cout << Search << " Not found!" << std::endl);


    std::cout << std::endl;
}

【讨论】:

    【解决方案5】:

    你定义GetMark的方式和你使用它的方式的结合是有缺陷的。

    无论您在GetMark 中做什么,main 中输入的值都不会改变。

    GetMark 更改为:

    int GetMark()
    {
       std::cout << "enter mark (0 - 100): " << std::endl;
       int mark;
       while ( std::cin >> mark )
       {
          if (  mark >= 0 && mark <= 100)
          {
             return mark;
          }
    
          std::cout << "Invalid value " << mark << std::endl;
          std::cout << "enter mark (0 - 100): " << std::endl;
       }
    
       // Unable to read.
       // Throw exception, or exit with an error message.
    }
    

    并更改其用法。而不是

    cout << "enter mark (0 - 100): " << endl;
    cin >> marks[i];
    GetMark(marks[i]);
    

    使用

    marks[i] = GetMark();
    

    GetMark 的工作版本:

    int GetMark()
    {
       std::cout << "enter mark (0 - 100): " << std::endl;
    
       std::string line;
       while ( getline(std::cin, line) )
       {
          std::istringstream str(line);
          int mark;
          if ( str >> mark )
          {
             if (  mark >= 0 && mark <= 100)
             {
                return mark;
             }
          }
          std::cout << "Invalid input: " << line << std::endl;
          std::cout << "enter mark (0 - 100): " << std::endl;
       }
    
       // Unable to read.
       // Throw exception, or exit with an error message.
       return 0;
    }
    

    Live Demo.

    【讨论】:

    • 谢谢,但我应该如何让函数此时不接受字符串?
    • @Sami,您必须使用cin.clear()cin.ignore() 的策略,但是您必须稍微更新while 循环。
    • 它不起作用...当我实现 cin.clear() 和 cin.ignore() 字符串仍然通过时,1 个循环的负整数也是如此,只有在那之后,函数才会提示不同的输入,并记录最近的正确输入但进入下一个循环
    • 是的,我遇到的问题是代码将错误的输入作为答案,所以对我来说,它被放入数组中,而不是被删除并替换为有效值,这使得我的数组的点,它正在计算一个平均值等等,因为无效的输入搞砸了所有的计算,所以毫无意义
    • @Sami,使用更新的GetMark 函数,您永远不会在marks 中获得无效值。
    猜你喜欢
    • 2013-10-02
    • 2012-05-23
    • 2013-11-12
    • 2010-12-12
    • 1970-01-01
    • 2015-10-11
    • 2021-03-07
    相关资源
    最近更新 更多