standard input stream cin failing to prompt for input - c++

1 #include<iostream>
2 using namespace std;
3
4 int main()
5 {
6 const double yen_to_euro=0.007215;
7 const double euro_to_dollar=1.12;
8 char currency;
9 double x;
10
11 while(currency!='q')
12 {
13 cout << "enter currency and unit(y , e, or d)";
14 cin >> x >>currency;
15
16 switch(currency){
17
18 case 'y':
19 cout <<"euro:"<< x*yen_to_euro<<" dollar:"<<x*yen_to_euro*euro_to_dollar<<'\n';
20 break;
21 case 'e':
22 cout <<"yen:"<< (x*(1.0/yen_to_euro))<<" dollar:"<<(x*euro_to_dollar)<<'\n';
23 break;
24 case 'd':
25 cout <<" yen:"<< x*(1.0/yen_to_euro)*(1.0/euro_to_dollar)<<" euro:"<<x*(1.0/euro_to_dollar)<<'\n';
26 break;
27 case 'q':
28 currency='q';
29 break;
30 default:
31 cout << "invalid";
32 break;
33
34 }
35
36 }
37
38
39 }
~
The intended function of the code above is to convert a selected currency( y for Japanese Yen, e for Euro , and d for US dollar) into the other currencies.
For instance, if I want to convert to 12 Japenese Yen, I would enter:
12y
which then the program would output
euro:0.08658 dollar:0.0969696
However, if I were to input 12e, I would receive an infinite loop. Double checking the code, there doesn't seem to be any logical errors.
Nevertheless, I sense the source of the trouble has to do with the cin at line 14 because if I take the amount x and the currency type separately like this:
cin>> x;
cin>> currency;
The code works fine, but I need to input the amount , followed by pressing enter, and then pressing the character that represents the currency-type. Is there a way to just enter all in one line, no spaces?
Furthermore, why is it behaving this way? This unusual behavior of going through infinite loop only happens when I enter e for Euro and q for quit.

12e is interpreted as the begin of a floating point number like 12e03. But the end is missing, so your stream is put on error (failbit). This state causes all subsequent input to fail until the failstate is cleared.
You could have an inner loop that checks such formatting errors:
while (...) {
...
while ( (cin >> x >> currency).fail() && !cin.eof()) { // loops as long as there's input and it's invalid
cout << "invalid format";
cin.clear();
}
if (cin.eof()) // if there's no longer input stop looping
break;
...
}
live demo
Note that you should initialize currency to something different than 'q' if you want to make sure that your loop is executed in every circumstance.
By the way, if you enter 12 e (with a space), 12 will be interpreted as the number and put to x and e to currency, as you expect.

As explained by other answers 12e refers to the scientific notation of floating point numbers and hence currency does not store 'e'.
To get the input in a single line without space, you should use std::getline and then parse the input string.
Since you know that the last character is always indicative of currency, the front characters can be converted to a number using std::stoi.

Replace cin >> x >>currency;
with
try{
std::string myLine;
std::getline (std::cin, myLine); // store line into myLine.
currency = myLine.back(); // get last character from line.
myLine.pop_back(); // remove last character from myLine.
x = std::stod(myLine); // try to conver the rest of the string to a double.
}
catch (...) {
//The user typed in something invalid.
currency= 'i';
}
Also, make sure to #include <string>
Note this solution assumes you are using C11.

Related

How to manipulate stdout?

