Spotting / checking an end of a sequence in C++ - c++

I need to read an unknown length sequence of integers and then i need to find the longest monotonic subsequence in it. The sequence ends with EOF sign and its elements are to separated with spaces.
I'm not really bothering the algorytm of finding the subsequence now I'd like to make sure that I'm reading elements of the sequence in a right way. Below is a code which is supposed to do the job but there's a bug which I don't get right now.
#include <iostream>
using namespace std;
int main()
{
int sum=0;
int a=0;
cout << "Give me a number: ";
// while (!fin.eof()) {
while (cin >> a) {
cin >> a;
sum +=a;
cout << "Sum is: " <<sum << endl;
/* Thats the place where whole magic is supposed to happen.
I'm really confused however, because after entering i.e. 2 3 4 2 4
and pressing <Enter> five times shows an answer "The sum is <proper sum>"
and the answer "The final sum is: ... " doesn't show at all.
*/
}
cout << "final sum is : " << sum;
cout << "Hello world!" << endl;
return 0;
}
I'll be very grateful if anyone could answer my questions and explain if and where I'm wrong.
I'll appreciate any help!

Well, for one, you seem to be checking on the state of fin, but you never open that file and you never read from it. I'm guessing you meant to use std::cin everywhere, or fin everywhere; I'll stick to std::cin, but fin would work the same way.
The problem is that you first check for end-of-file and then read and use the data. This means that if the read failed, you aren't told about this. Instead of
while (std::cin) {
std::cin >> a;
sum += a;
}
use
while (std::cin >> a) {
sum += a;
}
This will still perform the check, but after the read, meaning that if the read failed, you don't go into the body of the loop, and don't use the (nonsense) data.
The fin case looks much the same:
std::ifstream fin("mydata.txt");
while (fin >> a) {
sum += a;
}
Note that there's no need to explicitly check for whether you reached the end of the file; checking the state of the stream will catch that error, as well as any errors due to being unable to parse a number. If instead we did
while (fin >> a, !fin.eof())
this would correctly handle the case where you read the whole file, but loop infinitely if it contained something other than a number.

First, decide whether you're reading from the file (fin) or the program's input (std::cin). Currently, you're reading from one and checking the other for eof.
If you're reading from the file, then you'll need to open it. Otherwise, remove fin to avoid confusion.
Then you should check for eof (and other error conditions) after attempting to read, and before using the result:
while (std::cin >> a) { // or `fin`, if that's where you're reading from
// your code using 'a' here
}

Related

Need some help finding a logical error in my while loop

I am learning C++, and I am doing some exercises in the book I am using. One of them asks to write a program that asks a user how many numbers they want to add up. Then prompt for the numbers the user wants to add or to enter '|' once finished. The numbers are then pushed into a vector. Part of the program asks to check if the size of the vector is equal to the original number of input items and that is where I keep getting an error.
cout << "Please enter the numbers and | once you are done: ";
while(true)
{
for(int num; cin >> num; )
{
if(num == '|')
{
break;
}
ints.push_back(num);
}
if(ints.size() != n)
{
cout << "There are more or less numbers in the vector than originally specified\n"
<< "Vector will be cleared; please re-enter the values: ";
ints.clear();
continue;
}
else
{
break;
}
}
The problem is that if the number of input is off, the message goes into an infinite loop and I am not sure how to fix it.
EDIT: n is the variable that holds in the number of values user wanted to enter.
Thanks!
num is an integer and cin >> num won't extract | symbol. Comparison num == '|' may not work as expected because num could have the numeric value of | ascii symbol even when user did not input any | symbol. You should properly handle end marker reading:
// loop will break when user enters `|` because it is not an integer
// setting failbit of cin
for(int num; cin >> num;)
{
ints.push_back(num);
}
cin.clear(); // reset failbit making cin able to read again
// check the end marker entered by user
{
string end_marker;
cin >> end_marker;
if("|" != end_marker)
{
// use of endl will flush the stream ensuring that
// printed text won't stuck in the buffer
cout << "Please use | as end marker" << endl;
continue;
}
}
Here is how I implemented it. I am worried about the logic in your while loop. I had been taught to avoid while(true) whenever possible. You know the logic behind how your code should work. With more practice you'll start to recognize the conditions you need to use. I am sure there are better ways to do it. But this is the way I tried it.
But to answer your question, the main reason it is failing is because integers cannot compare themselves with characters.
if(num == '|')
That does not work since num is an integer and not a character.
Normally I would implement this in a class and since global variables are not highly looked upon I created my own namespace. You'll have to finish the rest of the logic yourself however:
#include <iostream>
#include <vector>
#include <string>
namespace global
{
std::vector<std::string> strings;
std::vector<int> ints;
std::string a = " ";
int num = 0;
}
void doWork()
{
std::cout << "Please enter the number of integers you would like to add up: ";
std::cin >> global::num;
std::cout << "Please enter the numbers and | once you are done: ";
while (global::a != "|")
{
std::cin >> global::a;
global::strings.push_back(global::a);
}
global::strings.pop_back();
for(auto &e : global::strings)
{
global::ints.push_back(std::stoi(e));
}
}
int main()
{
doWork();
if(global::ints.size() != global::num)
{
std::cout << "Size of vector does not match the size specified. Clearing vector" << std::endl;
global::ints.clear();
global::strings.clear();
global::num = 0;
global::a = " ";
doWork();
}
}
I made a vector of char's and converted those into integers so that way you could add them up. The while loop should be checking for | rather than always running true. It then will check the size of the vector in the end, clear it if it does not match, and ask you to do it again. This is the best way that I could think of doing it.
EDIT: as VTT pointed out, char can only do one character at a time. I have converted it into a string in order to handle the conversion.
EDIT 2: reset the values of global::num and global::a to their default at the end of the failure in order to prevent crashing.

