What is the purpose of using cin.get() in a while loop? - c++

I don't understand why I have to use cin.get() again in while loop. Using cin.get() prior to the while loop does the same thing that cin.get() would do while also in the while loop. It reads a string of text I input while accounting for spaces. But obviously in this program I am trying to push all the text into a vector. If I were to exclude the cin.get(next) from the while loop and only have the line.push_back(next), then the program gets an error and crashes.
Please explain why it does this. Thank you
//Demonstration of the generic find function
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector<char> line;
cout << "Enter a line of text: \n";
char next;
cin.get(next);
while(next != '\n')
{
line.push_back(next);
cin.get(next);
}
return 0;
}

Here´s a little guide to help you out. Sometimes it´s hard to see the forest for the trees at the beginning.
Define a variable named next of type char
char next;
Since next has no meaningful value right now, let´s get one. We need it for the condition in our while statement.
cin.get(next);
Lets loop around till next equals '\n'
while(next != '\n')
{
We still did not do anything meaningful with next the only thing we know is that it doesn´t equal '\n' so we really ought to do something with it.
We push it in our vector.
line.push_back(next);
great. Done so far. We now need a new value for next for several reasons. On the one hand if we don´t change next we will loop forever (or too long at least) since the condition of the loop won´t get something new to chew on and on the other hand we want a new value for our vector, don´t we?
So yes, lets get the next next
cin.get(next);
And back to the beginning of our loop for testing
}
that´s it.

Related

boost split - cout and vector - explain behaviour of this

I'm quite new to c++ and boost, I don't understand what's actually happening here.
So I'm using cin to get some input from the user. Then I'm splitting that string of spaces into a vector and trying to print the first index of the vector.
My code:
std::string cmd;
std::vector<std::string> args;
while (std::cin >> cmd) {
boost::split(args, cmd, boost::is_any_of(" "), boost::token_compress_on);
Console::print(args[0]);
break;
//reset the vector
//std::cin.clear();
//args.clear();
}
My console print function just uses normal cout, here is the code for it:
int Console::print(std::string message, int color)
{
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(consoleHandle, brightGreen);
std::cout << "myconsole :: ";
SetConsoleTextAttribute(consoleHandle, color);
std::cout << message << "\n";
return 0;
}
What's happening:
For the sake of this question the input is "start go".
I only want to print the first element. Without the break my program first prints start and then it prints out go. I have determined that the program does 2 loops and each time prints the first element, I know this because if I have the break then there is only start printed and the program ends. Firstly, why is this happening? Why does the first index of the vector get removed and then looped making the first index "go"?
Does this all have something to do with the stringstream/buffer or something. I don't know much about these. That was my guess so I tried to reset the buffer with cin.clear() and empty the vector with args.clear() but that still produced the same results.
Secondly, if I use the code below and try to access the 2nd element "go" my program just crashes. From what I have tried from the above I can assume that I am correctly splitting the string.
Is there some sort of asynchronous behavior going on and the split function just isn't finished yet? Or?
Any help would be awesome. Thanks.
Your problem is that std::cin >> cmd only reads "start", feeds that into the loop (which creates a single element vector and prints the only element), then loops round and does the same with "go".
You need while(std::getline(std::cin, cmd)).
You also need to learn to use your debugger which would have shown you what the problem was.

Searching for char from end of file using seekg() c++

I have a file and I want to only output the last line to the console.
Here's my thoughts on how I would do it. Use file.seekg(0, ios::end) to put myself at the end of file.
Then, I could create a decrement variable int decrement = -1; and use a while loop
while (joke.peek() != '\n')
{
decrement--;
}
and get the starting position for my final line (going backwards from the end).
Knowing this, joke.seekg(decrement, ios::end); should set me to the beginning of the final line, and assuming I previously declared string input;
I would think that
getline(joke, input);
cout << input << endl;
would output it to the console.
Full code
void displayLastLine(ifstream &joke)
{
string input;
int decrement = -1;
joke.clear();
joke.seekg(0, ios::end);
while (joke.peek() != '\n')
{
decrement--;
}
joke.clear();
joke.seekg(decrement, ios::end);
getline(joke, input);
cout << input << endl;
}
The problem is, when I go to call this method for the file, nothing happens. When I step through it, the decrement just keeps on subtracting one, far beyond where a '\n' would be. To give an example of a text file, it would look something like this:
junk
garbage
skip this line
This is the line that we're looking for!
joke.seekg(0, ios::end);
This positions the file at the end.
while (joke.peek() != '\n')
Well, here's problem #1. When you're at the end of the file, peek() always returns EOF.
decrement--;
You write:
When I step through it, the decrement just keeps on subtracting one,
Well, what did you expect to happen, since that's the only thing that the loop does? The only thing your for loop does is subtract 1 from decrement. So that's what happens.
This a common problem: a computer does only what you tell it to do, instead of what you want it to do.
Although this is not optimal, your missing step is that before you peek(), you need to seek() back by one character. Then, peek() shows you the character at the current cursor position. Then, seek() back by one more character, and check peek() again, and so on.
But that still will not be sufficient for you. Most text files end with a newline character. That is, a newline is the last character in the file. So, even if you add back the missing seek(), in nearly all cases, what your code will end up doing is finding the last character in the file, the final newline character.
My recommendation for you is to stop writing code for a moment, and, instead, come up with a logical process for doing what you want to do, and describe this process in plain words. Then, discuss your proposed course of action with your rubber duck. Only after your rubber duck agrees that what you propose will work, then translate your plain language description into code.
peek does not move the file pointer, it reads the character without extracting it. So, you are constantly peeking the same value (character) and ending up in an infinite loop.
What would you need to do is something like:
while (joke.peek() != '\n')
{
joke.seek(-1, ios::cur);
}
That would put the input position at the \n, using the 2nd overload of seekg.
Please note that this is not a perfect solution. You need to check for errors and boundary conditions, but it explains your observed behaviour and gives you something to start fixing your code.
Your loop is actually only decrementing "decrement" and not using it to make the next search.
while (joke.peek() != '\n')
{
joke.seekg(decrement, std::ios::end);
decrement--;
}

