The end-of -input character doesn't work - c++

before I was doing a very simple programming exercise and I have a problem with the end-of-input character. I wrote this program to check if two words repetead in the text :
string previous = ""; //initalized to "not a word"
string current; //current word
while (cin >> current) { //input operation
if (previous == current) // check if the word is the same as last
cout << "repetead words : " << current << '\n';
previous = current;
}
cout << previous << "\n" << current << "\n";
My book says that if I want to terminate the input operation and to fall out the while loop I must insert the end-of-input character, but, if I insert that character on the same line of my input words I will not fall out the loop.Just if I insert it on a newline it works.Why ? I must insert the end-of-input character on a newline to make it work ?

std::cin::operator>> will return false instead of another reference to std::cin when it reaches end-of-stream. Passing a single eof is a way to signal end-of-stream.
When std::cin parses only an eof, it interprets it specially instead of considering it more data in the stream. If it parses any data in combination with eof, it's just considered data in the stream.

Related

Detect Repeated Words

I'm a beginner in C++ and I've using Programming: Principles and Practice from Bjarne Stroustrup. I've gotten to the assignment chapter and came across this example
int main()
{
string previous = " "; // previous word; initialized to “not a word”
string current; // current word
while (cin>>current) { // read a stream of words
if (previous == current) // check if the word is the same as last
cout << "repeated word: " << current << '\n';
previous = current;
}
}
But I don't quite understand the logic behind it, mainly in the first through of the loop, where previous=" ", i dont know how previous get to equal anything at all from the input in current given that it values " ". If I compile and input " the cat cat eats" it identifies cat as the repeated word but how does it know since, like the comment says, its initialized to no word, why does it cout the repeated word: cat in that first case.
At the end of the loop iteration, you are assigning current value to previous (previous = current). At the start of new iteration, you are assigning user entered value to current value and comparing with previous.

Assigning a string variable to the space character " " in order to find repeated words

int main()
{
std::string previous = " ";
std::string current;
while (std::cin >> current)
{
if (previous == current)
std::cout << "\n repeated word: " << current;
previous = current;
}
};
The program works, but I don't know why. What exactly is the computer doing here? From what I understand, the computer first reads user input then checks if the word matches with "previous" which is initialized to a space character. Is the computer checking if both string variables are space characters? At what point does previous take on a different value?
In every step of the loop, current is checked against previous, and then previous is assigned to the value of current (in the last statement of the loop). Then another word is read into current, and so on.

console not returning expected number of characters in cin buffer

I am creating a console version of "Bull Cow Game". In the game, the user has a certain number of tries to guess what the secret word is. Every time they guess, the program returns the number of "Bulls" and "Cows" they guessed correctly. The user gets a "Bull" for every character that they guess in the right place and a "Cow" for every character that they guess correctly but is not in the right place.
My problem is in my getGuess() function. In the do-while loop, the program is supposed to loop if the user inputs anything other than the number of characters in "answer". When I run my program, I get some unexpected and confusing results:
1) No matter what I input for the first "guess", the program tells me that cin's gcount() is 0 or 1 characters after setw(). I could input 50 characters or 2 and the program would output the same result. If the gcount is 1, then this counts as one of the allotted guesses which is an undesirable result. If the cin.gcount() is 0, the program correctly does not count the guess as valid but I am still confused as to why the cin.gcount() is 0 at all.
2) If I change the number of characters in my guess from the previous guess, the program tells me that the cin.gcount() is whatever the cin.gcount() was after the previous guess instead of after the current guess. This is also an undesirable result since if the user decides to input the correct number of characters, the program will not accept the user's guess as valid.
I am confused as to why this is happening since isn't cin.ignore() supposed to dump all of the extraneous characters that setw() doesn't accept? Why would the number of characters in the cin buffer carry over from one guess to the other?
Here is the function in question:
string getGuess()
{
string guess = "";
const int MAX_LENGTH = 4;
/*ensures that "guess" is the same length as answer. This
will make it so that the program avoids comparing "guess"
to "answer" if "guess" has more characters than "answer".
This do-while loop also ensures that a user can't overflow
the cin buffer by theoretically inputting more characters
than the buffer could contain*/
bool endLoop = false;
do {
cout << "Enter a word containing exactly " << MAX_LENGTH << " characters: ";
cin >> setw(MAX_LENGTH) >> guess;
cout << "cin.gcount() after setw(): " << cin.gcount() << " characters" << endl;
/*ensures that the only character in the cin is '\n'. Otherwise
do-while loop continues*/
if (cin.gcount() != 1)
{
cout << "Invalid number of characters. Please input exactly " << MAX_LENGTH
<< " characters" << endl;
}
else
{
endLoop = true;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "cin.gcount() after cin.ignore(): "
<< cin.gcount() << " characters" << endl;
cout << "guess: " << guess << endl;
cout << endl;
} while ( endLoop == false );
cout << endl;
return guess;
}
Note: This was compiled with Microsoft Visual C++, ISO standard c++17.
A couple of misunderstandings I think
1) gcount only tells you how many characters have been read after an unformatted input operation, cin >> guess is not an unformatted input operation.
2) setw on input does not limit the numbers of characters read. If less than the specified width characters are read then the input is padded to make it equal the given width, but it does not stop more characters being read.
Your code is too tricky, forget about fancy I/O operations, do it the straightforward way. Just read a line of characters into a string using getline and check if the characters entered are what you expect. For instance remove the spaces at the beginning and end of that string, then check for internal spaces and finally check if the string is the length you require.

