【问题标题】:While loop causing an infinite loop but I can't figure out why虽然循环导致无限循环,但我不知道为什么
【发布时间】:2014-09-13 04:33:02
【问题描述】:

我正在做一个 C++ 作业,旨在教我们更多关于对象和 OOP 的知识。下面是我的代码。它的要点是,用户输入一些输入,程序会计算元音或辅音(由用户选择)的数量、输入的字符总数和行尾总数。

我遇到了三个问题:

  1. 我注释掉的代码部分在留下时会导致无限循环。它会导致countChars 函数的输出被无限打印,以及询问用户是否愿意输入的输出更多输入。
  2. countChars 函数未正确计算 EOL。我认为这很可能是由于我对 EOL 不熟悉。我如何在我的条件语句中表示它?如果我想说“如果它的值为'0'则增加”,我说if (variable == 0)。如果某事是 EOL,我如何告诉 C++ 递增?
  3. countChars 输出计数的随机负值。我确实注意到值会根据我输入的内容而变化(EOL 除外),但我不确定为什么会得到负值。除了使用 unsigned int 和初始化值之外,我不确定如何解决它。

另外,我预见人们会告诉我使用 getline 函数,但我们有非常具体的使用说明来使用 cin.get(毕竟我们应该学习一点东西)所以请避免使用getline.

头文件:

/*
+----------------------------------------+
|               CountChars               |
+----------------------------------------+
| -countVorC : Integer                   |
| -countEOL : Integer                    |
| -totalChars : Integer                  |
| -vowelCount : Boolean                  |
+----------------------------------------+
| <<constructor>>                        |
|   CountChars()                         |
| +inputChars() :                        |
| +vowelCheck(characterToCheck : Boolean)|
| +setVowelCount(VorC : Character)       |
| +getCountVorC() : Integer              |
| +getCountEOL() : Integer               |
| +getTotalChars() : Integer             |
| +getVowelCount() : Boolean             |
+----------------------------------------+
*/

using namespace std;

#ifndef COUNTCHARS_H
#define COUNTCHARS_H

class CountChars
{
private:
    unsigned int countVorC;
    unsigned int countEOL;
    unsigned int totalChars;
    bool vowelCount;
public:
    CountChars();
    void inputChars();
    bool vowelCheck(char characterToCheck);
    void setVowelCount(char VorC);
    int getCountVorC();
    int getCountEOL();
    int getTotalChars();
    bool getVowelCount();
};

#endif

实现文件:

#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <cstdio>
#include "CountChars.h"

using namespace std;

CountChars::CountChars()
{
    unsigned int countVorC = 0;
    unsigned int countEOL = 0;
    unsigned int totalChars = 0;
    bool vowelCount = false;
}

void CountChars::inputChars()
{
    int letter;

    while ((letter = cin.get()) != EOF && letter != EOF){
        if (vowelCount == true && (vowelCheck(letter) == true)) {
            countVorC++;
        }
        else if (vowelCount == false && (vowelCheck(letter) == false)) {
            countVorC++;
        }

        if (isalpha(letter)) {
            totalChars++;
        }

        if (letter == '\n') {
            countEOL++;
        }
    }
}

bool CountChars::vowelCheck(char characterToCheck)
{
    characterToCheck = toupper(characterToCheck);

    if ((isalpha(characterToCheck)) &&
       (characterToCheck == 'A' || characterToCheck == 'E' ||
       characterToCheck == 'I' || characterToCheck == 'O' ||
       characterToCheck == 'U')) {
       return true;
    }
    else {
        return false;
    }
}

void CountChars::setVowelCount(char VorC)
{
    VorC = toupper(VorC);

    if (VorC == 'V') {
        vowelCount = true;
    }
    else {
        vowelCount = false;
    }
}

int CountChars::getCountVorC()
{
    return countVorC;
}

int CountChars::getCountEOL()
{
    return countEOL;
}

int CountChars::getTotalChars()
{
    return totalChars;
}

bool CountChars::getVowelCount()
{
    return vowelCount;
}

主要:

#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <cstdio>
#include "CountChars.h"

using namespace std;

void printCounts(CountChars);

int main()
{
    char VorC;
    char repeat = 'Y';
    CountChars charCounter;

    cout << "Welcome to the Character Counter Program!" << endl;
    cout << "\nWould you want to count vowels or consonants?" << endl;
    cout << "Type 'V' for vowels and 'C' for consonants: ";
    cin >> VorC;
    cout << endl;

    while (toupper(VorC) != 'V' && toupper(VorC) != 'C') {
        cout << "\nSorry, that was an invalid choice. Please try again: ";
        cin >> VorC;
        cout << endl;
    }


    do {
        cout << "You may being typing input below.\n" << endl;

        charCounter.setVowelCount(VorC);
        charCounter.inputChars();
        cin.clear();
        printCounts(charCounter);

        cout << "\nWould you like to enter new input?" << endl;
        cout << "Type 'Y' for yes or 'N' for no: ";
        cin >> repeat;
        cout << endl;

        while (toupper(repeat) != 'Y' && toupper(repeat) != 'N') {
                cout << "\nSorry, that was an invalid choice. Please try again: ";
                cin >> repeat;
                cout << endl;
        }

    } while (toupper(repeat) == 'Y');

    cout << "\nThank you for using the Character Counter Program!\n" << endl;

    system("pause");
    return 0;
}

