use of: while (cin >> x) and eof - c++

I am not so sure how the works I suppose is my root problem here. I've read a few previous posts on while(cin>>x) but nothing seems to answer my question really.
I am using this loop to read in some text data:
while (cin >> x){
searchText.push_back(x);
}
but then later in the code I am trying to read in a single word using:
cout << "Please enter your target word: ";
string targetWord;
cin >> targetWord;
but the above while loop/ eof seems to scupper the 2nd code snippet (if I move the 2nd code snippet up above it all works fine, but obviously that is not what im trying to do)
EDIT
Here is the full code for clarity:
int main()
{
// ask for the target word
// cout << "Please enter your target word: ";
// string targetWord;
// cin >> targetWord;
// ask for and read the search text
cout << "Enter the complete search text, "
"followed by end-of-file: ";
vector<string> searchText;
string x;
while (cin >> x){
searchText.push_back(x);
}
// check that some text was entered
typedef vector<string>::size_type vec_sz;
vec_sz size = searchText.size();
if (size == 0){
cout << endl << "You must enter some text. "
"Please try again." << endl;
return 1;
}
// ask for the target word
cin.clear();
cout << "";
cout << "Please enter your target word: ";
string targetWord;
cin >> targetWord;
int count = 0;
for (int i=0; i<size; ++i){
if (targetWord == searchText[i]){
count++;
}
}
cout << "The target word [" << targetWord << "] was "
"in the search text " << count << " times." << endl;
return 0;
}
I am just trying to take in some text from the user... then a search word and see how many times the word appears in the entered text (pretty simple!)
I know I could do it differently but the question here is more about how can I use the cout/ cin stream again after it has had an EOF in it previously

When cin (or any other std::stream) hits an end of file, it sets a status to indicate that this has happened.
To reset this status, you need to call cin.clear();, which will clear any "bad" state, and make sure the stream is "ok" to use again. This also applies if you are reading from a file, and want to restart from the beginning.
Edit: I just took the code posted above, and ran it on my machine, adding at the top
#include <iostream>
#include <vector>
using namespace std;
This following is the compile and run:
$ g++ -Wall words.cpp
words.cpp: In function ‘int main()’:
words.cpp:40:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
$ ./a.out
Enter the complete search text, followed by end-of-file: aa bb cc [CTRL-D]
Please enter your target word: aa
The target word [aa] was in the search text 1 times.
which is what I expected to see...
Edit2: For completeness: The "success rate" of using cin.clear() will depend on the implementation. A more reliable solution is to use a different way to mark the end of the stream of words in the first phase of the program. One could use a single "." or "!" or some other thing that isn't supposed to be in a "word" - or something longer, such as "&&#&&", but that makes it hard to type and remember when one is 15 pages into the input.

When execution leaves the loop
while (cin >> x){
searchText.push_back(x);
}
it does so because the "testing" of cin has returned false, in other words, failbit and/or badbit has been set on the stream. When that is the case, any further attempt to read from the stream will fail, i.e. targetWord will be left empty.
To make the stream usable again, you have to reset the error flags by calling cin.clear();

