While the loop causes an infinite loop, but I cannot understand why

I am working on a C ++ assignment to teach us more about objects and OOP. Below is my code. Its essence is that the user enters some input, and the program counts the number of vowels or consonants (selected by the user), the total number of characters entered and the total number of line endings.

I have three problems:

  • The part of the code that I commented on causes an endless loop when it is left. This leads to the fact that the output from the countChars function countChars printed endlessly, as well as the output requesting the user if they would like to supply more input.
  • The countChars function countChars not correctly consider EOL. I think this is most likely due to my unfamiliarity with EOL. How can I put it in my conditional statement? If I want to say, “an increment, if it has a value of“ 0, ”I say if (variable == 0) . How can I say that C ++ is incremented if something is EOL?
  • countChars prints random, negative values ​​for counters. I notice that the values ​​change depending on what I type (except EOL), but I'm not sure why I get negative values. I am not sure how to fix this using unsigned int and initializing the values.

In addition, I foresee that people tell me to use the getline function, but we had very specific instructions for using cin.get (in the end, we need to learn a bit of everything), please avoid the fix that uses getline .

Header file:

 /* +----------------------------------------+ | 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 

Implementation File:

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

Main:

 #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; } 
0
source share
1 answer

cin.get() returns int

You have:

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

If a simple char is an unsigned type, as on some machines, then it will never evaluate to true, since the value -1 (normal value for EOF) is assigned (unsigned) char , it is displayed in 0xFF, and when 0xFF compared with int like EOF (it's still -1 ), the answer will be false, so the loop continues.

The fix for this is to use int letter instead of char letter . (Note that there is another problem with the code written if char is a signed type, then the character with code 0xFF - often ÿ, y umlaut, U + 00FF, LATIN SMALL LETTER Y WITH DIAERESIS - will be misinterpreted as EOF. The fix will be the same: use int letter; ).

I suspect this is only part of the problem.


EOF not EOL

In the same function, you also have:

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

You know that letter not EOF (because the loop checked this). Also, you would like to read EOL, not EOF (there is only one EOF for each file, although if you keep reading outside of EOF, you will get EOF again). You probably need:

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

or maybe you want to define an EOL and compare with it:

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

cin leaves a newline in the input

In code:

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

The first cin operation leaves a newline in the input stream. If the usage is printed with "Y", say, then the next cin operation (inside the loop) will read the new line, and since the new line is neither "V" nor "C", it will complain again (but then will wait for more input).

Add #include <limits> and use:

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

to read a new line.

Again, this is not the whole problem.


Cannot continue reading cin after EOF

And the last installment, I think ...

Commented code:

 /*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');*/ 

Note that the call to charCounter.inputChars() does not stop until cin reaches EOF . There is no input at this point, so the cin in the loop (which is commented out) will fail every time, never generating "Y". You need to clear errors on cin so that you can enter more data, for example, the answer to the question “more input”.

Interestingly, you confused EOL and EOF in the read code. Perhaps you intended to read only to the end of the line, and not to the end of the file. Then your loop condition (the first thing I mentioned first) should be:

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

You should always be prepared for any of the input operations in order to return EOF when you did not expect this, as here.


Ever an optimist! The previous issue was not the last.

The constructor does not create

I still have a problem with junk printing. For example, he says "Total characters: -85899345."

I tried to compile your code:

 $ 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 $ 

You specified local variables in your constructor that hide class members, so your constructor is actually not useful to build. The amount of spam is related to the fact that you start with garbage.

cin >> char(VorC) does not compile everywhere

Similarly, when I tried to compile Main.cpp , I got errors:

 $ 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&)) ^ … $ 

The problem is this:

 cin >> char(VorC); 

You really don't want the cast to be there:

 cin >> VorC; 

You should probably check if the input works:

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

The same problem affects cin >> char(repeat); , sure.

I do not know why it is compiled for you; he should not have done that. With this fixed, this is the kind of job. I came across a "new line still at the input", so the inputChars() function received null characters before EOL, etc. Now you decide what to do with it.

+3
source

Source: https://habr.com/ru/post/975230/


All Articles