void printCounts(CountChars charCounter)
{
cout << "\nTotal characters: " << charCounter.getTotalChars() << endl;

        if (charCounter.getVowelCount() == true) {
            cout << "Total vowels: " << charCounter.getCountVorC() << endl;
        }
        else {
            cout << "Total consonants: " << charCounter.getCountVorC() << endl;
        }

        cout << "Total end-of-lines: " << charCounter.getCountEOL() << endl;
}

【问题讨论】:

  • 为什么在做cin &gt;&gt; char(VorC); 时要投射到char?你为什么不直接做cin &gt;&gt; VorC;
  • 我想你想要 OR 运算符||
  • 我已经养成了将所有内容转换为我想要的类型的习惯,因为它很容易导致错误。无论如何,我不明白为什么这很重要,因为它不会导致任何错误。我只是重试了我的程序,去掉了铸件。所有的错误都仍然存在,不管是演员还是不演员。
  • @JasonSperske 我的代码中有很多条件语句。你建议我在哪里使用 OR 运算符?

标签: c++ infinite-loop


【解决方案1】:

cin.get() 返回 int

你有:

char letter;

while ((letter = cin.get()) != EOF)

如果普通 char 是无符号类型,就像在某些机器上一样,那么它永远不会评估为 true,因为值 -1(EOF 的正常值)被分配给(无符号)@987654326 @,它被映射到0xFF,当0xFFintEOF(仍然是-1)进行比较时,答案是否定的,所以循环继续。

解决此问题的方法是使用int letter 而不是char letter。 (请注意,如果char 是有符号类型,则编写的代码存在不同的问题;然后,代码为 0xFF 的字符(通常是 ÿ、y 变音符号、U+00FF、带分音符号的拉丁小写字母 Y)被误解为 EOF . 修复方法相同;使用int letter;)。

不过,我怀疑这只是问题的一部分。


EOF 不是 EOL

在同一个函数中,你还有:

    if (letter == EOF) {
        countEOL++;
    }

您知道 letter 不是 EOF(因为循环检查了这一点)。此外,您想计算 EOL,而不是 EOF(每个文件只有一个 EOF,但如果您继续尝试读取 EOF 之外的内容,则会重复返回 EOF)。你可能需要:

    if (letter == '\n') {
        countEOL++;
    }

或者您可能想定义 EOL 并与之进行比较:

    const int EOL = '\n';
    if (letter == EOL) {
        countEOL++;
    }

cin 在输入中留下换行符

在代码中:

cout << "Type 'V' for vowels and 'C' for consonants: ";
cin >> char(VorC);
cout << endl;

while (toupper(VorC) != 'V' && toupper(VorC) != 'C') {
    cout << "\nSorry, that was an invalid choice. Please try again: ";
    cin >> char(VorC);
    cout << endl;
}

第一个cin 操作将换行符留在输入流中。例如,如果用户输入了“Y”,那么下一个cin 操作(在循环内)将读取换行符,并且由于换行符既不是“V”也不是“C”,它会再次抱怨(但会等待更多信息)。

添加#include &lt;limits&gt; 并使用:

cin.ignore(numeric_limits<streamsize>::max(), '\n');

读取换行符。

同样,这不是问题的全部。


EOF 后无法继续阅读cin

最后一期,我想……

您注释掉的代码是:

/*do {
    cout << "You may being typing input below.\n" << endl;*/

    charCounter.setVowelCount(VorC);
    charCounter.inputChars();

    /*cout << "Would you like to enter new input?";
    cout << "Type 'Y' for yes or 'N' for no: " << endl;
    cin >> char(repeat);
    cout << endl;
        while (toupper(repeat) != 'Y' && toupper(repeat) != 'N') {
            cout << "\nSorry, that was an invalid choice. Please try again: ";
            cin >> char(repeat);
            cout << endl;
        }
} while (toupper(repeat) == 'Y');*/

请注意,在cin 到达EOF 之前,对charCounter.inputChars() 的调用不会停止。那时没有更多输入,因此循环中的cin(已被注释掉)每次都会失败,永远不会生成“Y”。您需要清除cin 上的错误,以便您可以输入更多数据,例如“更多输入”问题的答案。

我想知道您是否在阅读代码中混淆了 EOL 和 EOF。也许您打算只阅读到行尾而不是文件末尾。那么你的循环条件(我首先提到的那个)应该是:

int letter;

while ((letter = cin.get()) != EOF && letter != '\n')  // Or EOL if you define EOL as before

您应该始终准备好在您没有真正预料到时返回 EOF 的任何输入操作,就像这里一样。


