In the C++ Without Fear: A Beginner's Guide That Makes You Feel Smart book in chapter(8), part of a code trying to display a text file is the following:
while(1)
{
for(int i=1; i <= 24 && !file_in.eof(); i++)
{
file_in.getline(input_line,80);
std::cout<<input_line<<std::endl;
}
if(file_in.eof())
{
break;
}
std::cout<<"More? (Press 'Q' and ENTER to quit.)";
std::cin.getline(input_line,80);
c=input_line[0]; // <<<<<<
if(c=='Q'||c=='q')
{
break;
}
}
The part I'm not getting here is:
c=input_line[0];
I think it is put to read 'Q' or 'q'. But, why using this form (Array)? And, isn't there a way to read 'Q' or 'q' directly?
I tried std::cin>>c; but seemed to be incorrect.
Any ideas?
Thanks.
Because input_line is string ( array from chars), so input_line[0] gets the first letter - this is in case, that the user write "quit" or "Quit", not just "Q"
std::cin >> c; would be correct, if you enter just one char and press Enter
I tried std::cin>>c; but seemed to be incorrect.
That's correct, if c is a char.
You're right; reading an entire line just to extract a single character is bizarre. I recommend a book from this list.
You are getting the first character from the "array" into which the input line has been written.
NON-STANDARD solution, but works on windows platforms.
you can use getch() function defined in conio.h
example:
#include <conio.h>
...
char c = getch();
bye
Related
Sorry for the vague title but i really do not know how to describe the problem concisely..and the following is the simple codes:
#include <iostream>
using namespace std;
bool func(int a,char c,int b,int& result)
{
switch(c)
{
case '-':
result=a-b;
break;
case '+':
result=a+b;
break;
default:
return false;
}
return true;
}
int main()
{
cout<<"Usage:A {+|-} B"<<endl;
while(true)
{
int a,b,result;
char c;
cin>>a>>c>>b;
if(func(a,c,b,result))
{
cout<<result<<endl;
}
else
{
cout<<"Input Error!"<<endl;
}
}
return 0;
}
The right method to use the program is to input A {+|-} B.
For example,you can input 1[SPACE]+[SPACE]2[ENTER](which I mean "1 + 2" and then press ENTER) then it will spit out "3" for me.For the purpose of making the program more robust,I try to input 1[SPACE]+[SPACE]2[SPACE]+[ENTER] It just give me many "2" printed on the shell.Is there anyone who could tell me how to fix the bug?Many thanks!
PS:The codes is available at github:bug0x001.cpp
You fail to check if the input was read correctly. That's the first thing to do in a robust program. Also, if it failed, you should fix the input source. The endless stream of 2 is caused by a broken cin.
if( cin>>a>>c>>b &&
func(a,c,b,result))
{
}
else
{
cin.reset();
}
Your problem is that you are trying to get ints and char with cin, this is ok if you need that exact input, but crash when reading strange things (like a letter as int), as it reads garbage
The best solution (for me) is to read everything as a string (check cin.getline and stuff like that), then you "parse" the input as you whant, for example:
if you read "19+ 32 3" you can "easily" eliminate all spaces and split by any non numeric symbol, getting 3 strings: s1="19",s2="+" and s3="323", then you just parse each string as int (or whatever you need) and the symbol as char or whatever.
If you find anythng weird, you can try to understand it, eliminate it or just show an input error.
Is more complex than doing a cin.reset after testing, but allow you to "understand" more types of data input
cout << "Would you like to make another transaction? (y/n)" << endl;
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
while (repeat_transaction != 'y' && repeat_transaction != 'n')
{
cout << "Invalid selection: Please enter y or n";
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
}
During the Invalid selection loop, I once accidentally pressed "mn". I noticed the console read out Invalid selection..., So, it did in fact finish and re-enter the while loop. However, after this the console terminated the program. If you enter a single character 'a' or 'y' or 'n' it acts just as it should. Ending or not ending. This was before I attempted to use static_cast to force the truncation of the user input.
Since you managed to get this program to compile I can only assume that repeat_transaction was specified as a char and not a std::string.
When you use cin to get a character it only gets one character but it doesn't flush the buffer. I believe you understand this issue since you wrote This was before I attempted to use static_cast to force the truncation of the user input. . You can attempt to use cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); instead of static_cast<char>(repeat_transaction); after each call to cin >> repeat_transaction; . There are downsides to this. If you enter 'mn' it will work as expected. It reads the m which is not y or n and then flushes the extra characters until it finds end of line \n. If you do nm, n will match and the m will be thrown away. So in that case it will accept nm as valid and exit the loop.
There are other ways that may be easier and give you the effect closer to what you are looking for. Instead of reading a character at a time you can read an entire line into a string using getline (See the C++ documentation for more information). You can then check if the length of the string is not equal to 1 character. If it's not length 1 then it is invalid input. If it is 1 then you want to check for y and n. Although basic (and not overly complex) this code would do a reasonable job:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string repeat_transaction;
cout << "Would you like to make another transaction? (y/n)" << endl;
getline(cin, repeat_transaction);
while (repeat_transaction.length() != 1 || (repeat_transaction != "y" && repeat_transaction != "n"))
{
cout << "Invalid selection: Please enter y or n";
getline(cin, repeat_transaction);
}
return 0;
}
I said reasonable job since one deficiency you might see is that you want to trim white spaces from the beginning and end. If someone enters n or y with a space or tab in front it will be seen as invalid (whitespace at the end would be similar). This may not be an issue for you, but I thought I would mention it.
On a final note, you may have noticed I used using namespace std;. I did so to match what was in the original question. However, this is normally considered bad practice and should be avoided. These StackOverflow answers try to explain the issues. It is better to not do it and prepend all standard library references with std::. For example string would be std::string, cin would be std::cin etc.
I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.
This code is written in C++ and for reasons that I don't quite understand it is written twice.
I would expect that after inputting a random char it would display the char once and the String lower to it once as well. But I don't get this as output. What am I missing?
Solution: Adding a cin.ignore() statement disregards the return that is read in as well.
Making my code go through the loop once.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
char letter;
letter = cin.get();
while (letter!= 'X')
{
cout << letter << endl;
cout << "this will be written twice for ununderstandable reasons";
letter = cin.get();
}
}
Example:
If I were to write in cmd scrn c, I'd get a c back + twice the phrase this will be written twice for ununderstandable reasons. So what I thought to be the output
c
this will be written twice for ununderstandable reasons
is actually
c
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
as everyone already mentioned, cin will append the newline marker \n every time you hit enter. another solution is to place cin.ignore(); after every cin.get();.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
char letter;
letter = cin.get();
cin.ignore();
while (letter!= 'X')
{
cout<<letter<<endl;
cout<<"this will be written twice for ununderstandable reasons";
letter= cin.get();
cin.ignore();
}
}
You are reading every character with the unformatted get() function, including the newline character each time you hit return.
Depending on what you're trying to do, you could use formatted input (cin >> c) to skip all whitespace; or you could test each character and ignore things like newline that don't interest you; or you could use getline(cin, some_string) to read a whole line, and then process that.
When you type in a character the new-line character (from pressing enter) is also in your input buffer.
From the C-Reference:
The delimiting character is not extracted from the input sequence if found, and remains there as the next character to be extracted from the stream (see getline for an alternative that does discard the delimiting character).
Just use a cin.sync() after every cin.get() to clear the buffer and you should be good to go.
You forgot about the newline.
cin reads every character, which includes the newline you type after typing your character.
If you don't want this behaviour, you have to specifically check for newline.
while (letter!= 'X')
{
if (letter == '\n')
{
letter = cin.get();
continue;
}
cout<<letter<<endl;
cout<<"this will be written twice for ununderstandable reasons";
letter= cin.get();
}
The text 'this will be written twice..' will not necessarily print twice.
Type 'qwerty' + ENTER and your stream will have "qwerty\n" within and you'll see this output:
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
this will be written twice for ununderstandable reasons
Exactly that many as string "qwerty\n" has characters.
The problem is that
cin.get()
Puts all chars that you type into a stream/buffer (not your letter char) but handles one char every cin.get() invocation.
When you type 'abcXd' + enter - the program will print above line 3 times and stop on X.
It happens because cin.get() reads new-line character too. Try to press Enter without any symbols or type some string, like abc.
You need to handle it, e.g.:
while (letter = cin.get()) {
if (!isalpha(letter)) { continue; }
// handling user inputted alpha
}
Whenever I input a variable using cin, after one hits enter it automatically goes to a new line. I'm curious if there's a way to use cin without having it go to a new line. I'm wanting to cin and cout multiple things on the same line in the command prompt. Is this possible?
You can't use cin or any other standard input for this. But it is certainly possible to get the effect you are going for. I see you're on Windows using Visual Studio, so you can use, for example, _getch. Here's an example that reads until the next whitespace and stores the result in a string.
#include <conio.h> // for _getch
std::string get_word()
{
std::string word;
char c = _getch();
while (!std::isspace(c))
{
word.push_back(c);
std::cout << c;
c = _getch();
}
std::cout << c;
return word;
}
It's not very good. For example, it doesn't handle non printing character input very well. But it should give you an idea of what you need to do. You might also be interested in the Windows API keyboard functions.
If you want a wider audience, you will want to look into some cross-platform libraries, like SFML or SDL.
you can also use space for input instead of enter
something like this:
cin >> a >> b >> c;
and in input you type
10 20 30
then
a=10
b=20
c=30
As others have noted, you can't do this with cin, but you could do it with getchar(). What you would have to do is:
collect each character individually using getchar() (adding each to the end of a string as it is read in, for instance), then
after reading each character, decide when you've reached the end of one variable's value (e.g. by detecting one or more ' ' characters in the input, if you're reading in int or double values), then
if you've reached the end of the text for a variable, convert the string of characters that you've built into a variable of the appropriate type (e.g. int, double, etc.), then
output any content onto the line that might be required, and then
continue for the next variable that you're reading in.
Handling errors robustly would be complicated so I haven't written any code for this, but you can see the approach that you could use.
I don't think what you want to do can be achieved with cin. What you can do is to write all your input in one line, with a delimiter of your choosing, and parse the input string.
It is not possible. To quote #Bo Persson, it's not something controlled by C++, but rather the console window.
I can't comment but if you leave spaces between integers then you can get the desired effect. This works with cin too.
int a, b, c;
cin>>a; cin>>b; cin>>c;
If you enter your values as 10 20 30 then they will get stored in a, b, and c respectively.
just use the gotoxy statement. you can press 'enter' and input values in the same line
for eg. in the input of a 3*3 matrix:
#include<iostream.h>
#include<conio.h>
void main()
{clrscr();
int a[20][20],x,y;
cout<<"Enter the matrix:\n ";
for(int r=2;r<7;r+=2)
for(int c=2;c<7;c+=2)
{gotoxy(c,r);
cin>>a[r][c];
}
getch();}