Why is this code exiting at this point?

I'm new to C++. I stumbled upon one tutorial problem, and I thought I'd use the few things I have learnt to solve it. I have written the code to an extent but the code exits at a point, and I really can't figure out why. I do not want to go into details about the tutorial question because I actually wish to continue with it based on how I understood it from the start, and I know prospective answerers might want to change that. The code is explanatory, I have just written few lines.
Here comes the code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
double average_each_student() {
cout << "\n>Enter your scores seperated by spaces and terminated with a period\n"
<< ">Note: scores after total number of six will be truncated.\n"
<< endl;
double sum = 0, average = 0;
int user_input, counter = 0;
const double no_of_exams = 6;
while(cin >> user_input) {
++counter;
if(counter < 5) sum += 0.15 * user_input;
else if(counter > 4 && counter < 7) sum += 0.20 * user_input;
}
return sum / no_of_exams;
}
int reg_number() {
cout << "Enter your registration number: " << endl;
int reg_numb;
cin >> reg_numb;
return reg_numb;
}
int main() {
vector<int> reg_num_list;
vector<double> student_average;
reg_num_list.push_back(reg_number());
student_average.push_back(average_each_student());
string answer;
cout << "\n\nIs that all??" << endl;
//everything ends at this point.
//process returns 0
cin >> answer;
cout << answer;
}
The code exits at cout << "\n\nIs that all??" << endl;. The rest part after that is not what I intend doing, but I'm just using that part to understand what's happening around there.
PS: I know there are other ways to improve the whole thing, but I'm writing the code based on my present knowledge and I wish to maintain the idea I'm currently implementing. I would appreciate if that doesn't change for now. I only need to know what I'm not doing right that is making the code end at that point.
The loop inside average_each_student() runs until further input for data fails and std::cin gets into failure state (i.e., it gets std::ios_base::failbit set).
As a result, input in main() immediately fails and the output of what was input just prints the unchanged string. That is, your perception of the program existing prior to the input is actually wrong: it just doesn't wait for input on a stream in fail state. Since your output doesn't add anything recognizable the output appears to do nothing although it actually prints an empty string. You can easily verify this claim by adding something, e.g.
std::cout << "read '" << answer << "'\n";
Whether it is possible to recover from the fail state on the input stream depends on how it failed. If you enter number until you indicate stream termination (using Ctrl-D or Ctrl-Z on the terminal depending on what kind of system you are using), there isn't any way to recover. If you terminate the input entering a non-number, you can use
std::cin.clear();
To clear the stream's failure stated. You might want to ignore entered characters using
std::cin.ignore(); // ignore the next character
or
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// ignore everything up to the end of the line
use cin.clear(); before cin >> answer; That will fix the problem. But you are not controlling the input. it just runs out to cin..

How do I check the type of data read on cin?