永远是乐观主义者!上一期不是最后一期。

构造函数不构造

不过,我仍然有打印垃圾的问题。例如,它显示总字符数:-85899345。

我试图编译你的代码:

$ g++ -O3 -g -std=c++11 -Wall -Wextra -Werror -c CountChars.cpp
CountChars.cpp: In constructor ‘CountChars::CountChars()’:
CountChars.cpp:13:18: error: unused variable ‘countVorC’ [-Werror=unused-variable]
     unsigned int countVorC = 0;
                  ^
CountChars.cpp:14:18: error: unused variable ‘countEOL’ [-Werror=unused-variable]
     unsigned int countEOL = 0;
                  ^
CountChars.cpp:15:18: error: unused variable ‘totalChars’ [-Werror=unused-variable]
     unsigned int totalChars = 0;
                  ^
CountChars.cpp:16:10: error: unused variable ‘vowelCount’ [-Werror=unused-variable]
     bool vowelCount = false;
          ^
cc1plus: all warnings being treated as errors
$

您已经在构造函数中声明了隐藏类成员的局部变量,因此您的构造函数实际上并不能有效地构造。垃圾号码是因为你以垃圾开头。

cin &gt;&gt; char(VorC) 不会到处编译

同样,当我尝试编译 Main.cpp 时,开始出现错误:

$ g++ -O3 -g -std=c++11 -Wall -Wextra -Werror -c Main.cpp
Main.cpp: In function ‘int main()’:
Main.cpp:18:9: error: ambiguous overload for ‘operator>>’ (operand types are ‘std::istream {aka std::basic_istream<char>}’ and ‘char’)
     cin >> char(VorC);
         ^
Main.cpp:18:9: note: candidates are:
In file included from /usr/gcc/v4.9.1/include/c++/4.9.1/iostream:40:0,
                 from Main.cpp:1:
/usr/gcc/v4.9.1/include/c++/4.9.1/istream:120:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__istream_type& (*)(std::basic_istream<_CharT, _Traits>::__istream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>] <near match>
       operator>>(__istream_type& (*__pf)(__istream_type&))
       ^
/usr/gcc/v4.9.1/include/c++/4.9.1/istream:120:7: note:   no known conversion for argument 1 from ‘char’ to ‘std::basic_istream<char>::__istream_type& (*)(std::basic_istream<char>::__istream_type&) {aka std::basic_istream<char>& (*)(std::basic_istream<char>&)}’
/usr/gcc/v4.9.1/include/c++/4.9.1/istream:124:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__ios_type& (*)(std::basic_istream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<char>; std::basic_istream<_CharT, _Traits>::__ios_type = std::basic_ios<char>] <near match>
       operator>>(__ios_type& (*__pf)(__ios_type&))
       ^
…
$

这里的问题是:

cin >> char(VorC);

你真的不想让演员在那里:

cin >> VorC;

您可以说应该检查输入是否有效:

if (!(cin >> VorC)) …process EOF or error…

cin &gt;&gt; char(repeat); 当然也有同样的问题。

我不知道为什么它是为你编译的;它不应该这样做。有了这个固定,它有点工作。我遇到了“仍在输入中的换行符”,所以 inputChars() 函数在 EOL 之前得到零个字符等。现在由您来处理。

【讨论】:

  • 这是否意味着我必须使用无符号字符?当我尝试这样做时,inputChars 函数根本不起作用。
  • EOL 计数的修复工作(我混淆了 EOF 和 EOL)并且现在似乎正确计算了行尾,所以谢谢你。不过,我仍然有打印垃圾的问题。例如,它显示Total characters: -858993455,尽管将letter 更改为类型int 并在cin 运算符之后插入cin.ignore();,但仍会发生无限循环。另外,我没有误解任务。用户应该能够输入输入,直到他们输入 ^Z 来表示 EOF。新行不应停止输入流。
  • 我对我的程序进行了更多测试,这就是导致无限循环的原因:while (toupper(repeat) != 'Y' &amp;&amp; toupper(repeat) != 'N') { cout &lt;&lt; "\nSorry, that was an invalid choice. Please try again: "; cin &gt;&gt; repeat; cout &lt;&lt; endl; }
  • 事实证明,在调用 inputChars() 之后输入 cin.clear(); 就可以解决无限循环问题。该程序现在运行良好,除了为totalCharscountVorCcountEOL 打印的最后一期垃圾值。
  • 我正在测试cin &gt;&gt; repeat,但它无法为我阅读。您可能还需要测试。看来cin.clear() 不允许在cin 上的EOF 之后进行更多输入——至少对我来说不是。我不能立即确定必要的技巧是什么。顺便说一句,您需要一种机制来在每次迭代后将计数重置为零。构造函数中的代码(已修复)几乎可以执行(您可能不想在每次迭代时重置vowelCount)。也应该进行一些抽象(对于读取的 V/C 或 Y/N 循环)——但这可以等到其余的工作正常。
猜你喜欢
  • 2015-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
相关资源
最近更新 更多