I am working on a class project where I have to create an ordering system for a coffee shop in C++. If it is applicable, I'm working in Visual Studio.
In the project outline, the teacher said that there is a simple integer input to navigate the menu; however, he specifies that if NOTHING is inputted (I'm assuming what I've seen called a "hot enter") that it calculates the receipt and the program resets.
I have tried cin.get() and checking if the buffer is '\n', and this works fine, but my current implementation seems to only be able to capture a hot enter, and fails to roll into the switch case.
For getting input from the user, I've currently tried this:
// Get menu input
if (cin.get() == '\n') { // Check if user hot entered, assign value if so
input = 0;
} else { // If not, do it normally
input = cin.get();
}
However this does not work quite right, and fails to capture inputted integers for use in the switch case. I'm unsure if this sort of implementation is sound in reasoning, or whether there is a much simpler route to have a case for a hot enter.
I don't receive any errors, so I imagine there is something wrong with my understanding of how these functions work, or my implementation is flawed in its logic.
Thank you.
You used cin.get() twice. The second cin.get() in input = cin.get(); is redundant.
// Get menu input
input = cin.get();
if (input == '\n') { // Check if user hot entered, assign value if so
input = 0;
}
//else { // If not, do it normally
// input = cin.get();
// }
Related
this is my code
#include <conio.h>
#include <iostream>
using namespace std;
int main() {
bool a = false;
char b='p';
int c=0;
while (a != true) {
if (_kbhit()) {
b = _getch();
}
if (b=='w') {
c++;
cout << c << " ";
}
else if (b == 'c') {
cout << "hello";
}
}
system("pause");
return 0;
}
The problem is where when I press 'w' I want it to print out the value of c and it should be repeating until i press another input for _kbhit() right? because now it add 1 to c then prints c and when i press w again samething. What's wrong with my visual studio I'm using community 2017 I've tried to uninstall it and install it again but same problem occurs.
The problem you're running into seems to be a result of a recently added bug in _getch()/_kbhit.
For an extended key (e.g., a cursor key) it's documented that _getch() returns either a 0x0 or 0xe0 followed by the scan code for the key that was actually pressed. What's not documented is that if the user presses a non-extended key, _kbhit will still return true twice in succession, and calls to _getch() will return the key code the first time, and 0x0 the second time.
In your code, when the user presses 'w' or 'c', _kbhit will return true not just once (as you'd expect) but twice. The first time you call it, it'll return the scan code of the key, and the second it'll return a 0 byte.
What's happening in your code is that you're reading the scan code, printing something appropriately, then _kbhit is returning true again, so you read the '\0' byte, set b to '\0', and then (since you don't have any code to do anything when b is 0) you (repeatedly) do nothing until the next time the user presses a key.
Reference
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=vs-2017
It seems like the program behaves the way you want it to. If I press 'w', it goes into an infinite loop of increasing the value of c and printing it. Pressing any other key stops printing and pressing 'c' goes on the same infinite loop and prints hello. Doesn't seem to be any problems as far as the posted code is concerned. Also, I would like to say the same as #Someprogrammerdude, if it compiles, but doesn't behave the way you want it to, it's an issue with the code, not the IDE and/or compiler.
Hypothetical answer: Your computer might always be thinking that a key is pressed, thus kbhit() always returns true. This maybe caused by a bad mouse/keyboard/controller driver and/or configuration. The code is fine, your PC is not.
I'm learning C++ and have a few questions.
This program should take inputs for the name and price of items and output them to a text file. When the sentinel value 999 is entered for the item name, the while loop should cease and output all sets of inputs (item name and price) to the text file.
I have two problems with this program:
Only the most recent set of inputs (name, price) is displayed. How do I keep all inputs in memory?
Entering 999 for the item name does not cause the program to exit. Instead, the program ceases to display prompts. How do I stop the program correctly?
I should probably use a for loop, but I'm not sure how that would be implemented.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string item_name;
double price;
int item_number;
const string SENTINEL = "999";
ofstream myfile ("invoice1.txt");
while(item_name != SENTINEL)
{
cout<<"Enter the name of the item."<<'\n';
cin>>item_name;
if (item_name == SENTINEL)
{
cin>>item_name;
myfile<<"Thank you for your entries"<<'\n';
myfile<<item_name<<"#"<<price<<endl;
myfile.close();
break;
}
else
{
cout<<"Enter the price of the item."<<'\n';
cin>>price;
}
}
myfile<<"Thank you for your entries"<<'\n';
myfile<<item_name<<"#"<<price<<endl;
myfile.close();
return 0;
}
How to do this with a std::vector
First, a few includes:
#include <vector> // obviously. Can't do vectors without the vector header.
#include <limits> // for a trick I'll use later
Create a structure to link the item name with a price
struct item
{
string name;
double price;
};
and make a vector of that structure
vector<item> items;
Then after you read in a name and price, stuff it in a structure and stuff the structure into the vector.
item temp;
temp.name = item_name;
temp.price = price;
items.push_back(temp);
On why the while loop doesn't work... That'll take a walk through.
while(item_name != SENTINEL)
This is a good start. If item_name isn't SENTINEL, keep going. Exactly right. Thing is, item-name hasn't been set the first time you get here, forcing some squirrelly logic inside the loop. General rule of thumb is read, then test. Test before read is not so useful. For one thing, there's nothing to test, but the real problem is now you're using untested data or have to include another test to catch it.
Read, then test.
{
cout<<"Enter the name of the item."<<'\n';
cin>>item_name;
Get an item name. Groovy-ish.
if (item_name == SENTINEL)
{
cin>>item_name;
OK. Not bad, but why get another item_name here?
myfile<<"Thank you for your entries"<<'\n';
myfile<<item_name<<"#"<<price<<endl;
myfile.close();
break;
break exits a loop or a switch. So out we go.
}
else
{
cout<<"Enter the price of the item."<<'\n';
cin>>price;
Reading in numerical values has a few dangers you have to watch out for. The big one is if whatever the user typed can't be turned into price, cin goes into error mode and won't get back out until the error is cleared. And before you try to get price again, the garbage data needs to be removed.
A neat thing about cin >> x is it returns cin. This lets you stack commands. cin>>a>>b>>c>>d. cin, and all its streaming brethren, have a built in boolean operator you can use in tests. If cin is still in a good state, all of the reads completed successfully, it can be tested and will return true.
This lets you do stuff like if (cin>>a>>b>>c>>d) and test that all of the reads were good in one shot.
}
}
Applying read, then test, we get
while(cin>>item_name && // read in an item name
item_name != SENTINEL) // and then test that it isn't the sentinel
This goofy-looking bit of code is about the safest way to do this. It will even catch and exit cin comes to a sudden end. Doesn't happen all that often with cin, but this is a great way to test for the end of a file.
{
while (!(cin >> price)) // keep looping until the user gives a number
{ // if we're here, the user didn't give a good number and we have to clean up
// after them. Bad user. Bad. Bad.
As an aside, don't do this trick with a file. The file could have ended. You would have to test the file for end of file and exit here before continuing with the clean up.
// clear the error
cin.clear();
// throw out everything the user's typed in up to the next line
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// user got out of the while of doom. They must have entered a number.
Welllll actually, it just had to start with a number. cin >> is pretty dumb and will let 1234abcd through, taking the 1234 and leaving the abcd for the next read. This can leave you with some nasty surprises. In this case the abcd will wind up as the next item_name. what should have been the next item_name will become the next price and the bad ju-ju rolls on from there.
And now back to the code.
item temp; // make a temporary item
temp.name = item_name; // set the values correctly
temp.price = price;
items.push_back(temp); // put them in the list.
You can save a bit of work here by adding a constructor to item and using vector's emplace_back method. Look it up. Very handy.
}
And again without the running commentary:
while(cin>>item_name && // read in an item name
item_name != SENTINEL) // and then test that it isn't the sentinel
{
while (!(cin >> price)) // keep looping until the user gives a number
{ // if we're here, the user didn't give a good number and we have to clean up
// after them. Bad user. Bad. Bad.
// clear the error
cin.clear();
// throw out everything the user's typed in up to the next line
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// user got out of the while of doom. They must have entered a number.
item temp; // make a temporary item
temp.name = item_name; // set the values correctly
temp.price = price;
items.push_back(temp); // put them in the list.
}
Now you have a vector full of items to print. Stack Overflow is full of examples on how to do this, but it's best if you take a shot at it first.
Why do you have an extra cin call inside the if statement checking the entry?
I think that is not necessary.
For the issue with your inputs you are only storing the most recent entered values because each time the loop runs again it will over write the variables.
To solve this you will need to use an array to store items. If you want to make it so that you can run the loop an enter as many inputs as needed you will need to implement a dynamic array.
Here is how to implement a dynamic array http://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/
As of now, I'm making a program with different screens that use the escape key to exit, but what happens is if I press escape in, lets say the option menu. And then I go into the game, which the game allows escape to exit out, it will automatically leave the game. If that makes sense. :), but, it seems like the escape key floats around in the input buffer, and I tried many ways to clear it but I can't find a way. Here is a part of my code.
int Controls()
{
// Allows us to get a key when pressed
int Key;
Key = _getch();
switch(Key)
{
// Number 27
case KEY_ESCAPE:
do code...
break;
}
return Key;
}
Try doing a
fflush(stdin);
whenever you transition to any new page. It clears the input stream.
Here's one of the return 0; sections I have in my main() function:
cout << "Would you like to remove a Pokemon? (Y/N): ";
cin >> removePokemonChoice;
cin.ignore(5, '\n');
if (toupper(removePokemonChoice) == 'Y')
{
deletePokemon();
cout << "New list:" << endl;
displayPokemon();
}
if (removePokemonChoice == -1)
return 0;
currently, it won't exit out of the program if the user enters -1. I can't use an else statement because I want the program to loop (there's a similar question after this bit that I want to come after) until -1 is entered.
Your program asks "(Y/N)" so I suppose removePokemonChoice is a char type... it is strange to expect -1 value from char data. By the way "-1" need 2 characters, so it must be string :-)
Think of it this way:
You're writing a program that asks you whether or not you want to remove a Pokemon. Normally, like in the actual game itself when Prof. Oak prompts you with a confirmation of do you want Charmander (and the answer is yes, you always go with the fire type, no exceptions). The choices the game will always give you is "Yes" or "No".
Would you ask a yes/no question and expect a numerical answer back? While it is true the compiler converts and does numerical stuff in the background, what you really should be thinking about is, is it intuitive to the user?
Suppose we have a menu which presents the user with some options:
Welcome:
1) Do something
2) Do something else
3) Do something cool
4) Quit
The user can press 1 - 4 and then the enter key. The program performs this operation and then presents the menu back to the user. An invalid option should just display the menu again.
I have the following main() method:
int main()
{
while (true)
switch (menu())
{
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
case 3:
doSomethingCool();
break;
case 4:
return 0;
default:
continue;
}
}
and the follwing menu():
int menu()
{
cout << "Welcome:" << endl
<< "1: Do something" << endl
<< "2: Do something else" << endl
<< "3: Do something cool" << endl
<< "4: Quit" << endl;
int result = 0;
scanf("%d", &result);
return result;
}
Entering numerical types works great. Entering 1 - 4 causes the program to perform the desired action, and afterwards the menu is displayed again. Entering a number outside this range such as -1 or 12 will display the menu again as expected.
However, entering something like 'q' will simply cause the menu to display over and over again infinitely, without even stopping to get the user input.
I don't understand how this could possibly be happening. Clearly, menu() is being called as the menu is displayed over and over again, however scanf() is part of menu(), so I don't understand how the program gets into this error state where the user is not prompted for their input.
I originally had cin >> result which did exactly the same thing.
Edit: There appears to be a related question, however the original source code has disappeared from pastebin and one of the answers links to an article which apparently once explained why this is happening, but is now a dead link. Maybe someone can reply with why this is happening rather than linking? :)
Edit: Using this example, here is how I solved the problem:
int getNumericalInput()
{
string input = "";
int result;
while (true)
{
getline(cin, input);
stringstream sStr(input);
if (sStr >> result)
return result;
cout << "Invalid Input. Try again: ";
}
}
and I simply replaced
int result = 0;
scanf("%d", &result);
with
int result = getNumericalInput();
When you try to convert the non-numeric input to a number, it fails and (the important part) leaves that data in the input buffer, so the next time you try to read an int, it's still there waiting, and fails again -- and again, and again, forever.
There are two basic ways to avoid this. The one I prefer is to read a string of data, then convert from that to a number and take the appropriate action. Typically you'll use std::getline to read all the data up to the new-line, and then attempt to convert it. Since it will read whatever data is waiting, you'll never get junk "stuck" in the input.
The alternative is (especially if a conversion fails) to use std::ignore to read data from the input up to (typically) the next new-line.
1) Say this to yourself 1000 times, or until you fall asleep:
I will never ever ever use I/O functions without checking the return value.
2) Repeat the above 50 times.
3) Re-read your code: Are you checking the result of scanf? What happens when scanf cannot convert the input into the desired format? How would you go about learning such information if you didn't know it? (Four letters come to mind.)
I would also question why you'd use scanf rather than the more appropriate iostreams operation, but that would suffer from exactly the same problem.
You need to verify if the read succeeded. Hint: it did not. Always test after reading that you successfully read the input:
if (std::cin >> result) { ... }
if (scanf("%d", result) == 1) { ... }
In C++ the failed state is sticky and stays around until it gets clear()ed. As long as the stream is in failed state it won't do anything useful. In either case, you want to ignore() the bad character or fgetc() it. Note, that failure may be due to having reached the end of the stream in which case eof() is set or EOF is returned for iostream or stdio, respectively.