More specifically, I want to make sure this type is a double (or int/float). I have searched near and far and found pretty much zero non-rigorous solutions. I want to only use code that I can fully understand, being a complete beginner at C++.
In Java, I can simply do something like this:
ArrayList<Double> data = new ArrayList<Double>();
Scanner in = new Scanner(System.in);
while (in.hasNextDouble()) {
double x = in.nextDouble();
data.add(x);
n += 1;
sum += x;
}
double average = sum / n;
C++ is clearly a different story. Here's what I tried:
vector<double> data;
while (looping)
{
cin >> x;
if (typeid(x) != typeid(float) && typeid(x) != typeid(double) &&
typeid(x) != typeid(int))
{looping = false; break;}
data.push_back(x);
n += 1;
sum += x;
}
double average = sum / n;
This doesn't work. The loop keeps going as doubles are entered, but once I enter something that's not a double the code simply stops and doesn't advance onward. I'm pretty crestfallen. Any suggestions?
User doesn't "enter a variable". She enters a string. And operator >> when supplied with a float variable tries to interpret this string as a textual representation of a floating-point number.
It may or may not succeed: in Java, failure would cause nextDouble() to throw an exception. In C++, stream operations don't throw; instead failure means that cin.good() will start to return false.
float x;
cin >> x;
while (cin.good())
{
data.push_back(x);
n += 1;
sum += x;
cin >> x;
}
if x is declared as double, your if condition would fail and hence the while loop is broken
You have several solutions here. I will post 2 of them. The first solution needs c++11 standard due to stod function. You can do this passing -std=c++11 flag to gcc or clang++. Microsoft compiler enables c++11 by default.
Solution 1. It consists of reading in a string all the time through cin >> input_string and using standard c++11 function stod. stod stands for string to double. If stod fails to parse a double, it will throw an std::invalid_argument exception.
This solution would be like this:
#include <iostream>
#include <vector>
#include <numeric>
#include <string>
#include <stdexcept>
using namespace std;
int main() {
vector<double> vec;
string input;
try {
while (getline(cin, input)) {
vec.push_back(stod(input));
}
}
catch (std::invalid_argument &) {
cout << "Invalid argument caught\n";
//Failed to parse a double
}
//If pressed Ctrl+D (in linux, which sends EOF), failbit and eofbit are set
//If it is through invalid_argument the way the loop was exit, then,
//eof and failbit are not set and cin can be used without clearing.
double average = accumulate(vec.begin(), vec.end(), 0.0)/vec.size();
cout << "EOF: " << cin.eof() << endl;
cout << "Fail: " << cin.fail() << endl;
//Clean eof and failbit to be able to use cin again
cin.clear();
cout << "EOF after cleaning: " << cin.eof() << endl;
cout << "Fail after cleaning: " << cin.fail() << endl;
cout << average << endl;
}
EDIT: I tested and when you put more than one number per line it will just get the first one without throwing std::invalid_argument. It will throw an std::invalid_argument only when you start a line when the line starts with a non-double. This is because the stod function behaves like this: stod reference.
Note that this solution only allows to read one double per line.
Solution 2. Read using cin >> input_double directly. This can fail. Please note that iostreams don't use exceptios by default in c++. You can activate them with the api, but I don't recommend you to do it because you can manage all error handling locally.
You can read any number of doubles separated by any space characters:
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
using namespace std;
int main() {
double x = 0.0;
vector<double> data;
//cin will fail to read the first non-double in the input.
//You can input as many doubles as you wish. Spaces will
//be ignored. At the first non-double, cin will fail to read
//and will exit the loop, setting istream::failbit.
//Alternatively, you can send EOF (Linux is Ctrl+D) and the loop also will finish.
while (cin >> x) {
data.push_back(x);
}
double average = accumulate(data.begin(), data.end(), 0.0)/data.size();
//If you wanted to use again cin, you should:
//1. Clear failbit. You can do like this:
cin.clear();
//2. Cleaning the remaining input. Will stop when finding end of line.
string rubbish;
geline(cin, rubbish);
//cin is usable here again if you need it and with the input clean already.
cout << average << '\n';
}
You can give something like this in the input, in one line:
1 2.4 -38.7 5.8 28.9 hello.
What will happen? The loop will consume until 28.9, stopping at hello. After that, failbit is set. We clean failbit to be able to continue reading until the end of the line. Since hello is considered "rubbish" because we wanted to read doubles, we clean it with a getline and we can use cin again without trouble.

question concerning cin.clear()

I am just working through the book Accelerated C++. (My problem is located on page 57, if you guys have the book with you)
The problem is the following:
We do have a function which reads student grades:
...
while (in >> x) { // in and x are defined as an istream& and as a double
hw.push_back(x); // hw is vector defined as vector<double>&
}
in.clear();
...
Now, in book and also on the cplusplus.com refernce is stated that the clear function resets all the error states and that the input is now again ready to read some input.
The problem is that if I put a:
int a = 0;
cin >> a;
cout << a << endl;
after the function it jumps the cin and just gives me a 0. Did I understand the function of cin.clear() totally wrong or what can I do to get the cin active again.
As I had the same problem a while before I read the book, I know that I solved the problem back then with the following line:
cin.ignore( numeric_limits<streamsize>::max(), '\n');
Of course I then have to hit an extra enter key but it eats all the stuff which comes before and which makes the cin not to work.
The thing is that neither .clear nor .ignore work properly alone but using them both together I am able to enter something for the variable a;
EDIT: Ok, here is the whole code. This is something I have written myself, which is not from the book.
istream& in = cin;
int var = 0;
vector<int> vec;
while ( in >> var ) {
vec.push_back(var);
}
for (int f = 0; f < vec.size(); ++f) {
cout << vec[f] << endl;
}
cin.clear();
cout << "cleared" << endl;
int a = 0;
cin >> a;
cout << a << endl;
The call to clear clears the error state set by a failed read. It doesn't do anything with the characters that might be present in the input stream.
If the error state is a result of failing to read a double, it is likely that the next character will also fail as an integer.
If you try
char ch;
cin >> ch;
I'm sure that will work better.
Otherwise you will have to ignore some characters to get rid of the unreadable input.
The while loop in your code example reads integer values until the end of input or an error occurs while reading, e.g. giving a character that cannot occur as an integer digit like 'q'.
When an error occured, you might have a chance to recover from that error by calling clear() and then removing the offending character from cin's input buffer:
char dummy;
cin >> dymmy;
Then you can read an int again.

