The code in the cont function asks the user if they want to play my game again.
The code works when receiving proper character inputs such as 'y' or 'n' as well as their respective capital letter variants, and the else block works properly to loop the function if an invalid input such as 'a' or 'c' is entered.
However during a test run, an input of 'yy' breaks the code causing the program to infinitely loop, running not only this cont function but my game function as well.
choice is stored as a char variable. I am wondering why the code even continues to run upon inputting multi-character inputs such as 'yy' or 'yes'. What's interesting is 'nn', 'ny' and other variations of multi-character inputs that begin with 'n' causes no issues and properly results in the else if block running as intended. Which prints "Thanks for playing." then ends the program.
Can variables declared as char accept inputs greater than 1 character? Does it only take the first value? And if so why does 'yy' cause a loop rather than the program running as intended by accepting a value of 'y' or 'Y'? How can I change my program so that an input of 'yy' no longer causes issues, without specific lines targeting inputs such as 'yy' or 'yes'.
#include <iostream>
#include <string> // needed to use strings
#include <cstdlib> // needed to use random numbers
#include <ctime>
using namespace std;
// declaring functions
void cont();
void game();
void diceRoll();
// variable declaration
string playerName;
int balance; // stores player's balance
int bettingAmount; // amount being bet, input by player
int guess; // users input for guess
int dice; // stores the random number
char choice;
// main functions
int main()
{
srand(time(0)); // seeds the random number, generates random number
cout << "\n\t\t-=-=-= Dice Roll Game =-=-=-\n";
cout << "\n\nWhat's your name?\n";
getline(cin, playerName);
cout << "\nEnter your starting balance to play with : $";
cin >> balance;
game();
cont();
}
// function declaration
void cont()
{
cin >> choice;
if(choice == 'Y' || choice == 'y')
{
cout << "\n\n";
game();
}
else if (choice == 'N' || choice == 'n')
{
cout << "\n\nThanks for playing.";
}
else
{
cout << "\n\nInvalid input, please type 'y' or 'n'";
cont(); // calls itself (recursive function!!!)
}
}
void game()
{
do
{
cout << "\nYour current balance is $ " << balance << "\n";
cout << "Hey, " << playerName << ", enter amount to bet : $";
cin >> bettingAmount;
if(bettingAmount > balance)
cout << "\nBetting balance can't be more than current balance!\n" << "\nRe-enter bet\n";
} while(bettingAmount > balance);
// Get player's numbers
do
{
cout << "\nA dice will be rolled, guess the side facing up, any number between 1 and 6 : \n";
cin >> guess;
if(guess <= 0 || guess > 6 )
{
cout << "\nYour guess should be between 1 and 6\n" << "Re-enter guess:\n";
}
} while(guess <= 0 || guess > 6);
dice = rand() % 6+1;
diceRoll();
if (dice == guess)
{
cout << "\n\nYou guessed correctly! You won $" << (bettingAmount * 6);
balance = balance + (bettingAmount * 6);
}
else
{
cout << "\n\nYou guessed wrong. You lost $" << bettingAmount << "\n";
balance = balance - bettingAmount;
}
cout << "\n" << playerName << ", you now have a balance of $" << balance << "\n";
if (balance == 0)
{
cout << "You're out of money, game over";
}
cout << "\nDo you want to play again? type y or n : \n";
cont();
}
void diceRoll()
{
cout << "The winning number is " << dice << "\n";
}
Does it only take the first value?
Yes, the >> formatted extraction operator, when called for a single char value, will read the first non-whitespace character, and stop. Everything after it remains unread.
why does 'yy' cause a loop
Because the first "y" gets read, for the reasons explained above. The second "y" remains unread.
This is a very common mistake and a misconception about what >> does. It does not read an entire line of typed input. It only reads a single value after skipping any whitespace that precedes it.
Your program stops until an entire line of input gets typed, followed by Enter, but that's not what >> reads. It only reads what it's asked to read, and everything else that gets typed in remains unread.
So the program continues to execute, until it reaches this part:
cin >> bettingAmount;
At this point the next unread character in the input is y. The >> formatted extraction operator, for an int value like this bettingAmount, requires numerical input (following optional whitespace). But the next character is not numerical. It's the character y.
This results in the formatted >> extraction operator failing. Nothing gets read into bettingAmount. It remains completely unaltered by the >> operator. Because it is declared in global scope it was zero-initialized. So it remains 0.
In addition to the >> extraction operator failing, as part of it failing it sets the input stream to a failed state. When an input stream is in a failed state all subsequent input operation automatically fail without doing anything. And that's why your program ends up in an infinite loop.
Although there is a way to clear the input stream from its failed state this is a clumsy approach. The clean solution is to fix the code that reads input.
If your intent is to stop the program and enter something followed by Enter then that's what std::getline is for. The shown program uses it to read some of its initial input.
The path of least resistance is to simply use std::getline to read all input. Instead of using >> to read a single character use std::getline to read the next line of typed in input, into a std::string, then check the the string's first character and see what it is. Problem solved.
cin >> bettingAmount;
And you want to do the same thing here. Otherwise you'll just run into the same problem: mistyped input will result in a failed input operation, and a major headache.
Why do you need this headache? Just use std::getline to read text into a std::string, construct a std::istringstream from it, then use >> on the std::istringstream, and check its return value to determine whether it failed, or not. That's a simple way to check for invalid input, and if something other than numeric input was typed in here, you have complete freedom on how to handle bad typed in input.
so this is one of the first bits of code I am trying to write without too much direction, however I seem to have hit a wall. I am attempting to write a very basic "MPG" application and one thing I have come to find is that when the application asks for user input it allows inputs such as "2d" or any alphanumeric input and it continues to operate as long as the digit is first. For example "2d will work but "d2" will not, and the application will carry on as if the letter is not there. ex. 2d/2=1. Here's the code.
#include <iostream>
#include <ctype.h>
int main()
{
float a, b;
char again = 'Y';
std::cout << "After several hours on the road you wonder what your gas mileage must have been..." << "\n";
while (again == 'y' || again == 'Y')
{
std::cout << "How much gas did you have in your tank to start with?" << "\n";
while (!(std::cin >> a))//cin for float a
{
std::cout << "Your input must be a number...1" << "\n";
std::cin.clear();
std::cin.ignore(1000000, '\n');
}
if (a > 0)
std::cout << "How many miles did you travel?" << "\n";
while (!(std::cin >> b))//cin for float b
{
std::cout << "Your input must be a number...2" << "\n";
std::cin.clear();
std::cin.ignore(1000000, '\n');
}
if (b > 0)
std::cout << "You have obtained an whopping " << b / a << " miles to the gallon!" << "\n" << "\n";
std::cout << "Would you like to try again? (Y/N): ";
std::cin >> again;
}
}
By default, numeric formatting starts with skipping whitespace and stops reading characters as soon as one character not matching the format of the read type is encountered. If a number could be read before such a character is encountered the read succeeds.
That applied to your example of entering "2d" means that 2 is successfully read as number and the next character to be read is d. If you want to catch that situation as an error, you can check what the next character in the stream is. If you require individual numbers to be read on lines without any spaces trailing the value, you can simply do something like this:
while (!(std::cin >> a) || std::cin.peek() != '\n') {
// ...
}
NOTE: SOLVED, problem was not getline() but find function with an
Improperly filled array!
I've looked up several questions before posting my own, but I could not find an answer for my problem. This is my first question posted, but I did do some research and tried other solutions from other questions before posting my own. So I am not entirely sure this isn't a duplicate. My apologies! Thank you for understanding in advance!
I am trying to use getline() (c++) to get user input. It works fine in my main, but does not in my user defined function. I thought it might have to do with the buffer, so i used cin.ignore() as suggested in:
C++ getline method not working
and i checked:
How does getline work with cin?
to make sure I properly understood getline(). However my program still does not work correctly.
My program takes English Text as a string from user input (console input) and converts it into Morse Code and outputs result as a string (console output).
basically my problem is this:
getline works in my main function for both strings and strings with spaces ex: "This" and "This Code".
However, in my user defined function, it ONLY works for strings without spaces ex: "This".
Thanks for the help! Code snippets below!
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[]);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
resultString = textToMorse(alphabet, morseAlphabet); // function where I use
// getline() but does not work
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
// does not work
string textToMorse(const string alphabet, const string morseAlphabet[])
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with strings without spaces,
//but breaks with others. ex: "This" works as input
//but "This code" breaks and the console seems to freeze
// then crashes out
cin.clear();
// rest of code, but program breaks before this.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
However if I edit my code and get the input from my main and pass it in as a parameter, it works.
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with both "This" and "This code"
cin.clear();
resultString = textToMorse(alphabet, morseAlphabet, userInput); //function modified
//to take one more
//parameter
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput)
{
//code, but program works.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
I didn't include all of the code, just the parts I felt were relevant to the question.
by works I mean:
getline successfully takes input. getline successfully assigns a string such as "this" and "this code" to the variable userInput when used in main function.
it only successfully assigns strings without spaces such as "this" when used in my user defined function. In that function, for some reason it does not work when I enter a string like "this code" or any string with a space inbetween.
note: program is not finished, as I plan to add other methods to do the reverse (as seen in code with
extra user options, but these are not yet implemented or defined, code still runs and compiles for problem I am facing.
The problem is that there is no morse code for a space.
Make a verification:
int n = alphabet.find(userInput[i]);
encodedEnglishText += (n == string::npos) ? " ": morseAlphabet[n];
Then it will work.
When you are looking for your input character in the alphabet string you won't find ' ' and std::string::find() return std::string::npos (normally -1 converted to the type std::string::size_type but the value isn't guaranteed). Using this value to index morseAlphabet won't do you much good: it is undefined behavior. This problem does not arise when you enter just one string as all characters are found in alphabet.
The proper way to deal with the situation is to look for the character and capture the result. Before using the result, you'd test the input, e.g.:
std::string::size_type pos(alphabet.find(userInput[i]));
if (pos == std::string::npos) {
// deal with the character not being part of the alphabet
}
else {
encodedEnglishText += morseAlphabet[pos];
}
Note that there are a few other things wrong with your program:
The selection of options should be inside the loop! The way it is implemented entering, e.g. 2 results in an infinite loop.
Using std::toupper() with a char can also result in undefined behavior! The problem is that std::toupper() expects a non-negative value of the value EOF but char may be signed. To avoid this problem you should use any of the functions from <cctype> or <ctype.h> with unsigned char:
userInput[i] = toupper[static_cast<unsigned char>(userInput[i]));
If the user doesn't enter an integer but, e.g., foo reading userSelection will fail and stream will get into failure state where it won't do anything until std::cin.clear() is entered. The best approach to deal with this situation is to test the result of reading the value before doing anything. If the input failed you can recover from the situation by clearing the status and skipping the offending character, e.g.:
if (std::cin >> userSelection) {
// use the selection
}
else {
std::cout << "ignoring invalid input\n";
std::cin.clear();
std::cin.ignore();
}
Note that your use of std::cin.clear() should be needed. Also, you should verify that the input you read with std::getline() is successful: in general, all user inputs should be tested for success.
If you enter a space character after the integer when reading userSelection, your call to std::cin.ignore() will ignore this space not the newline! To avoid this problem you could either read all charactors up to the first newline or skip all whitespace prior to the non-whitespace character:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // all till newline
std::cin >> std::ws; // skip all whitespace to first non-whitespace character
Do not use std::endl! It does not only create a newline but it also flushes the stream. This can easily create a performance problem.
You should probably pass std::string arguments by reference rather than by value. Passing the argument alphabet by value creates a copy with is inefficient (the morseAlphabet argument is passed by pointer although it looks like an array).
Some string literals seem to be split across multiple lines. Doing so is illegal (I guess, however, that this problem was introduced when pasting the code to the question above at some point).
I actually wrote a function to convert string into ascii values.
However I managed to confuse my self and don't understand why my own code works.
here it is:
void convertToString()
{
char redo;
int letter;
int length;
do {
cout<< "How long is your word \n";
cin >> length;
cout << "Type in the letter values \n";
for (int x = 0; x < length; x++) {
cin >> letter;
cout << char (letter);
}
cout << "\n To enter another word hit R" << endl;
cin >> redo;
} while (redo == 'R');
}
In the terminal I can type in all the ASCII values I want with out changing line, however I though this would cause a problem, anyways my question is, is hitting the enter button the same as hitting space? if not i dont understand how my code is able to print out the chars since i write it all in one line...Does it assign the interger "letter" a new value everytime there is a space?
Please help/explain
This is to expand a bit on what Igor said in his comment and to give a little example.
As Igor said, istream::operator>>(&int) will read non-whitespace. This means for each call on the operator, it scans along the input stream (what you typed in) for non-whitespace and reads until the next whitespace again. The next call will pick up where you left off. So, entering a space or a newline is exactly the same for this situation where you're taking in an int.
You can verify this with a simple bit of code that scans until EOF:
#include <iostream>
int main()
{
int number;
while (std::cin >> number)
{
std::cout << number << std::endl;
}
return 0;
}
This will wait for user entry to be complete (pressing enter), but print a new line for each integer in your input as separated by whitespace. So "1 2 3 4" will print each of those numbers on separate lines, regardless of if you separate them with spaces, tabs, or newlines.
Title probably sounds confusing so first I'll show you my code, I made this simple program to get two input values and multiply them, and another thing, but that's not important, It works correctly:
#include <iostream>
using namespace std;
main()
{
int a,b,c,d,e;
char j = 4;
cout << "Welcome to Momentum Calculator\n\n";
cout << "------------------------------\n";
cout << "Please Enter Mass in KG (if the mass in in grams, put \"9999\" and hit enter): \n\n";
cin >> a;
if (a==9999) {
cout << "\nPlease Enter Mass in grams: \n\n";
cin >> d;
}
else {
d = 0;
}
cout << "\nPlease Enter Velocity \n\n";
cin >> e;
if (d == 0)
{
c = (a*e);
}
else {
c = (e*d)/100;
}
cout << "\nMomentum = " << c;
cin.get();
cin.ignore();
while (j == 4)
{
cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
main();
}
}
Now as you can see, my variable is an int (integer) and my problem is If I enter an English letter (a-z) or anything that is not a number will cause it to repeat my program unlimited times at an unlimited speed. I want a string/char to see if my var "a" is a letter or anything but don't know how to. I can do it, however, I want user to input only one time in "a" and mine makes him to enter again. Please Help :)
There is a function called isalpha in ctype library, checks whether your variable is an alphabetic letter so you can do using isalpha function.
Will isdigit or isalpha from standard library help you?
P.S.
1KG contains 1000 grams, so you should divide by 1000, not by 100;
UPDATE:
Seems I understood your question...
You need cin.clear(); before cin.get() and cin.ignore().
Otherwise the these calls won't do anything, as cin is in an error state.
I think you can get a as an String, and see if it contains English letter or not, if it contains, again ask for the input ( you can do it in a while loop ). And when a correct input entered, parse it and find what is it's number.