For example, when using GitHub CLI, they prompt you like so:
Do something? (Y/n)
and if you were to input n and press 'Enter', then that output would change to:
Do something? No
'Next line's content'
I would like to do something similar in my program.
In my use case, it would look like:
Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4:
where the user inputs the integers, presses 'Enter', and is now on Row 4: .
Upon the user pressing 'Enter', I would like it to transform into:
Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4: N/A
or, preferably:
Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
but I am not sure how to do this, since the user hitting 'Enter' would put std::out at the new line, and if I were to print out N/A, it would look like:
Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4:
N/A
Terminal applications do this by sending special control characters to the terminal (this is an extremely old school API!). Libraries like ncurses and external tools like tput can make the arcane incantations for you, but it's not too hard to do yourself.
In this case, once the user presses Enter, you want to move the cursor back up to the start of the previous line, clear the rest of the line, and write what you want instead.
#define ESC_PREV_LINE "\e[F"
#define ESC_CLEAR_TO_END "\e[K"
std::cerr << "Row 4: " << std::flush; // traditionally, interactive prompts appear on stderr! this makes it easy to separate the "real" output of a program from the interactive part to e.g. save in a file
// read input...
if(need_to_rewrite_input) {
std::cerr << ESC_PREV_LINE ESC_CLEAR_TO_END "Row 4: 7 8 9\n";
}
You may want to check at the start of the program that cerr actually refers to a terminal, and either use a fallback behavior or just die if it's not.
One option is to use a library like ncurses. That is particularly relevant if, for example, you want to overwrite output on multiple lines preceding the cursor.
If you're looking for something more basic (as in, only affect output on the last line, and without much error checking, and without relying on escape codes that are often device specific) you can do something like
const std::string yesno = "(Y/n)"
char input;
std::cout << "Do something? " << yesno << " ";
std::cin >> input;
if (std::toupper(input) == 'Y')
{
for (std::size_t i = 0; i < yesno.length() + 2; ++i)
std::cout << "\b \b";
std::cout << 'Y';
std::cout << std::endl;
}
// code that produces next line of output
The loop backs up an overwrites characters on the last line, one at a time. The magic number 2 in the loop comes from the need to overwrite the space character and the single character entered by the user.
The downside of the above is that it ASSUMES the user enters exactly one character before hitting the enter key. There is no way to prevent the user doing something different (e.g. a user may happily enter YYYY before hitting the enter key).
To deal with that, one can do
If you want to relax that assumption the following is possible
const std::string yesno = "(Y/n)"
std::string input;
std::cout << "Do something? " << yesno << " ";
std::getline(std::cin, input);
if (input.length() > 0 && std::toupper(input[0]) == 'Y')
{
for (std::size_t i = 0; i < yesno.length() + input.length() + 1; ++i)
std::cout << "\b \b";
std::cout << 'Y';
std::cout << std::endl;
}
// code that produces next line of output
This will cope with the user entering YNYN before the enter key, by checking only the first character entered, and ignoring (and overwriting) the rest.
Both of the above do assume that outputting a space character will overwrite the character at the cursor position). But default settings of most modern terminals or consoles (hardware device or emulator in a windowing system) are consistent with that assumption. There are some old devices (largely obsolete, and now rarely seen outside historical displays or museums) for which that assumption is not true [and ncurses will often not detect, let alone properly handle, such devices either].
The other assumption made is that the terminal width exceeds the length of user input. So, if the terminal/window width is 80 characters, it is assumed the user will not enter 80 or more characters before hitting the enter key.

Is cin.get() reading multiple digit characters at once?

We were asked to write a simple C++ program by our teacher to add two numbers in the following format:
input: 12 14
output: m+n = 26
The program must also work for other inputs in the form:
input: Hello please add 12 and 14 !
output: m+n = 26
The solution that was given was:
#include <iostream>
using namespace std;
int main(){
int m,n;
char ch;
while(cin.get(ch)){
if(isdigit(ch))
{
cin.putback(ch);
cin>>m;
break;
}
}
//cin.putback() restores the last character
//read by cin.get() back to the input stream
while(cin.get(ch)){
if(isdigit(ch))
{
cin.putback(ch);
cin>>n;
break;
}
}
cin.ignore(80,'\n');
cout<<"m + n = "<<m+n<<endl;
return 0;}
But now I need to know why this program also works for numbers that are not single digits. Shouldn't cin.get(char) just read one digit and cin.putback() return the same? Please help me I am a beginner.
Yes, cin.get() will read only one character at a time.
The important part, where the number is actually read, is 4 lines below: cin>>m;. This will consume as many digits as possible and store the resulting integer in m.
Some more details:
// example with input 524 42
while(cin.get(ch)) // extract one character at a time
{ // ch='5', remaining input="24 42"
if(isdigit(ch)) // if it's a digit (0-9), then:
{
cin.putback(ch); // Put it back into the stream, "unread" it
// remaining input="524 42"
cin >> m; // extract an integer from stream
// m=524, remaining input="42"
break;
}
}
The reason for the loops seems to be to skip over any non-numeric input before a number appears. Note that there is a little bug here, since it will also ignore leading signs. (e.g. input -4 4 will output m + n = 8)