It would be somewhat helpful if we knew the type of x in the
first loop, but basically: you read all of the available input,
then try to read some more, and you're surprised that it's
failing. The contrary would surprise me.
The real question is: what are you trying to do? Basically,
what is the type of x, and—I'm assuming that you're
supposing that cin is an interactive device because of the
prompt—how do you determine that the first input has
finished? If the first loop ends because of "end of file" (user
entered control-D under Unix, or control-Z under Windows), then
there's no way you can reliably expect to read more. Resetting
the error status with cin.clear() might work; it will cause
the istream to try to read more from the streambuf. But it
might not; there are any number of layers below the istream
which, for whatever reason, may have memorized the end of file.
So you'll have to find some different way of recognizing the
end.
Just guessing from the names of the variables: if you're trying
to read a list of words, I'd use std::getline, with an empty
line for the end of the list. So the first loop would become:
while ( std::getline( std::cin, x ) && x != "" ) {
searchText.push_back( x );
}
if ( ! std::cin ) {
// Something really bad has happened...
}
Alternatively, you might want to break up the line on white
space, to allow more than one word per line (and to ignore any
extra white space in the line:
std::string line;
while ( std::getline( std::cin, x ) && x != "" ) {
std::istringstream l( line );
while ( l >> x ) {
searchText.push_back( x );
}
}
if ( ! std::cin ) // ...
Even if x has some other type, you might want to consider
something along these lines.

I used cin.clear() and on my mac set-up it did not seem to clear the EOF but on a ubuntu set-up it did clear the stream
Apple:
(Canopy 32bit) joes-imac:chap3 joe$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Ubuntu:
joe#joe-HPlaptop:~$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
I am happy to accept it is just compiler differences and finish/ close the issue (was a silly little one really!)
Thanks for all the help though (my first stackoverflow question actually!)

cin will stop when it will encounter endline character or a newline. So every time you enter something and hit enter it you are providing an '\n'. while(cin>>x){} should be used to read input continuously without endline/'\n'.

Related

First & only cin is skipped, even after using cin.ignore

Edit 2:
Well, turns out I was just being dumb! It wasn't anything to do with the code at all. I was running everything via a bash script, and because of how I was using it before (which also didn't require any input) I was still running it with & at the end - so obviously I couldn't get any input from that shell.
My program seemingly skips the line were I try to receive input using cin (it goes right to the next line).
Edit: Please look at the bottom where I put the new code and what happens.
I've searched here and googled, and I've found a lot of questions where people had the same problem! As far as I understand, the problem was almost always a leftover '\n' - but none of the solutions have worked for me sofar. This is the problematic code:
//char input_char;
std::string input_string;
//int input_int;
//std::string line;
std::cout << "hello. your input: ";
std::cin.clear();
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
std::cin >> input_string;
// std::getline(std::cin, input_string);
std::cout << "input: " << input_int << endl;
I only need one character or number. I've tried it with a character, int, or string; and I've tried cin and getline. I've added clear and ignore as was suggested for other similar questions, but I still have the same problem.
This is at the beginning of my main, so I'm not doing any other cout or cin before this code. However, this is part of a larger project, and I'm using ros. Before the program gets to this part, there are other outputs which are handled through ros; no other input though.
I'd very much appreciate you help with this! I feel like I must be missing something really obvious...
Edit: I've now commented out literally everything that isn't immediately related to this input, and moved cin to the very top of the main. This is now the complete code (commented parts left out):
#include <iostream>
#include <ros/ros.h>
#include <vector>
#include <ros/console.h>
#include "std_msgs/String.h"
//#include <SharedMessages/MicroconRequest.h>
/* ... */
//ros::Publisher reqPublisher;
//SharedMessages::MicroconRequest reqMsg;
/* ... */
int main( int argc, char* argv[] )
{
char input_test;
std::cout << "character: ";
std::cin >> input_test;
std::cout << input_test;
std::cout << "did that work?";
// Handle ROS communication
ros::init( argc, argv, "Gestures" );
ros::NodeHandle n;
//ros::Subscriber joy_sub_ = n.subscribe<sensor_msgs::Joy>("joy", 10, joyCallback, this);
//reqPublisher = n.advertise<SharedMessages::MicroconRequest>("MicroconRequest", 10);
ros::Rate loop_rate(10);
// Infinite control loop
while (ros::ok())
{
/* ... */
cntLoop++;
ros::spinOnce();
loop_rate.sleep();
}
// turn off microcontroller
return 0;
}
Now what happens is the following:
$ ./startDemo.bash
Starting Minimal Example
$ character: a # now I have time to input something, but...
a: Befehl nicht gefunden. # = command not found]
# then it doesn't do anything, so I stop it
$ ./stopDemo.bash
killing /Gestures
did that work?[ WARN] [1473954737.268901991]: Shutdown request received.
[ WARN] [1473954737.268978735]: Reason given for shutdown: [user request]
killed
$
Only after killing the program does the output suddenly appear. What is happening here? I'm so confused.
I don't understand your original question about skipping a line but the reason nothing is printed until you shutdown is that you are missing the endl from the output. I added it and the output seems as you would expect?
char input_test;
std::cout << "character: ";
std::cin >> input_test;
std::cout << input_test;
std::cout << "did that work?" << std::endl;
Output:
root#93043381199d:/catkin_ws/devel/lib/stack# ./stack_node
character: a
adid that work?
Well, turns out I was just being dumb! It wasn't anything to do with the code at all:
I was running everything via a bash script, and because of how I was using it before (which also didn't require any input) I was still running it with & at the end - so obviously I couldn't get any input from that shell.
[Note: I wasn't sure if it was good practice to answer one's own question; at first I just edited it. But I figured it'd make more sense than to just leave it open.]

clearing out extra input from terminal

Here is an example code demonstrating the problem I'm facing.
#include <iostream>
#include <string>
extern "C" {
#include <unistd.h>
}
int main()
{
std::cout << "Making tests ready!" << std::endl;
std::cout << "\nTo start out, Enter an integer: ";
int a = 0;
std::cin >> a;
std::string input;
sleep(3); // what to do if user enters data during this?
std::cout << "\n Now enter a string";
std::getline(std::cin, input);
std::cout << "\nHere are your values - " << a << " & " << input;
return 0;
}
See the sleep call in between the code? This could be replaced with somewhat long delays while computing something when my program isn't accepting any inputs. Now if user presses some keys during this time, that input is captured by std::getline() in next line of code. I know this is the default behavior since it should capture the input being provided.
But what I want is to clear all that captured input and start fresh with 15th line that is std::cout << "\n Now enter a string";, which is immediately after sleep. I don't know exact term to describe this or else I would have used that. Thanking you.
Edit: I've tried using std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); in my code, but it asks for input and then discards it.
Please mind my english, not a native speaker.
Reading the comments causes me to think that you can't really solve this problem (at least by the means suggested there). There's an inherent race condition in any case. Consider the following lines:
sleep(3);
// (*) <- Potential location 1.
std::cout << "\n Now enter a string";
// (**) <- Potential location 2.
std::getline(std::cin, input);
The various comments show some (very technically-competent) ways to flush the standard input. The problem is, you cannot put them in the location marked (*) nor (**).
First location - you clear the standard input some way. Now you decide it's time to move to the next line (std::cout << ...). While you do that, the user types in some more input. Race!
Second location - You print out the message (std::cout << ...), and proceed to clear the standard input. Before you manage to do that, the user typed in something. Race!
It seems to me that any of the techniques described in the comment require locking the standard input, and I don't think there's a (standard) way to do so.

How to break out of this for loop: `for (; cin >> A;);`

for (cout << "\nEnter the Sentence now:";
cin >> Ascii;
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
Probably the best advice is don't be clever. Not only do you make it hard for anyone else* to read, understand, and modify your code, you run a real risk of outsmarting yourself.
Thus, don't try to do weird and clever things to implement your loop. Just do things naturally. If they don't naturally fit into how for or while or do ... while statements are structured, then just write a generic loop and use break statements to deal with leaving the loop. e.g.
while (true) {
// Some stuff
if (i_should_break_out_of_the_loop) {
break;
}
// Some more stuff
}
This is pretty much always better than doing things like torturing the for statement in the way you have.
Once you have a clear, easily comprehensible loop, it should be relatively easy to modify it to suit your needs. (or to ask a clearer and more focused question)
*: "anyone else" also includes you three weeks from now, after you've had time for it leave your short term memory.
I strongly advise you to turn this loop into a while loop. However the following is true whether or not you do:
Just enter an EOF, then the loop will terminate.
How an EOF is input will depend on your OS (and possibly also on your terminal settings). On Linux (under default terminal settings) you get an EOF pressing Ctrl+D at the beginning of the line. On Windows, I think it's Ctrl+Z. On Mac I have no idea.
Of course you could also redirect stdin for your program to come from a file (in which case EOF is — as you would guess — generated at the end of file), or from a pipe (in which case EOF is generated as soon as the writing program closes the pipe).
If the variable Ascii is not of type char or string, you may also enter something that cannot be parsed as that variable's data type (e.g. if reading an int, anything other than a number will cause the stream to report failure and thus the loop to terminate).
You also might want to add another end condition then in the loop body (which in your for loop is currently just an empty statement). For example, you might decide that a percent sign should terminate your loop; then you could write (I'm still assuming the type of Ascii which you didn't provide is char):
cout << "\nEnter the Sentence now:";
while(cin >> Ascii)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
if (Ascii == '%')
break;
}
However note that normally operator<< skips whitespace; I guess you don't want whitespace skipped. Therefore you probably shouldn't use operator<< but get; this will also allow you to use the end of line as end condition:
cout << "\nEnter the Sentence now:";
while(std::cin.get(Ascii) && Ascii != '\n')
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
}
However in that case, it's better to read the line in one step and then iterate through it:
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (std::string::iterator it = line.begin; it != line.end(); ++it)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)*it + RandomNumberSubtract << endl;
}
Note that in C++11, you can simplify this into
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (auto ch: line)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)ch + RandomNumberSubtract << endl;
}