cin in a while-loop

#include <iostream>
using namespace std;
int main()
{
string previous;
string current;
while (cin >> current)
{
if(current == previous)
{
cout << "repeated word";
}
previous=current;
}
return 0;
}
my questions are:
When it states while(cin>>current), why is the entire entered string of text not assigned to current? I don't understand how it compares all the words individually.
How does it get a word for previous. How does it know 2 of the same words are adjacent?
EDIT: I think I just understood why. Tell me if I am wrong but I think its because the compiler stops the cin assignment at the space and that first word is assigned to current, then it compares it to the previous word, but since it is the first word, it does not have a previous word so it just assigned the first word to previous and compares the next word in the sentence until there are no more words left. I'm fairly certain this is how it works but I am going to leave this up in case anyone is ever wondering something similar.
The default behavior is to stop on whitespace when reading strings as you are doing. You can change it to read whitespace by saying std::cin >> std::noskipws.
The previous word is always assigned at the end of the loop. Given the answer to part 1, it should be clear why previous works.
If you use std::istream::operator>> with a std::string argument, it reads characters until it finds any whitespace character. This means that it will only read a single "word" if you're entering a sentence. Use std::getline(cin, current); to read an entire line (until a newline character).
You assign current to previous: previous = current. This means that after reading current, you make previous current. So the next time, before you read, you can compare previous with current to see if they're the same thing.
If you want to use string, you must use #include string or std_lib_facilities.h

Input terminal problems and map

I am using map to count the occurence of words. Here is the code.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string,int>wordcount;
string s;
while (cin>> s && s!="red")
++wordcount[s];
while (cin>>s && s!="red")
cout << s << " " << wordcount[s] << endl;
return 0;
}
I start the program, type words and at the last line enter the word "red", but it does not do anything. Then I type "red" the second time and it outputs:
press any key to continue
what is wrong?
Nothing is wrong. Visual Studio will automatically PAUSE the program before it ends to prevent the console window from closing, when you "Run without Debugging".
I understand that you want to receive a list of words, fill each word's number of occurrences into a map, and print it.
So, instead of the second while loop, you need to iterate on the map that you created and print the count for each word.
You can learn here how to print the map's contents.
Too groggy to write here, but I'll try a second time. :)
If you write a lot of words, it will count them up until you write "red".
The second loop will print the count for the words you input, but if you put "red" right away it will simply terminate the program without printing anything.
Try running the program with the following input:
one
two
two
red
zero
one
two
red

Using cin.get() to grab a line of text, then using it in a loop to display that line?

Ok, so I came across this code snippet in my textbook that's supposed to echo every other character a user types in. Now, I understand the every other character part, but I'm having difficulty with the use of cin.get(). I understand why the first cin.get() is there, but why is it also inside the loop? I'm guessing I'm not fully grasping the nature of input streams...
EDIT: It just clicked... I'm an idiot. Thanks for clearing that up.
char next;
int count = 0;
cout << "Enter a line of input:\n";
cin.get(next);
while (next != '\n')
{
if ((count%2) == 0)
cout << next;
count++;
cin.get(next);
}
Thanks in advance!
cin.get in this case does not "grab a line of text" as you seem to believe. cin.get in this case grabs just a single character. With cin.get you read characters the user is typing in, one by one, one after another. This is why you have cin.get in a loop.
The call to cin.get(next) that comes before the loop is only placing the first character of buffered user input into the variable 'next.'
Once inside the loop, and the character stored in 'next' has been processed (echoed if at an even index, otherwise ignored), cin.get(next) needs to be called again to retrieve the next character.
Its printing characters present at even positions
char next;
int count = 0;
cout << "Enter a line of input:\n";
cin.get(next);//gets first character (position zero) from input stream
while (next != '\n')//check whether the character is not line feed(End of the line)
{
if ((count%2) == 0)//checks if position is even
cout << next; //if yes print that letter
count++; //increments the count
cin.get(next); //gets next character from input stream
}
We require two cin.get(...)
before entering the while loop we need to know first character(position zero)
inside while loop for getting next character
but what is the use of outside cin.get(ch) what does it do
how cin.get() works inside loop
both behaviours are lookin different
so it's making confusing
there is a statement in loop to print the character got using cin.get(next) but it will not print it.... it will print all together after pressing enter key ... actually it should display the characters as we type from the keyboard but it is not actually working like that
istream& get(char &c) gets a character from the input stream.
so on the first call cin.get(next) you typed:
"hello world!"
Then future cin.get(next) will fetch h, e, l, l, etc... on every call until the there are no more characters in the input stream and that's when it will block asking the user for more input.
Streams in C++ , are buffered. Think of them as a line of letters. When you call cin.get(var) the first character in that line is removed and returned to you. So, that's how it works.
An example would help better. When the first cin.get() is executed, let's say you type in :
LISP
and then, cin.get() will return (in the var.) L and then the buffer will look like ISP... the next call will place I in the var. and the buffer will look like SP and so on...