This is the program:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main(){
string strKingdom = "";
bool conquered_me;//see if was conquered, was going to use this on other program and true = game over.
int gold;
int food;
int citizens;
int soldiers;
cout << endl <<"Name of kingdom: ";
cin >> strKingdom;
cout << endl << "were you conquered (true/false): ";
cin >> conquered_me;
cout << endl << "How many gold do you have?:";
cin>>gold;
cout << endl << "How many food do you have?:";
cin >> food;
cout << endl << "How many citizens do you have?:";
cin >> citizens;
cout << endl << "How many soldiers do you have?:";
cin >> soldiers;
return 0;
}
The problem is that when I compile it the progam only lets me insert the first 2 variables and then it shows the rest of the questions (after compile):
Name of kingdom: steve
were you conquered (true/false): false
How many gold do you have?:
How many food do you have?:
How many citizens do you have?:
How many soldiers do you have?:
Entering string "true" to the bool variable does not work. You should enter 1 or 0. Your "true" cannot be "consumed", so it's left in the buffer. Next, you're trying to read int value, so "true" also does not match. And so on... until the end of the program.
That's how I would do that:
#include <string>
#include <iostream>
#include <errno.h>
#include <stdlib.h>
using namespace std;
void askForString(string aPrompt, string &aValue) {
cout << aPrompt << " ";
cin >> aValue;
}
void askForBool(string aPrompt, bool &aValue) {
string tString;
while (1) {
cout << aPrompt << " ";
cin >> tString;
if (tString == "true") {
aValue = true;
break;
} else if (tString == "false") {
aValue = false;
break;
} else {
cout << "Repeat, please?" << endl;
}
}
}
void askForInt(string aPrompt, int &aValue) {
string tString;
char *endptr;
while (1) {
cout << aPrompt << " ";
cin >> tString;
errno = 0;
aValue = strtol(tString.c_str(), &endptr, 10);
if (errno || tString.c_str() == endptr || (endptr != NULL && *endptr != 0)) {
cout << "Repeat, please?" << endl;
} else {
break;
}
}
}
int main(void) {
string strKingdom;
bool conquered_me;
int gold;
int food;
int citizens;
int soldiers;
askForString("Name of kingdom:", strKingdom);
askForBool("were you conquered (true/false):", conquered_me);
askForInt("How many gold do you have?:", gold);
askForInt("How many food do you have?:", food);
askForInt("How many citizens do you have?:", citizens);
askForInt("How many soldiers do you have?:", soldiers);
cout << "Kingdom: " << strKingdom << endl;
cout << "Conquered: " << (conquered_me ? "true" : "false") << endl;
cout << "Gold: " << gold << endl;
cout << "Food: " << food << endl;
cout << "Citizens: " << citizens << endl;
cout << "Soldiers: " << soldiers << endl;
return 0;
}
Bring them all into strings, and convert as needed.
For some reason (probably compatibility with older code) iostreams default to converting true to 1 and false to 0 during I/O.
That's only the default though--there's a manipulator named boolalpha that will set the stream to use true and false (or localized equivalents) instead.
So, code like:
std::cout << 1 == 0; // produces `0`
std::cout << boolalpha << 1 == 0; // produces `false`
This also works for input, so you can change your code to something like this:
cin >> boolalpha >> conquered_me;
...and it should work as expected (and in: it should accept inputs of false or true, and produce values of false and true from them, and if it doesn't that's bug in the standard library).
None of your read commands check for error. ALL of them should be written as something like:
while (!(std::cin >> strKingdom)) {
std::cerr << 'Bad input' << std::endl;
std::cin.clear(); // clear the error
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the rest of the line
// output the same prompt again?
}
To make this easier, you might want to write a helper function:
template<typename T> void get_input(const char *prompt, T &result) {
std::cout << prompt << std::endl;
while (!(std::cin >> result)) {
std::cerr << 'Bad input' << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << prompt << std::endl; } }
You can then specialize that for bool types to read true/false properly...
This line:
cin >> conquered_me;
Should be like this:
cin >> boolalpha >> conquered_me;
Otherwise the input expects either a "0" or a "1".
By using boolalpha your input can be "true" or "false.
You need to employ std::getline and std::string to read the various values. (You can then use functions like atoi to parse them.) Here is your code sample using the std::getline function.
#include <iostream>
#include <string>
#include <cstdlib>
int main(){
std::string strKingdom = "";
bool conquered_me;//see if was conquered, was going to use this on other program and true = game over.
int gold;
int food;
int citizens;
int soldiers;
std::string tString = ""; // Used to read and subsequently parse the string.
std::cout << std::endl <<"Name of kingdom: ";
std::getline(std::cin,strKingdom);
std::cout << std::endl << "were you conquered (true/false): ";
std::getline(std::cin,tString);
conquered_me = (tString == "true");
std::cout << std::endl << "How many gold do you have?:";
std::getline(std::cin,tString);
gold = std::atoi(tString.c_str());
std::cout << std::endl << "How many food do you have?:";
std::getline(std::cin,tString);
food = std::atoi(tString.c_str());
std::cout << std::endl << "How many citizens do you have?:";
std::getline(std::cin,tString);
citizens = std::atoi(tString.c_str());
std::cout << std::endl << "How many soldiers do you have?:";
std::getline(std::cin,tString);
soldiers = std::atoi(tString.c_str());
return 0;
}
Related
this is the code i wrote for simple grading exams (im still a very beginner) but when i do a wrong input in (Grades) it doesnt go to the function i made which is called (FalseInput) to make the user able to re-enter the (Grades) any suggestions to how to solve?
and how to improve in general ?
here is an example of whats the problem :
Please Type Your Name : rafeeq
Please Insert The Grade : as (which is an input error)
you failed
thanks.
#include <iostream>
#include <string>
using namespace std;
char Name[30];
int Grades;
const int MinGrade(50);
void FalseInput() {
cout << "pleae enter the number again : ";
cin >> Grades;
if (Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << Grades;
} else if (Grades < MinGrade and cin.fail() == 0) {
cout << "you failed\n";
} else if (cin.fail() == 1) {
cout << "its not a valid number\n";
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
}
}
int main() {
cout << "Please Type Your Name : ";
cin.getline(Name, 30);
cout << "Please Insert The Grade : ";
cin >> Grades;
if (Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << "The Grade Achieved : " << Grades << "%";
} else if (Grades < MinGrade) {
cout << "you failed\n";
} else if (cin.fail() == 1) {
cout << "its not a valid number\n";
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
}
return 0;
}
You don't check if the extraction of an int succeeds here:
cin >> Grades;
You can check the state of the input stream after extraction like this and it needs to be the first condition or else the program will make the comparisons with MinGrade first and will get a true on Grades < MinGrade.
if(!(cin >> Grades)) {
if(cin.eof()) {
// You can't recover the input steam from eof so here you need
// to handle that. Perhaps by terminating the program.
}
cin.clear();
cin.ignore(1000, '\n');
cout << endl;
FalseInput();
} else if(Grades >= MinGrade) {
cout << Name << " : " << "you passed\n";
cout << "The Grade Achieved : " << Grades << "%";
} else if(Grades < MinGrade) {
cout << "you failed\n";
}
You do have a lot of unnecessary code duplication and you also use an array of char to read the name - but you have included <string> so I assume you're familiar with std::string. I suggest using that.
Simplification:
#include <iostream>
#include <limits>
#include <string>
int main() {
const int MinGrade = 50;
std::string Name;
int Grades;
std::cout << "Please Type Your Name : ";
if(std::getline(std::cin, Name)) {
while(true) {
std::cout << "Please Insert The Grade : ";
if(!(std::cin >> Grades)) {
if(std::cin.eof()) {
std::cout << "Bye bye\n";
break;
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "That's not a valid number!\nPlease enter the "
"number again!\n";
} else if(Grades >= MinGrade) {
std::cout << Name << " : " << "you passed\n";
std::cout << "The Grade Achieved : " << Grades << "%\n";
break;
} else { // no need to check "Grades < MinGrade" here
std::cout << "you failed\n";
break;
}
}
}
}
What is happening: When that string "as" is attempted to write to the integer Grades, cin.fail() is set and Grades has the default of 0 written to it (I think that's right)
C++ cin reading string into int type returns 0
All-in-All: Input validation is needed BEFORE you check it's values.
Here is one approach, check if cin was able to successfully convert:
https://www.hackerearth.com/practice/notes/validating-user-input-in-c/
Another approach would be to read cin into a string instead of int, then you can control how to convert/cast it to whatever form you want (more work, but being that you are new - you will learn a lot doing this).
Secondary Note: Your string of 50 characters for name - imagine what would happen if you wrote 60 characters of input. There will be more data than the container can hold, thus writing past the bounds and into his neighbor (could cause a segment fault, or worse - crazy unexpected behavior)
Why does this work? Using cin to read to a char array smaller than given input
Not under standing looping for arrays. Looping through all of grab some or search. Can someone explain the process? Thanks in advance. Sorry if duplicate. I looked around and couldnt find a solid explaination that I could understand.
#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void allContacts(string names[], string phones[])
{
cout << "Showing all contacts... Press Q to go back to main menu" << endl;
}
void addName(string names[], string phones[])
{
bool keepGoing;
string input;
beginning:
for (int i = 0; i < sizeof(names); i++)
{
cout << "Enter contact name: ";
cin >> names[i];
cout << "Enter contact number: ";
cin >> phones[i];
cout << "Do you have another contact to add? y or no" << endl;
cin >> input;
if(input == "y" || input == "Y")
{
goto beginning;
}
if(input == "n" || input == "N")
{
cout << "Contacts you have entered: " << endl;
cout << names[i] << " : " << phones[i] << endl;
}
}
}
void searchName(string names[], string phones[])
{
string name;
cout << "Enter Name: ";
cin >> name;
cout << "Search for a name or Press Q to go back to main menu" << endl;
for (int i = 0; i < sizeof(names); i++){
if (name == names[i])
{
cout << counter << names[i] << " 's phone number is: " << phones[i] << endl;
} else {
cout << "No results found";
}
}
}
int main()
{
string names[100];
string phones[100];
int choice;
cout << "============================" << endl;
cout << "=== Welcome to PhoneBook ===" << endl;
cout << "============================" << endl;
cout << "1- Add a New Contact" << endl;
cout << "2- Search By Name" << endl;
cout << "3- Display All" << endl;
cout << "0- Exit" << endl;
cout << "Select a number: " << endl;
cin >> choice;
switch(choice)
{
case 1:
addName(names, phones);
break;
case 2:
searchName(names, phones);
break;
case 3:
allContacts(names, phones);
break;
case 0:
cout << "Exiting PhoneBook...";
break;
}
}
In C++ arrays lose attributes when passed to functions. Those attributes are capacity and size (number of filled slots). You will need to pass this additional information for each array:
void addName(string names[], unsigned int names_capacity, unsigned int names_size,
string phones[], unsigned int phones_capacity, unsigned int phones_size)
To get around this, you can use std::vector. The std::vector knows its capacity and size, so you don't have to pass additional attributes to your function.
Also, if you use tolower or toupper before you compare, you only need to make one comparison:
char input;
cout << "Do you have another contact to add? y or n" << endl;
cin >> input;
input = toupper(input);
if(input == 'Y')
When using strings, you can convert them to all uppercase or all lowercase by using std::transform, such as:
std::transform(input.begin(),
input.begin(), input.end(),
tolower);
I'm trying to make a little game, and I'm a beginner.
The problem is the parts with the ifs and the else, where it says "Lady" and "Sir".
#include <iostream>
#include <string>
using namespace std;
int main()
{
string playerName;
int age;
int playerGender;
cout << "Are you a Lady or a Sir?" << endl;
cin >> playerGender;
if (playerGender = Lady)
{
cout << "So you're a girl. " << endl;
}
else if (playerGender = Sir)
{
cout << "So you're a boy." << endl;
}
cout << "What is your name " << playerGender << "?" << endl;
cin >> playerName;
cout << "What is your age?" << playerName << endl;
cin >> age;
if (age <= 10)
{
cout << "You're too young " << playerName << "! " << endl;
}
else if (age >= 11)
{
cout << "You are old enough to play" << playerName << ". " << endl;
That's what I have, I don't know whats wrong. Help please!
When you perform the following:
std::cin >> playerGender;
You are retrieving a number from the user. You are then assigning that number to your playerGender with the following:
if (playerGender = Lady)
You're only using a single =, which assigns the value that's in Lady to playerGender. You probably mean to write == which will compare the value of playerGender and Lady.
I can't tell what Lady and Sir are, but for your purposes you will need to ensure they are an int:
const int Lady = 0, Sir = 1;
Or an enum:
enum genders { Lady = 0, Sir = 1 };
Now you can make the following comparison:
if (playerGender == Lady)
{
}
else if (playerGender == Sir)
{
}
I am currently taking a C++ programming class and am working on a project in which I have to create a fairly simple movie database. My code essentially works as intended yet in certain cases it causes the main menu to loop infinitely and I cannot figure out why. I brought this to my teacher and he cannot explain it either. He gave me a workaround but I would like to know if anyone can see the cause of the problem. Full code is as follows:
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct MovieType
{
string title;
string director;
int year;
int length;
string rating;
};
MovieType addMovie() {
MovieType newMovie;
cout << "Movie title :";
getline(cin, newMovie.title);
cout << "Director :";
getline(cin, newMovie.director);
cout << "Year :";
cin >> newMovie.year;
cout << "Length(in minutes) :";
cin >> newMovie.length;
cout << "Rating :";
cin >> newMovie.rating;
cout << endl;
return newMovie;
}
void listMovie(MovieType movie) {
cout << "______________________________________" << endl;
cout << "Title : " << movie.title << endl;
cout << "Director : " << movie.director << endl;
cout << "Released : " << movie.year << endl;
cout << "MPAA Rating : " << movie.rating << endl;
cout << "Running time : " << movie.length << " minutes" << endl;
cout << "______________________________________" << endl;
}
void search(vector<MovieType> movieVector) {
string strSearch;
cout << endl << "Search title: ";
getline(cin, strSearch);
for (int c = 0; c < movieVector.size(); c++) {
if (movieVector.at(c).title == strSearch)
listMovie(movieVector.at(c));
}
}
int main() {
bool quit = 0;
vector<MovieType> movieVector;
while (quit == 0) {
char selection = 'f';
cout << "Main Menu:" << endl;
cout << "'a' - Add movie" << endl;
cout << "'l' - List movies" << endl;
cout << "'s' - Search by movie title" << endl;
cout << "'q' - Quit" << endl;
cout << "Please enter one of the listed commands:";
cin >> selection;
cin.ignore();
cout << endl;
if (selection == 'a')
movieVector.push_back(addMovie());
else if (selection == 'l') {
for (int c = 0; c < movieVector.size(); c++) {
listMovie(movieVector.at(c));
}
}
else if (selection == 's') {
search(movieVector);
}
else if (selection == 'q')
quit = 1;
}
return 0;
}
When an unexpected input type is entered during the addMovie function(like entering text for the int type year), it just runs through the function then loops through the menu infinitely. It appears to me that the code just stops even looking at the input stream. I have tried using cin.ignore() in many different places but it doesn't matter if there is nothing left in the stream it just keeps going.
I am using NetBeans to compile my code.
I really have no idea why it behaves like this otherwise I would offer more information but I am just curious as to why this happens, because as I said before, my professor doesn't even know why this is happening.
Any help or insight is greatly appreciated.
cin enters an error state where cin.fail() is true. In this state it just ignores all input operations. One fix is to clear the error state, but better, only use getline operations on cin, not formatted input.
E.g., instead of
cin >> newMovie.year;
… do
newMovie.year = stoi( line_from( cin ) );
… where line_from can be defined as
auto line_from( std::istream& stream )
-> std::string
{
std::string result;
if( not getline( stream, result ) )
{
// Throw an exception or call exit(EXIT_FAILURE).0
}
return result;
}
Disclaimer: code untouched by compiler.
I am struggling to get an input validation working for my game.
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
int iGumballs;
int iUserguess;
int iGuesses = 0;
while (true)
{
system("CLS");
cin.clear();
iGuesses = 0;
srand(static_cast<unsigned int>(time(0)));
iGumballs = rand()%1000+1;
cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;
do
{
cout << "Enter your guess: ";
cin >> iUserguess;
if(iUserguess > iGumballs)
{
cout << "Too high!" << endl << endl;
}
if(iUserguess < iGumballs)
{
cout << "Too low!" << endl << endl;
}
iGuesses ++;
}
while(iUserguess > iGumballs || iUserguess < iGumballs);
cout << "You guessed the right amout of gumballs" << endl << endl;
cout << "You took " << iGuesses << " guesses" << endl << endl;
system ("pause");
}
return 0;
}
I basically want the program to display
Your Guess: Sorry, incorrect input - try again
When the user enters a number less then 1, and higher then 1000, as well as some sort of validation which makes sure a number is entered instead of a letter or symbol. I tried cin.fail() but I couldn't get it quite to work.
Thanks,
John
You will need some test to see if is a number or not, try this:
#include <iostream>
#include <string>
#include <ctime>
#include <boost/lexical_cast.hpp> //dependency that can be optional
using namespace std;
bool is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
int main()
{
int iGumballs;
std::string iUserguessStr;
int iUserguess;
int iGuesses = 0;
while (true)
{
system("CLS");
cin.clear();
iGuesses = 0;
srand(static_cast<unsigned int>(time(0)));
iGumballs = rand()%1000+1;
cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;
do
{
cout << "Enter your guess: ";
cin >> iUserguessStr;
if(is_number(iUserguessStr))
iUserguess = boost::lexical_cast<int>(iUserguessStr); //you can make your own or maybe use lexical cast to transform a string into integer
else
continue; //put some fancy message here warning the user
if(iUserguess > iGumballs)
{
cout << "Too high!" << endl << endl;
}
if(iUserguess < iGumballs)
{
cout << "Too low!" << endl << endl;
}
iGuesses ++;
}
while(iUserguess > iGumballs || iUserguess < iGumballs);
cout << "You guessed the right amout of gumballs" << endl << endl;
cout << "You took " << iGuesses << " guesses" << endl << endl;
system ("pause");
}
return 0;
}
My answer is based on a related problem: How to determine if a string is a number with C++?
Yo can use if(cin) to check the state of the input stream and since operator>> will return the input stream that was passed to it you can use if(cin>>iUserguess)
If cin is in a failed state -maybe because the user entered a non number- the expression if(cin>>iUserguess) will evaluate to false.
If the user enters a non number you will need to call cin.clear() to clear the stream state and cin.ignore() to discard the input, before trying to read a number again.
so using your example, it could be changed to this:
#include <iostream>
#include <ctime>
#include <limits>
using namespace std;
int main()
{
int iGumballs;
int iUserguess;
int iGuesses = 0;
while (true)
{
system("CLS");
iGuesses = 0;
srand(static_cast<unsigned int>(time(0)));
iGumballs = rand()%1000+1;
cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;
do
{
cout << "Enter your guess: ";
if(cin >> iUserguess)
{
iGuesses ++;
if(iUserguess > iGumballs)
{
cout << "Too high!" << endl << endl;
continue;
}
if(iUserguess < iGumballs)
{
cout << "Too low!" << endl << endl;
continue;
}
}
else
{
cout<<"incorrect input - try again\n\n";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
continue;
}
}
while(iUserguess > iGumballs || iUserguess < iGumballs);
cout << "You guessed the right amout of gumballs" << endl << endl;
cout << "You took " << iGuesses << " guesses" << endl << endl;
system ("pause");
}
return 0;
}
To validate characters you could use the try-catch structure.
-First read in a string and try Typecasting it and handle the errors with try-catch.
-Then use conditions to make sure the input is in range.
-If the input isn't valid, you can write an error message to display.