Why is part of my code being skipped and not letting me enter input?

Why does my code skip the last question when I put to much info in for the fist one? What am I doing wrong?
const int SIZEC =31;
char phrase[SIZEC];
cout << " Provide a phrase, up to 30 characters with spaces. > " << endl;
cin.getline(phrase, SIZEC);
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << " The phrase is: " << phrase << endl;
cout << endl;
cout << " Using sring Class Obects " << endl;
cout << "--------------------------" << endl;
cout << endl;
string leter;
cout << " Provide a single character > " << endl;
cin >> leter;
cout << " The single character is: " << leter << endl;
cout << endl;
If the code before this is needed tell me and I'll add it.
Use std::string::resize as a workaround.
string phrase;
getline(cin, phrase);
phrase.resize(30); // phrase will be reduced to 30 chars
string letter; // better to use char letter
cin >> letter;
letter.resize(1);
The main problem is that getline behaves differently in two cases:
If at least SIZEC characters are read and there is no newline character among them (e.g. there should be at least SIZEC+1 bytes to store the data read), it stops reading and sets so-called failbit status bit on the stream, which means "I have failed to read something, so input stream is probably incorrect". Quoting cplusplus.com:
The failbit flag is set if the function extracts no characters, or if
the delimiting character is not found once (n-1) characters have
already been written to s.
If newline character is encountered, failbit is not set and the newline character is succesfully read and ignored by getline.
What happens next is more interesting: extraction functions (all of them, I assume) fail immediately if the input stream is bad() (that is, either failbit, badbit, or eofbit are set on the stream). In particular, if previous extraction operation failed, all subsequent will fail as well. So, basically, if first line of the input cannot be fitted in your phrase array, then cin becomes "bad" and all further read operations do nothing.
You can override that behavior by manually resetting the failbit after calling getline like this:
cin.clear();
Following read operations will succeed until another one fails.
In your particular case, I assume that you want to read the first line regardless of the length, and then a second line. I that case, I think you
should to first check whether getline failed (by checking cin.failbit() or cin.good()) and then either do nothing (if it did not and there is no need in reading extra newline) or resetting the failbit and ignoring characters till the first newline. Something like this:
#include <iostream>
#include <limits>
#include <string>
using namespace std;
int main() {
char buf[5];
cin.getline(buf, sizeof buf);
if (!cin) { // operator ! is overloaded for `istream`, it's equal to `good()`
// If stream is bad: first line of the input was truncated,
// and following newline character was not read.
// Clear failbit so subsequent read operations do something.
cin.clear();
// Read remaining of the first line.
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// At this point, first line of the input is consumed
// regardless of its length
int x;
cin >> x;
cout << "String: |" << buf << "|\n";
cout << "x: " << x << "\n";
}
You can read more on StackOverflow here and there.
However, if there is no reason to use C-style string together with istreams, I'd suggest you using string and std::getline instead (like in Shreevardhan's answer); it will produce cleaner code and there will be no extra cases.

ifstream to get then next character

So I have a while look that checks every character in a file.
while (infile.get(ch))
The problem is that in the same loop I have to check the next character to check for some validation.
Is there anyway I could move the next character while keeping track of the current one?
Thanks
Use the peek() method so you will be able to look at the next character before extracting it. Here's an example:
std::istringstream iss("ABC");
for (char c; iss.get(c); )
{
std::cout << "Current character is: " << c << std::endl;
if (iss.peek() != EOF)
std::cout << "Next character is: " << (char)iss.peek();
}
This should output:
Current character is: A
Next character is: B
Current character is: B
Next character is: C
Current character is: C