std::cin with more complex objects

I have a text file which first describes some lines and then describes some colorful lines:
1 2 3 4
5 6 7 8
9 10 11 12
red 1 0 0 1 2 3 4
green 0 1 0 5 6 7 8
blue 0 0 1 9 10 11 12
The number of lines in each section is unknown at time of execution
I overloaded the std::cin >> operator for these structs:
struct Point { int x, y; }
struct Line { Point a, b; }
struct Color { float r, g, b; std::string name; };
struct ColorfulLine { Line line; Color color; };
(Full example here: http://ideone.com/bMOaL1 [already works - edited according to the accepted answer])
Now I need to iterate over the file using Lines and ColorfulLines:
Line line;
while(cin >> line) { cout << "We've got a line!\n"; }
ColorfulLine color_line;
while(cin >> color_line) { cout << "We've got a colorful line!\n"; }
// actually I'm putting them into std::lists but I skipped this part for simplicity
And here is the problem - the colorful lines are never fetched, i.e. the second loop is not executed.
I have an assumption why it happens but don't know how to fix it:
When std::cin tries to fetch the 4th Line, it fails because instead of a number there's the string "red".
Next, in the second while loop, std::cin tries to read a string (Color.name) but it sees a number, and then fails too.
I tried to put some random word before the ColorfulLines section hoping that when the first loop fails, the second will start reading from the "red" string, but it didn't.
How to fix this?
After the first loop breaks, std::cin is in a bad state. That's why the loop breaks in the first place. Performing reads on a bad stream fails immediately, thus the second loop is never entered.
To solve this, reset the error state after the first loop breaks with
std::cin.clear();

cin >> val sometimes reads 0 depending on Ctrl-Z

I was trying to write a code in C++ in Windows using MinGW compiler, my code counts and prints the number of consecutive times a number occurs in a given set of input. The code is as follows:
#include <iostream>
int main()
{
int c_val = 0,val = 0,cnt = 1;
std::cin>>c_val;
while(std::cin>>val){
if(val==c_val)
cnt++;
else{
std::cout<<c_val<<" occurs "<<cnt<< " times"<<std::endl;
c_val = val;
cnt = 1;
}
}
std::cout<<val<<" occurs "<<cnt<<" times";
}
INPUT: 42 42 42 12 13 13 ^Z (press Enter)
OUTPUT:
42 occurs 3 times
12 occurs 1 times
0 occurs 2 times
But if I press Enter before ^Z then it looks like:
INPUT: 42 42 42 12 13 13 (press Enter) ^Z (press Enter)
OUTPUT:
42 occurs 3 times
12 occurs 1 times
13 occurs 2 times
I want to know why the variable val in my code stores 13, when I use ^Z key after pressing my return key and why does it store 0 if I give the ^Z key along with my input.
Here is what happens. I observed this using MinGW-w64 4.9.2. The behaviour was the same whether running the executable in a Windows console, or under Cygwin (but not using cygwin-mingw).
Pressing ^Z at the beginning of a line sets the end-of-file condition
Pressing ^Z anywhere else actually sends ASCII 26 character to the stream
I also observed:
cin >> val sets val to 0 if it fails due to the input not containing a number.
cin >> val leaves val unchanged if input fails due to end-of-file.
According to this thread that is the correct behaviour specified by C++11.
So your results can be explained. When you input 42 42 42 12 13 13^Z, it is the same as if you had written 42 42 42 12 13 13x. The first six numbers are read, and then when x is encoutered, cin >> val fails and sets val to 0.
But when you press Enter and then ^Z, it is as if you were reading from a file and you reached the end of the file. cin >> val leaves val unchanged and it is still holding the value that it had after the last successful cin >> val.
If you make the change suggested by Gautam Jha suggested then you will get 13 in both cases. This is because he effectively reads into a temporary int, and then only stores the temporary int into the real val if the read succeeded, thereby avoiding the behaviour where a failed read sets val to 0.
This is probably the desired behaviour although you might also want to check cnt > 0 to avoid a weird output in the case of totally empty input.
See the difference
#include <iostream>
int main()
{
int c_val = 0,val = 0,cnt = 1;
std::cin>>c_val;
int curr_val = 0;
while(std::cin>>val){ // in case of no value cin will set val =0
curr_val = val;
if(curr_val == c_val)
cnt++;
else{
std::cout<<c_val<<" occurs "<<cnt<< " times"<<std::endl;
c_val = curr_val;
cnt = 1;
}
}
std::cout<<curr_val<<" occurs "<<cnt<<" times";
}

Getting input from external files?

I need to get very basic input from an external file in C++. I tried searching the internet a few times but nothing really applied to what I need. This would be a .txt file that the input it coming from, and it would be filled with lines like this:
131
241
371
481
I have code already to manually get this input, and it looks like this:
using namespace std;
//Gets the initial values from the user.
int control=0;
while (rowb!=0){
cout << "Row: ";
cin >> rowb;
cout << "Column: ";
cin >> columnb;
cout << "Number: ";
cin >> numb;
row[control]=rowb-1;
column[control]=columnb-1;
num[control]=numb;
control++;
}
This is part of a program that solves sudoko boards. The inputed numbers are the initial values that a sudoko board holds, and the user is inputing the row, column, and number that comes from a board.
What I need is to be able to create a .txt file with these numbers stored in rows so that I do not have to enter so many numbers. I have very little idea how to go about doing this. Mainly I'll only be using the txt file for testing my program as I move along with adding more code to it. It takes 150+ entered numbers within my program just to get a single board, and it takes a lot of time. Any accidentally wrong entered value is also a huge problem as I have to start again. So how would I get C++ to read a text file and use those numbers as input?
Aside from the other suggestions, you can simply redirect a file to standard input, like so (where $ is the command prompt):
$ myprogram < mytextfile.txt
That will run myprogram just as normal but take input from mytextfile.txt as if you had typed it in. No need to adjust your own program at all.
(This works on both Unix/Linux systems and on Windows.)
You can open a file for input with std::ifstream from the header <fstream>, then read from it as you would from std::cin.
int main()
{
std::ifstream input("somefile.txt");
int a;
input >> a; // reads a number from somefile.txt
}
Obviously, you can use >> in a loop to read multiple numbers.
Create an std::ifstream object, and read from it just like you would from std::cin. At least if I understand what you're trying to do, the 131 as the first input is really intended to be three separate numbers (1, 3, and 1). If so, it's probably easiest to change your input file a bit to put a space between each:
1 3 1
2 4 1
3 7 1
4 8 1
Personally, I would start with a different format of the file: enter a value for each cell. That is, each row in the input file would represent a row in the sudoko board. Empty fields would use a space character. The immediate advantage is that the input actually pretty much looks like the sudoko board. Also, you would enter at most 90 characters: 9 characters for the board and a newline for each line:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
int main(int ac, char* av[])
{
std::ifstream in(ac == 1? "sudoko.init": av[1]);
char board[9][9];
for (int i(0); i != 9; ++i)
{
in.read(board[i], 9).ignore();
}
if (!in)
{
std::cout << "failed to read the initial board\n";
}
else
{
typedef std::ostream_iterator<char> iterator;
std::fill_n(iterator(std::cout << "board:\n\n+", "+"), 9, '=');
for (int i(0); i != 9; ++i)
{
std::copy(board[i] + 0, board[i] + 9, iterator(std::cout << "\n|", "|"));
std::fill_n(iterator(std::cout << "\n+", "+"), 9, (i + 1) % 3? '-': '=');
}
std::cout << "\n";
}
}
This would take input like this:
4 5 3 8
71 3
16 7
6 4 7
6 8
1 9 5
6 42
5 94
4 7 9 3
Note that each of these lines uses 9 characters. You might want to use something more visible like ..