time format hh:mm:ss input - c++

I am in a case when i am given two time formats hh:mm:ss to input.
I know that int variables exctract from cin until a non-integer is reached. This means that i can extract the hours easily, but then the character ":" would still be in the stream, which would cause a problem for the extraction of minutes.
I know i can use cin.ignore() but since i have to input two time formats, the code just for the input would result very long and not seem too good.
Just to give you an idea:
int h,m,s, h2,m2,s2;
cin>>h;
cin.ignore();
cin>>m;
cin.ignore();
cin>>s;
cin>>h2;
cin.ignore();
cin>>m2;
cin.ignore();
cin>>s2;
I know that cin automatically ignores whitespaces. Is there a way to make it automatically ignore a specific character (in this case, the character ":")?

An easy approach is create a colon() manipulator:
std::istream& colon(std::istream& in) {
if ((in >> std::ws).peek() == ':') {
in.ignore();
}
else {
in.setstate(std::ios_base::failbit));
}
return in;
}
You can then just extract the ':' characters:
in >> h >> colon >> m >> colon >> s;
Obviously, I'd create an input operator for times so I could then read the two objects using
in >> time1 >> time2;

For my case also I need time input in HH:MM:SS format. I solved that ':' input by using it as a delimiter for getline()function. I have attached that portion of code here.
const char delim = ':';
string hr_s, min_s, sec_s;
int hr, min, sec;
cout << "Enter HH:MM:SS : " << endl;
std::getline(cin, hr_s, delim);
std::getline(cin, min_s, delim);
std::getline(cin, sec_s);
hr = stoi(hr_s);
min = stoi(min_s);
sec = stoi(sec_s);
if ((hr_s.length() == 2) && (min_s.length() == 2) && (sec_s.length() == 2)&& (isValidTime(hr, min, sec)))
{
cout << "Good Time Format" << endl;
}
else
{
cout << "Bad Time format input"<< endl;
}
The method to check the validity of the numbers input:
bool isValidTime(int hr, int min, int sec)
{return (((hr >= 0) && (hr < 24)) &&
((min >= 0) && (min < 60)) &&
((sec >= 0) && (sec< 60)));}
Note: this code has no effect unless the user input some other character instead of ':'. For other case it should be fine. I am not sure if I answered your question or not but I hope this is helpful.

Related

While condition: How to allow comparison between non-integer/double user input and integer limits