While loop with try catch fails at bad cin input

I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().
Thank you very much for any help
Please enter the first number: f
Sorry, I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?Sorry,
you d on't get any more tries. Press
any key to continue . . .
#include <iostream>
using namespace std;
int main(){
int entry;
int attempts = 1;
int result;
while(attempts <= 5) {
try {
cout << "\n\nPlease enter the first number: ";
cin >> entry;
if (cin.fail())
throw "Sorry, I don't think that's a number?";
if (entry < 0)
throw "Sorry, no negative numbers. Try something else? ";
cout << "\nNow the second number: ";
cin >> entry;
cin.clear();
cin.get();
}
catch (char* error) {
cout << error;
attempts++;
}
}
if (attempts > 5)
cout << "Sorry, you don\'t get any more tries.\n";
system("pause");
return 0;
}
You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.
Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.
(And yes, you probably should rethink your use of exceptions).
The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.
// Infinite loop for retrying until successful
while (true) {
// Ask the user something
std::cout << prompt;
// Read the answer (one full line)
std::string line;
if (!std::getline(std::cin, line))
throw std::runtime_error("End of input while expecting a value");
// Put the line read into iss for further parsing
std::istringstream iss(line);
int val;
// Read val from iss and verify that reading was successful and
// that all input was consumed
if (iss >> val && iss.get() == EOF) return val;
std::cout << "Invalid input, try again!\n";
}
It is fun to make a BASIC style input function out of this:
template <typename Val> void input(std::string const& prompt, Val& val) {
// (the above code goes here, slightly adjusted)
}
int main() {
int w;
double l;
input("Enter weight in kg: ", w);
input("Enter length in m: ", l);
std::cout << "BMI: " << w / (l * l) << std::endl;
}
Notes for the pedantics who were going to downvote me:
function input should be specialized for std::string
exceptions thrown by the input function should be caught in main
My Problem was to block char input to a cin >> number
This error caused an 'infinite' loop showing my prompt cout << prompt
with no way of exit but kill the process ...
The following shows what worked for me!
========================================
double fi_trap_d() // function to return a valid range double catching errors
{
double fi_game_sec;
//-------------------------------------------
do
{
fi_game_sec = -1;
cout << fi_game_sec_c;
//------------------------------
cin.ignore(); // (1)
//------------------------------
try
{ cin >> fi_game_sec; cin.clear(); } // (2)
catch (...) //out_of_range)
{
fi_game_sec = -1;
cout << " Dis am an error!\n";
// just loop back as we asked for a number
}
} while (fi_game_sec < 1);
//-------------------------------------------
return fi_game_sec;
}
========================================
Despite trying the " Dis am an error! " has NEVER shown up.
The key was (1) & (2) !
Exceptions should be used to handle exceptional, unexpected situations. Incorrect input from a user is neither unexpected nor exceptional -- it's more or less the norm. Personally, I tend to just ignore most bad input completely (when it can't be prevented). When (and only when) they enter something unusable repeatedly is it even worth pointing it out to them. As such, I'd tend to write the code something like:
char ch;
int attempts = 0;
std::cout << "Please enter the first number: ";
do {
cin >> ch;
attempts++;
if (attempts > 5)
std::cerr << "The only allowable inputs are '0' through '9'\n";
} while (cin.good() && !isdigit(ch));
int first_number = ch - '0';
This reads the input as a character, so it's always removed from the input stream. Then it attempts to validate the input, and if it fails, attempts to read again. Of course, you might want/need to get a little more elaborate, such as reading an entire line, attempting to convert it to a number, and reading another line if that fails.
Why are you doing this with exceptions? You're not going to kill the program on input, so you shouldn't throw an exception.
Just print out your error message and attempt to read in again.
It looks like you would be better off with iostream's native exceptions. Enable with
cin.exceptions( ios::failbit );
try {
…
} catch( ios_base::failure & ) {
cin.clear();
…
}
Never, ever throw an an object not derived from std::exception, and especially not a native type like char*.