Usually I write a control loop as follows:
Loop that enters writes ints into vector nVec until "done" is entered.
while (cin >> sString){
if (sString="done")
{
break;
}
nVec.push_back(sString);
}
this works fine, but how would I go about doing this if I wanted the loop to end once the user entered nothing (just pressed enter)?
You can't "not enter anything" into your token-wise extraction. The only way for your loop to stop is for the user to send end-of-file (Ctrl-D on Linux). I would personally say that this is the correct behaviour, but if you want to end on empty input, you need to read lines:
Sales_item total;
for (std::string line; std::getline(std::cin, line); )
{
if (line.empty()) { exit_program(); /* or "break" */ }
std::istringstream iss(line);
for (Sales_item book; iss >> book; )
{
total += book;
std::cout << "The current total is " << total << std::endl;
}
}
This way, you tokenize each line into possibly multiple books. If you just want one book per line, rip out the inner loop and just say std::istringstream(line) >> book;.
Related
This might sound silly, but it's my first time solving programming contests on line. The problem is usually described as:
Input:
First line indicates the number of test cases t.For the next 't' lines the data is entered.
I've written the following program (with the correct headers included):
vector<string> read_strings(int t_cases) {
vector<string> ip_vec;
string line, str;
int cnt = 0;
while (cnt != t_cases-1) {
std::getline(std::cin, line);
++cnt;
}
std::istringstream iss(line);
while (iss >> str) {
ip_vec.push_back(str);
}
return ip_vec;
}
But this program always gets stuck in an input loop. I've also tried to parse the line as soon as it's entered by putting iss in the first while loop. If anyone could provide me a pointer on how to solve this problem, I will be able to finally test the rest of the program.
Thanks.
You need to add the lines to the vector as they are read. The first while loop is reading through all the test cases, but is not saving them somewhere. Then next while loop tries to reads line, which is the last test case read. Try the following:
vector<string> ip_vec;
string line, str;
for (int cnt = 0; cnt < t_cases; cnt++) {
std::getline(std::cin, line);
ip_vec.push_back(line);
}
Since you're starting to learn how programming contests work, I wouldn't recommend you to store all the input given. In general, you can store the number of inputs t and for each test case, the program outputs the answer for that test before reading the next test case. For example:
for (int i = 1; i <= t; i++) {
cin >> input;
// Some computations specific to the problem
cout << output << endl; // Pay attention on how the problem wants the output to be printed.
}
If the problem doesn't give you the number of test cases, you can simply change the loop to:
while (cin >> input) {
// Computations...
cout << output << endl;
}
It's usually how I solve problems from programming contests.
EDIT: As noted by #AnkitKulshrestha, if there's more than one input that you have to read for each test case, you can simply read them like this (with three inputs, for example):
while (cin >> a >> b >> c) {
// Computations...
cout << output << endl;
}
if(inputFile.is_open()){
while(!inputFile.eof()){
getline(inputFile, line);
ss << line;
while(ss){
ss >> key;
cout << key << " ";
lineSet.insert(lineNumber);
concordance[key] = lineSet;
}
lineNumber++;
}
}
For some reason, the while loop is kicking out after the first iteration and only displays the first sentence of my input file. The rest of the code works fine, I just can't figure out why it thinks the file has ended after the first iteration.
Thanks
Firstly you should be reading the file without using eof , as πάντα ῥεῖ notes (see here for explanation):
while( getline(inputFile, line) )
{
// process the line
}
Note that the preceding if is not necessary either.
The main problem , assuming ss is a stringstream you defined earlier, comes from the logic:
ss << line;
while(ss){
// stuff
}
The while loop here only exits when ss fails. But you never reset ss to be in a good state. So although your outer loop does read every line of the file, all of the lines after the first line never generate any output.
Instead you need to reset the stringstream each time:
ss.clear();
ss.str(line);
while (ss) {
// stuff
}
In my simple Fraction class, I have the following method to get user input for the numerator, which works fine for checking garbage input like garbage, but will not recognize user input which starts with an integer, and is followed by garbage, 1 garbage or 1garbage.
void Fraction::inputNumerator()
{
int inputNumerator;
// loop forever until the code hits a BREAK
while (true) {
std::cout << "Enter the numerator: ";
// attempt to get the int value from standard input
std::cin >> inputNumerator;
// check to see if the input stream read the input as a number
if (std::cin.good()) {
numerator = inputNumerator;
break;
} else {
// the input couldn't successfully be turned into a number, so the
// characters that were in the buffer that couldn't convert are
// still sitting there unprocessed. We can read them as a string
// and look for the "quit"
// clear the error status of the standard input so we can read
std::cin.clear();
std::string str;
std::cin >> str;
// Break out of the loop if we see the string 'quit'
if (str == "quit") {
std::cout << "Goodbye!" << std::endl;
exit(EXIT_SUCCESS);
}
// some other non-number string. give error followed by newline
std::cout << "Invalid input (type 'quit' to exit)" << std::endl;
}
}
}
I saw a few posts on using the getline method for this, but they didn't compile when I tried them, and I'm having trouble finding the original post, sorry.
Better check as follows:
// attempt to get the int value from standard input
if(std::cin >> inputNumerator)
{
numerator = inputNumerator;
break;
} else { // ...
Or yes: Follow recommendations to parse a complete input line combining std::getline() and std::istringstream appropriately.
I recently bought a C++ Primer and got stuck with a problem. I have to read a sequence of words using cin and store the values in a vector. After having unusual problems, I found out that while(cin >> words) invites problems (like infinite loop) if you expect invalid inputs: Using cin to get user input
int main()
{
string words;
vector<string> v;
cout << "Enter words" << endl;
while (cin >> words)
{
v.push_back(words);
}
for(auto b : v)
cout << b << " ";
cout << endl;
return 0;
}
Therefore, I'm trying to find an alternative to this problem. Help ?
That link you provided regarding input problems is a little different. It's talking about when you expect the user to enter a particular value, but you might fail to read the value (let's say it's an integer) because something else was entered. In that case, it's good to use getline to retrieve a whole line of input and then parse the value out.
In your case, you're just after words. When you read a string from a stream, it will give you all consecutive non-whitespace characters. And, ignoring punctuation for a moment, you can call that a "word". So when you talk about 'invalid input', I don't see what you mean. The loop will continue to give you "words" until there are none left in the stream, at which point it will error:
vector<string> words;
string word;
while( cin >> word ) words.push_back(word);
However, if you expect the user to enter all words on one line and press enter to finish, then you need to use getline:
// Get all words on one line
cout << "Enter words: " << flush;
string allwords;
getline( cin, allwords );
// Parse words into a vector
vector<string> words;
string word;
istringstream iss(allwords);
while( iss >> word ) words.push_back(word);
Or you can do this:
cout << "Enter words, one per line (leave an empty line when done)\n";
vector<string> words;
string line;
while( getline(cin, line) )
{
// Because of the word check that follows, you don't really need this...
if( line.size() == 0 ) break;
// Make sure it's actually a word.
istringstream iss(line);
string word;
if( !(iss >> word) ) break;
// If you want, you can check the characters and complain about non-alphabet
// characters here... But that's up to you.
// Add word to vector
words.push_back(word);
}
How do I run the while loop until the end of line or null character reached.
Here is my code
#include<iostream>
using namespace std;
main()
{
char input[20];
cout<<"Enter a line: ";
cin>>input;
while(input!='\0')
{
cout<<"This is a text";
}
system("pause");
}
If you want to read until either a newline or a NUL, read one character at a time inside the loop.
#include<iostream>
int main()
{
char input;
std::cout << "Enter a line: " << std::flush;
while(std::cin >> input && input != '\n' && input != 0) {
std::cout << "This is a test\n";
}
}
Notes:
main requires a return type
Never, ever, say "using namespace std;"
Don't forget to flush if you want cout to appear immediately.
Notice the compound test in the while condition:
First, did the read succeed?
Next, is it not '\n' (one of your conditions).
Next, is it not NUL (the other of your conditions).
The body of the loop will be executed once per input character -- is that what you wanted?
But, consider if you have correctly specified your requirement. It is an unusual requirement -- why would there be a NUL in a text file, and why would you want to process each character individually?
In idiomatic C++, you can read the input file in a line at a time using std::getline:
std::string myString;
while(std::getline(std::cin, myString)) {
// process myString
}
If you just want to read in a single line:
std::string myString;
if(std::getline(std::cin, myString)) {
// process myString
}
Finally, if you want to read a line, and ignore its contents:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
try something like:
i = 0;
while ((input[i] != '\0') && i < 20)
{
cout<<"This is a text";
i++;
}
Like this:
std::string line;
if (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
else
{
// error, e.g. EOF
}
If you want to read multiple lines, use a while loop instead:
while (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
The issue is that you're reading an entire chunk of text at once and then printing it until the input is '\0'. However, you're never actually updating this inside the loop. You can either use cin inside the loop to get the input, OR if you're trying to output each character, you can index the char array.