Objective: Run a while loop that will repeat until the user inputs an integer between 1-3 (inclusive). So if an integer that is smaller than 1 or bigger than 3 is inputted or any character or string is inputted, the loop repeats.
My noob knowledge: I know how to compare user input when it is an integer, but when it is a char or string datatype input all I get is an infinite loop. Plus I declared the inputtable variable as an integer, so not sure how to go on about this.
I've done some Google searches but can't seem to find a question similar enough to mine.
Advice is highly appreciated :)
Code below:
int Decision1 = 4;
while ( Decision1 < 1 || Decision > 3)
{
std::cout << "Enter answer here: ";
std::cin >> Decision1;
std::cout << "\n\n";
}
int Decision1;
while(std::cin >> Decision1) {
if(Decision1 >= 1 && Decision1 <= 3) break;
// todo
}
You can use ASCII codes for checking number or character.
#include <iostream>
int main() {
char Decision1 = '0';
while ( (Decision1 < 49 && Decision1 >=47) || (Decision1 >51 && Decision1 <=57 ))
{
std::cout << "Enter answer here: ";
std::cin >> Decision1;
std::cout << Decision1;
std::cout << "\n";
}
}
I hope helpful for you.
Keep in mind: when you read input from std::cin you're reading text that's typed at the console. The stream extractor tries to convert that text to the target type. That is, in
int i;
std::cin >> i;
the >> operator looks for digit characters and figures out what value those characters represent. If the characters can't be converted to an integer value the extraction fails. Streams have a conversion to bool that tells you whether the stream is in a good state, or whether an attempted operation failed. So:
int i;
if (std::cin >> i)
std::cout << "got a value!\n";
To write a loop that prompts for valid input you need to reverse the test:
int i;
while (!(std::cin >> i) {
std::cout << "bad input\n":
// now clear the input stream, so it's back in a good state
}
To also check that the value is in the required range, just do it:
int i;
while (!(std::cin >> i) || i < 1 || i > 3) {
std::cout << "bad input\n":
// now clear the input stream, so it's back in a good state
}
To clear the input stream, you have to reset its internal flags. You do that with std::cin.clear();. And, depending on what you think was typed in, you probably want to get rid of any additional characters that the user typed. You do that with std::cin::ignore(std::numeric_limits<std::streamsize>::max(), '\n'). That tells the stream to discard character until it reaches a newline (press ENTER), or until it has read a huge number of characters.
Putting it all together:
int i;
while (!(std::cin >> i) || i < 1 || i > 3) {
std::cout << "bad input\n":
std::cin.clear();
std::cin::ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Yes, this clears the stream state and flushes the input when the input was a valid integer but out of range; that's harmless. It's a waste of time, but the speed of keyboard input is limited by how fast the user types, which is much slower than anything that the code in this loop does.

How to reject char inputs in cin and define minimum and maximum int values?

I have a program which has the ability to reject user input if a char is entered instead of an int, and this works almost perfectly - anything entered that isn't a number is being rejected.
However, all of these cins need to accept any value between a minimum and a maximum, but I can't get it to work. The code below shows my efforts so far, but there's a slight bug. If a char is entered, followed by an int that is out of range, and another char is entered (I like to test rigorously - I mean, who knows what could happen if an actual end user came across the problem) the program throws the final value of mortgageTerm out as 0.
Could anyone tell me where I'm going wrong and give me any pointers to help me fix it? Thanks in advance to anyone who's able to help me solve my problem!
int mortgageTerm;
string line;
cout << "Mortgage term (1 - 40 years) : ";
while (!(cin >> mortgageTerm))
{
cout << "That's not a valid choice! Try again : ";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
while (getline(cin, line))
{
stringstream linestream;
if (!linestream >> mortgageTerm)
{
cout << "Input was not a number! Try again : ";
cin >> mortgageTerm;
continue;
}
if ((mortgageTerm <= 0 || mortgageTerm > 40))
{
cout << "Input out of range. Try again : ";
cin >> mortgageTerm;
continue;
}
char errorTest;
if (linestream >> errorTest)
{
cout << "Invalid input. Try again : ";
cin >> mortgageTerm;
continue;
}
break;
}
cout << mortgageTerm;
You're almost there. Your first issue is your first while loop is not needed at all. Then we just need to tweak the second loop to make sure that all the input read was used in the value you get. We can also simplify it by using a single error statement, Making those changes gives you
int mortgageTerm;
string line;
cout << "Mortgage term (1 - 40 years) : ";
while (getline(cin, line)) // consume all input given
{
stringstream linestream(line); // you have to construct the stream from the string here
linestream >> mortgageTerm; // try and read the data
if (!linestream.eof() || mortgageTerm <= 0 || mortgageTerm > 40)
{
// either there is input left in linestream or the value is not in range
cout << "Invalid input. Try again : ";
}
}
Just check for the minimum and maximum in the same condition where you check if it was able to be converted into an int, using ||, in a condition the expressions are checked left to right in order, so the first did its work already when you evaluate the second and mortageTerm will have the value.
Edited to address comments.
int mortgageTerm;
cout << "Mortgage term (1 - 40 years) : ";
while (!(cin >> mortgageTerm) ||
mortageTerm < 1 ||
mortgageTerm > 40 )
{
cout << "That's not a valid choice! Try again : ";
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
}
// If you are concerned about extra input after the number and want to clear the input stream
// cin.ignore(std::numeric_limits<streamsize>::max(), '\n');

Incorrect sum when adding up numbers

Ok, here's the code to add indefinite numbers and present the sum in c++. But error is that addition taking place is of first number and the last digits of all the other numbers. For example if i want to add 30 + 40 + 55 + 70, my program counts 30 + 0 + 0 + 5 + 0 = 35. What am I doing wrong?
#include <iostream>
using namespace std;
int main()
{
int num = 0;
int sum = 0;
cout << "Please enter numbers you want to add and end with N or n: ";
for (;;)
{
cin >> num;
sum += num;
cout << endl;
char indicator ('q');
cin >> indicator;
if (( indicator == 'n') || (indicator == 'N'))
break;
}
cout << "The sum is: " << sum << " ";
return 0;
}
I'm not sure I fully understand what you are trying to do, but if you want to add a list of integers terminated by an N (or n) character, then you should read each entity as a string, see if it's the terminating character, and if it's not, then convert it to an integer:
int sum = 0;
while (true) {
std::string s;
std::cin >> s;
if (tolower(s[0]) == 'n')
break;
sum += std::stoi(s);
}
Of course, the above code is only a skeleton -- in production code, you should always check if I/O operations succeeded and sanitize your input. A more complete example would be:
std::string s;
while (std::cin >> s) {
int ch = s[0];
if (ch > 0 && tolower(ch) == 'n')
break;
try {
sum += std::stoi(s);
} catch (const std::invalid_argument &e) {
// handle conversion error
break;
} catch (const std::out_of_range &e) {
// handle out-of-range error
break;
}
}
When you read the indicator, you extract the next non-blank character from the input stream; if the user has entered a number, this is the first digit. There are several ways of working around this.
The simplest is simply to loop on:
while ( std::cin >> num ) {
sum += num;
}
The input will fail if the next input doesn't have the form of a number (without extracting it). (This also has the advantage that you don't use the input if it fails for some reason.) This is more or less the standard idiom.
If you really do want to check for the 'n', you can use std::cin.peek() to look ahead one character, without extracting it. This doesn't skip white space, however, so you might want to do std::cin >> std::ws first. In this case, you'd probably want to wrap it in a function:
bool
terminationRequested( std::istream& source )
{
source >> std::ws;
return source.peek() == 'n' || source.peek() == 'N';
}
and then
while ( ! terminationRequested( std::cin ) ) {
int num;
std::cin >> num;
if ( ! std::cin ) {
// error...
}
sum += num;
}
You still have to check for a possible error after std::cin >> num. Otherwise, if the user enters "a", you'll end up in an endless loop, adding an undefined value to sum.
Alternatively, another frequent idiom is too use putback to return the indicator to the stream:
while ( std::cin >> indicator && indicator != 'n' && indicator != 'N' ) {
std::cin.putback( indicator );
std::cin >> num;
if ( ! std::cin ) {
// error...
}
sum += num;
}
Again, you'll have to handle the errors somehow. Using num if std::cin >> num fails is undefined behavior.
It's because you read the indicator character which will remove and ignore the next input digit by the user from the input stream.

How to properly use cin.peek()

This function is supposed to read a fraction and place it in an array. If the user enters '0' the function is supposed to exit. I am trying to do this using the cin.peek() function but execution always goes into the if statement and doesn't allow the user to exit.
How should I properly code this (I am open to not using peek(), I thought it was the simplest way of doing it.)
Thanks!
void enterFrac(Fraction* fracs[], int& index)
{
int n, d;
char c, slash;
cout << "Enter fractions (end by entering a 0): ";
c = cin.peek();
if ( c != '0')
{
cin >> n >> slash >> d;
Fraction* f = new Fraction();
f->num = n;
f->den = d;
fracs[index] = f;
index++;
}
}
This test of peek() works however:
#include <iostream>
using namespace std;
int main () {
char c;
int n;
char str[256];
cout << "Enter a number or a word: ";
c=cin.peek();
if ( (c >= '0') && (c <= '9') )
{
cin >> n;
cout << "You have entered number " << n << endl;
}
else
{
cin >> str;
cout << " You have entered word " << str << endl;
}
return 0;
}
There are two issues with your use of std::istream::peek():
This function access the next character and does not skip leading whitespace. You probably want to skip leading whitespace before determining what the next character is, e.g., using the manipulator std::ws: (std::cin >> std::ws).peek().
The result from std::istream::peek() is not a char. Instead, it is an std::char_traits<char>::int_type (which is a fancy spelling of int). The result may, e.g., be std::char_traits<char>::eof() and if the value of '0' happens to be negative (I'm not aware of any platform where it is; however, e.g., the funny character from my name 'ΓΌ' is a negative value on platforms where char is signed) you wouldn't get the correct result, either. That is, you normally compare the result of std::istream::peek() against the result of std::char_traits<char>::to_int_type(), i.e., you'd use something like this: std::cin.peek() == std::char_traits<char>::to_int_type('0')
That said, your program doesn't check whether it could successfully read the nominator and the denominator, separated by a slash. You always want to verify that reading was successful, e.g., using something like
if ((std::cin >> nominator >> slash >> denominator) && slash == '/') {
...
}
Just for entertainment, you can create a manipulator for testing that a character is a slash, indeed:
std::istream& slash(std::istream& in) {
if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type('/')) {
in.setstate(std::ios_base::failbit);
}
return in;
}
This way, you'd encapsulate the test for slash. If you need to use this in multiple places this is quite handy.

Problem with input in c++

I have a very basic question i want to take integer input in certain range from user. if the user gives some string or char instead of integer. then my program goes to infinite loop.
my code is some what like that
cin >> intInput;
while(intInput > 4 || intInput < 1 ){
cout << "WrongInput "<< endl;
cin >> intInput;
}
I am only allowed to use c++ libraries not the c libraries.
As mentioned in the possible duplicate, you should check the state of cin on each loop.
Possible implementation:
if(cin >> intInput)
while(intInput > 4 || intInput < 1 ){
cout << "WrongInput "<< endl;
if(!(cin >> intInput)){ break; }
}
Very ugly code, just trying to illuminate the answer which is to check the state of cin.
The solution to this answer is to always read lines from the standard input.
std::string input; int value = 0;
do
{
// read the user's input. they typed a line, read a line.
if ( !std::getline(std::cin,input) )
{
// could not read input, handle error!
}
// attemp conversion of input to integer.
std::istringstream parser(input);
if ( !(parser >> value) )
{
// input wasn't an integer, it's OK, we'll keep looping!
}
}
// start over
while ((value > 4) || (value < 1));
#include <locale>
..
if(!isalpha(intInput)) {
..
}
Note, this won't work if, for example the user enters a "+" but maybe it will put you in the right direction..