cin.getline() skipping first iteration

I'm practicing with c string / pointers and can't solve this simple problem. cin.getline() isn't prompting user input for the first iteration, but does so for the consecutive strings. (I arbitrarily chose 10 as the char limit).
Am I overlooking something extremely simple?
void getStrings() {
int num;
cout << "How many strings? ";
cin >> num;
const int numStrings = num;
char** stringSet = (char**) malloc(numStrings * sizeof(char*));
for (int i = 0; i < numStrings; i++) {
*(stringSet + i) = (char*) malloc(10);
cout << "String " << i << ": ";
cin.getline(stringSet[i], 10);
cout << endl;
}
Setting aside the fact that it's generally inadvisable to use bare pointers in C++ when things like the standard library's std::string are available, you should not use malloc. For example: Instead of (char*) malloc(10), you should write new char[10] and remember to delete[] *(stringSet+i) at the end of your program.
That said, the line:
cin >> num
... extracts only the first number it comes across. It will fail (and cin will set its fail bit, and will need to be reset with cin.reset()) if it encounters any non-whitespace characters before it encounters a number.
But it stops extracting from the input after that. In your input stream is still whatever whitespace or other characters were still present in your input. For example, if you ran this program and typed "2 foobar" before pressing enter, it would immediately print:
String 1: foobar
String 2:
This is because the stream still contains "foobar\n".
In order to get the behavior you're looking for you will probably want to add this before your loop:
cin.ignore();
That will clear the stream of anything that's there.
cin >> num;
This will prompt the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key. The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key. cin will parse the digits to produce an integer, which it stores in the num variable. It stops at the newline character, which remains in the input buffer. Later, you call getline, which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input. So it appears that the first call to getline didn't do anything, but actually it did.
What do you mean by " isn't prompting user input for the first iteration"? I read that to mean "isn't printing the prompt for the input of the first string", but based on your code, I think it means "is printing the prompt for the input of the first two strings before it reads input."
cin >> num reads a number, the whole number, and nothing but the number. It does not read whatever follows the number, like a newline. So the first getline reads the newline character which you've already typed.
By the way, you should use cerr instead of cout for user prompts.
cout should be reserved for actual output. That makes scripting much easier, because you can redirect cout independent of cerr, and because you don't want to capture prompts in the program results anyway.

string operations and odd results

first post so my apologies if I break protocol.
I'm working on a silly program for school and I have the following code.
cout << "//Dictionary Program//\n\n";
cout << "Enter a command:\n's' - to search for a pattern at the beginning\n";
cout << "'e' - to search for a pattern at the end\n";
cout << "'c' - to search for a pattern anywhere in the word\n";
//Gather user input.
cout << "Please enter a command ('q' to quit): ";
cin >> userCommand;
cmdCheck = userCommand.find("secq");
while(cmdCheck < 0 || userCommand.length() > 1){
cout << "Please enter a valid command\n";
cin >> userCommand;
cmdCheck = userCommand.find("secq");
}
This is driving a menu and I am trying to validate the input. It should be one letter, and one of the following "secq"
I am having a terrible time with the string.find() in the immediate window. I end up with CXX0047: Error: argument list does not match a function. Which I don't understand at all because I am using it elsewhere.
The while condition is not being nice to me. When I give the program a "v" it ends up inside the block like it should, but then I give it an "s" where the cmdCheck should evaluate to 0, but it gives a -1 and stays inside the block.
Lastly, I coded around another error with the cmdCheck but I had that in the while condition and it was not working either. while(userCommand.find("secq") < 0 ...
My inital thought was a problem with the input buffer but when I look at the userCmd variable in the Locals window I have a character array of size 1. There is only the letter and no junk from the buffer (as far as I can tell)
I know I could just tie a bunch of || together with each command but this is a bit more elegant in my opinion. I looked at my final last year and my conditionals were ugly. It's more of a matter of principle at this point.
The expression userCommand.find("secq") tries to find the string "secq" in userCommand. From the sounds of it, you actually want to do the exact opposite, i.e., find the userCommand in the string "secq":
std::string::size_type cmdCheck = std::string("secq").find(userCommand);
while (cmdCheck == std::string::npos) {
...
}
Also note that std::string doesn't return an int. Instead it returns a std::string::size_type. This may be a typedef for int but it may also be a typedef for a different integer type. If the string being passed to find() can't be found, std::string::npos is returned. The exact value for this constant is also not defined so you are best off comparing to this constant instead of making any assumptions.
I'm guessing that userCommand is an std::string. Since the command is supposed to be a single character, use a char instead of a string. Then just use the value as the argument in a switch statement, with appropriate cases for the valid characters and a default case that gives an error message.
Take input using getline in a string.
getline (cin, userCommand) ;
If the input is one letter, take it in a single char. If you insist on taking it in a string, use its first index to check.
Maybe a loop like this would be more appropriate:
char result;
std::cout << "Your command: ";
for (std::string line; ; )
{
if (!(std::getline(std::cin, line))
{
std::cerr << "Fatal error: Unexpected end of input!\n";
std::exit(1);
}
if (line.size() == 1 && line.find_first_of("secq") == 0)
{
result = line[0];
break;
}
std::cout << "Sorry, I did not understand. Please say again: ";
}
std::cout << "Thank you! You said, '" << result << "'\n";
Now if the loop breaks, result will contain the user input.