So I'm trying to make a simple application that quizzes the user. It asks a question and the user answers 1, 2, 3, or 4. The app then takes that answer and if it is correct adds +1 to the total_score which will be displayed at the end. Everything looks sound to me, but when I run it and I get to the if (q1_valid == false) part it skips the cout and runs the goto no matter if q1_valid is true or false.
#include <iostream>
using namespace std;
int main()
{
int q1_answer;
int total_score;
bool q1_correct;
bool q1_valid;
Question_1:
cout << "Question 1 (#3 is correct)" << endl;
cout << "1.) Answer 1" <<endl;
cout << "2.) Answer 2" <<endl;
cout << "3.) Answer 3" <<endl;
cout << "4.) Answer 4" <<endl;
cin >> q1_answer;
if (q1_answer == 1)
q1_correct = false;
q1_valid = true;
if (q1_answer == 2)
q1_correct = false;
q1_valid = true;
if (q1_answer == 3)
q1_correct = true;
q1_valid = true;
if (q1_answer == 4)
q1_correct = false;
q1_valid = true;
if (q1_valid == false)
cout << "Invalid answer." <<endl;
goto Question_1;
if (q1_correct == true)
cout << "Correct!" <<endl;
(total_score + 1);
goto Question_2;
if (q1_correct == false)
cout << "Incorrect." <<endl;
goto Question_2;
if (q1_valid == false)
goto Question_1;
Question_2:
cout<< "Q2" <<endl;
cin.ignore();
cin.ignore();
}
I have a few tips here:
If... then is a conditional, not a loop. Sorry, that's just me being slightly picky. ;)
Never, ever, ever, ever use goto. ADVANCED USAGE: only use goto when there's a damned good reason to.
When testing boolean values, you don't need "== true" or "== false".
It looks like you haven't learned how to use the else statement yet. That's going to make your program a lot easier to read, debug, and understand.
Brackets are also necessary, as noted above.
You need to use brackets:
if (q1_valid == false) {
cout << "Invalid answer." <<endl;
goto Question_1;
}
If you don't use the brackets, the if only executes the first statement directly following it, if the if condition evaluates to true.
You don't have braces around the statements after the if, so only the first statement is conditional. In this case, that means that "q1_valid=true;" runs no matter what the answer is.
if (q1_answer == 4) {
q1_correct = false;
q1_valid = true;
}
You need an editor which shows you this by indentions.
emacs will, for example
Brackets for the if statement are required.
Have you considered using the switch statement:
switch (q1_answer){
case 1:
q1_correct = false;
q1_valid = true;
break;
case 2:
q1_correct = false;
q1_valid = true;
break;
case n:
//...
break;
}
Don not forget to use brackets.
Related
So I am new to C++, and I am working through a pdf tutorial that is getting me started with basic stuff. I was writing a simple case program, and I experienced something weird.
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
enum string_feeling {
eGood,
eBad,
eOk,
};
string_feeling hashit(string const& feeling) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
return eGood;
}
if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
return eBad;
}
if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
return eOk;
}
else cout << "";
}
int main() {
string username;
cout << "Hello! Please enter your first name here: \n";
cin >> username;
cout << "Hello, " << username << "!\n";
cout << "How are you today? ";
string feeling;
cin >> feeling;
cout << endl;
switch (hashit(feeling)) {
case eGood:
cout << "That's great!";
break;
case eBad:
cout << "I hope you are happy soon!";
break;
case eOk:
cout << "That's good.";
break;
default:
cout << "Ok.";
}
}
Whenever I didn't have the "else" after the "if (feeling == ok)" stuff, the default case would never be called and if I entered something random it would give me the text from the eGood case. I was wondering why this is happening and since I'm learning C++ I didn't want to just brush it off not ever knowing why it worked after I put the else statement in there. So, if anyone could explain this to me that would be great! Sorry for my bad grammar.
Compile your program with warnings enabled like g++ -Wall -Wextra -Werror and it won't even compile, because string_feeling hashit(string const& feeling) does not return a value in all cases.
Compiling code without warnings enabled is a surefire way to waste time.
When none of conditions in the three if statements in hashit function become true, no return statement is executed in the function and undefined behavior is invoked.
(Quote from N3337 6.6.3 The return statement)
Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
To avoid this, you should add one more kind to the enum
enum string_feeling {
eGood,
eBad,
eOk,
eOther // add this
};
and return it when no conditions are met.
string_feeling hashit(string const& feeling) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
return eGood;
}
if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
return eBad;
}
if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
return eOk;
}
else cout << "";
return eOther; // add this
}
You always have to return a value else the behavior is undefined
If you cannot modify your enum to add a case for an unknown feeling you can modify hashit to return true if feeling is valid and in that case to set the output parameter with the corresponding enum value, else to return false without setting the output parameter :
#include <iostream>
#include <string>
using namespace std;
enum string_feeling {
eGood,
eBad,
eOk,
};
bool hashit(string const& feeling, string_feeling & r) {
if (feeling == "Good" || feeling == "good" || feeling == "GOOD") {
r = eGood;
}
else if (feeling == "Bad" || feeling == "bad" || feeling == "BAD") {
r = eBad;
}
else if (feeling == "Ok" || feeling == "ok" || feeling == "OK") {
r = eOk;
}
else
return false;
return true;
}
int main() {
string username;
cout << "Hello! Please enter your first name here: \n";
cin >> username;
cout << "Hello, " << username << "!\n";
cout << "How are you today? ";
string feeling;
cin >> feeling;
cout << endl;
string_feeling f;
if (! hashit(feeling, f))
cout << "I do not understand how you are" << endl;
else {
switch (f) {
case eGood:
cout << "That's great!" << endl;
break;
case eBad:
cout << "I hope you are happy soon!" << endl;
break;
case eOk:
cout << "That's good." << endl;
break;
}
}
}
Compilation and execution :
pi#raspberrypi:/tmp $ g++ -Wall c.cc
pi#raspberrypi:/tmp $ ./a.out
Hello! Please enter your first name here:
bruno
Hello, bruno!
How are you today? good
That's great!
pi#raspberrypi:/tmp $ ./a.out
Hello! Please enter your first name here:
bruno
Hello, bruno!
How are you today? aze
I do not understand how you are
pi#raspberrypi:/tmp $
Out of that :
to name your enum string_feeling is not very clear, whatever the feeling was input as a string, better to just name it Feeling
it can be practical in hashit to get the string by value to change it to lowercase then to just compare it with with "good" "bad" and "ok" or to use strcasecmp on its .c_str(), allowing to also manage "gOoD" etc
If no if conditions will meet, hashit went to
else cout << "";
Since you didn't explicitly write the return statement, the function returns the default value 0, which is equal to eGood.
However, the default return value is not always 0. This is an undefined behaviour.
If you runs this code with a different compiler, you may get different results.
I am working on C++, and using a basic authentication method using if statements, so what I have here, is when the the input is not the desired combination, it will say Access denied and ask the user if they want to try again or quit. I tried doing this using the goto variable, but it hasn't been working. Help please? (Full code: https://pastebin.com/49LdGgJX)
else {
cout << "Access denied..." << " Try again? (Y/N) >" << flush;
string ask;
cin >> ask;
if(ask == "N" || "n"){
cout << "Shutting down..." << endl;
goto end;
}
else if(ask == "Y" || "y"){
goto restart;
}
else {
cout << "Invalid option." << endl;
goto restart;
}
}
end:
return 0;
Your if statements are wrong as:
if(ask == "N" || "n")
always evaluates to true because the "n" operand always evaluates to true and you are using a logical OR operator. The string literal of "n" decays to const char* pointer whose value is not 0 thus evaluating to true. What you want is:
if(ask == "N" || ask == "n")
and:
else if(ask == "Y" || ask == "y")
That being said don't use goto.
One of the possible break-ups of that code structure into more procedural way (wouldn't dare to call this "object oriented").
You can use similar way to break up menu handling code into separate functions for each option, etc.
If this would be multi-user app, then you may want to store instead of simple true/false full credentials of the user authenticated, like having a structure containing name, code (password probably can be thrown away after authentication to not keep it in memory long, if you don't need it later).
// returns true if user wants to exit
// sets authenticated to true when the Drew user is detected
bool AuthenticateUser(bool & authenticated) {
cout << "Enter your username >" << flush;
...
if (name == "Drew" && ...) {
authenticated = true;
cout << "Access granted. Welcome, " << name << "." << endl;
cout << "Welcome to Database of Drew" << endl;
return false;
}
cout << "Access denied..." << " Try again? (Y/N) >" << flush;
...
return (ask == "N" || ask == "n"); // N = wants to exit
}
// returns true if user wants to exit
bool ProceedWithMenu() {
cout << "1.\tAdd new record." << endl;
cout << "2.\tDelete record." << endl;
...
if (1 == value) {
...
}
if (5 == value) {
cout << "Application quitting... " << endl;
}
return (5 == value);
}
void mainLoop {
bool authenticated = false;
bool exitApp = false;
do {
if (!authenticated) {
exitApp = AuthenticateUser(authenticated);
} else {
exitApp = ProceedWithMenu();
}
// repeat authentication / menu until user decides to quit app
} while (!exitApp);
}
This example is still quite crude and oversimplified, just trying to illustrate power of do {} while, return, and similar. Often also continue and break can be of great help to control the flow of code execution, without any goto and labels.
I have a code working on basic c++. I just want when this loop become completed and one if statement become true, a message generate automatically. In this regard i have used while statement but while statement is also work i don't want to display the message. Means when if statement (congratulation....) become true, the message (You don't have more...) displays.
for(i=1; i<=attempt; i++){
cout<< "whatever" ;
cin >> userNumber;
if (userNumber < secretNumber){
cout << "Oooppssss... Your entered number is too low..." <<endl;
}
else if (userNumber > secretNumber){
cout << "Oooppssss... Your entered number is too high..."<<endl;
}
else if(userNumber==secretNumber){
cout << "Congratulation you have won..."<<endl;
break;
}
else{
cout << "Invalid Input."<<endl;
}
}
while(attempt=i){
cout<< "You don't have more turn...Computer Won."<<endl<<endl;
break;
}
Reason is you are not using == and hence condition always turns true. Also instead of while loop you need if
while(attempt=i){
Use
if((attempt + 1) == i){
I want to make a program that tracks the number of CDs sold. And i want to know which is the best seller. The CD's are categorized as Alternative music classical, country, dance, pop, rock and R&B
I made a menu driven program that will display the music genres but
here's my problem: I don't know how can the user could continue on inputting the number of the genres of music sold until he wants to stop it. And after he stops how can he report on how many CDs were sold for each genre? Basically the user will continue on counting the number of CD's sold until he wants to stop the sales.
#include<iostream>
using namespace std;
int main ()
{
int counter = 1;
int result, Alternative = 0, Classical = 0, Country = 0, Dance = 0, Pop = 0, Rock = 0, RnB = 0;
cout << "Choose the music genre sold (Only choose the numbers): \n1. Alternative\n";
cout << "2. Classical\n3. Country\n4. Dance\n5. Pop\n6. Rock\n7. R&B\n\t\t\t\t\t\t\t";
while (counter <= 100)
{
cin>>result;
if(result == 1)
{
Alternative = Alternative + 1;
}
else if(result == 2)
{
Classical = Classical + 1;
counter++;
}
else if(result == 3)
{
Country = Country + 1;
counter++;
}
else if(result == 4)
{
Dance = Dance + 1;
counter++;
}
else if(result == 5)
{
Pop = Pop + 1;
counter++;
}
else if (result == 6)
{
Rock = Rock + 1;
counter++;
}
else if (result == 7)
{
RnB = RnB + 1;
counter++;
}
cout<<"\nAlternative:"<<Alternative;
cout<<"\tClassical:"<<Classical;
cout<<"\tCountry: "<<Country<<"\n";
cout<<"Dance: "<<Dance;
cout<<"\tPop: "<<Pop;
cout<<"\tRock: "<<Rock;
cout<<"\tR&B: "<<RnB<<"\t\t\t";
}
}
EDIT:
Thanks #timrau and #sfjac for the break, switch and variable++ suggestions.
Instead of making the while loop stop after a fixed number (100) of iterations[1], you could ask the user to enter a specific character or number when he is done.
Consider the following code, for example:
// assume you have already declared and initialized all the required variables, as in your example.
// for now we will say that this is -1, so that it doesn't count as a valid option, and so it passes our while's condition.
int result = -1;
while (result) // condition evaluates to FALSE if user enters zero.
{
// print out the menu.
cout << "The menu goes here... " << endl
<< "Press 0 (zero) when you are done.";
// get the input.
cin >> result;
// use switch to check against constant values. Its cleaner.
switch (result)
{
case 1: Alternative++; // For incrementing variables, use the ++ operator.
break;
case 2: Classical++;
break;
// and so on, for all your choices.
// And then,
default: cout << "Oops! That wasn\'t a valid choice. Try again..." << endl;
}
}
// now the user is done, and has entered 0.
cout << "\nAlternative: " << Alternative
<< "\tClassical: " << Classical
<< "\tCountry: " << Country << "\n"
<< "Dance: " << Dance
<< "\tPop: " << Pop
<< "\tRock: " << Rock
<< "\tR&B: " << RnB << "\t\t\t";
// and yes, you can fold your cout like that, so you don't have to type "cout" every time.
Hope that was of some help :-)
[1] An iteration is each time a loop repeats (Iteration on Wikipedia).
So add quit option to your cout:
cout << "2. Classical\n3. Country\n4. Dance\n5. Pop\n6. Rock\n7. R&B\n8. quit
Add new condition (switch is better option here) in your while loop:
else if(result == 8) {
break;
}
Also in your first if, you should increment choice i.e. in case of alternative. Best would be incrementing choice after you read the value just once instead of duplicating in every conditions.
And your cout that prints genre's within while loop should be post end of while loop i.e. before last brace i.e. end of main.
while (counter <= 100 || result == -1)
{...}
you can prompt the user to type -1, if they're finished.
Or else, you may use a switch, for example:
bool stop = false;
while (counter <= 100 || stop)
{
switch(result)
{
case 1: ...;
case 2: ...;
.
.
.
default:
stop = true;
}
}
if the user enters a value other than [1, 7], it will exit the loop.
Allow the user to thell you that he's finished with the input:
//...
cout << "...7. R&B\n999.End input \t\t\t\t\t\t\t";
do {
// all your statements
} while (result!= 999);
Personally, I'd start the numbering with 0 for end of input and then the rest of the possible choices. The user could quickly see how to stop and then you could write while (result). But that's matter of taste.
Some other suggestions:
Consider switch instead of your long if...else ... chain. Or better here, consider using an array to avoid repetitive code:
int genre[8]={}; // create ainitalised array
//... as above
do {
cin>>result;
if (result>=0 && result<8) {
genre[result]++;
counter++;
}
else if (result!=999)
cout <<"Wrong value entered!\n";
} while (result!= 999);
I'm just learning C++ (1 week of experience) and was trying to write an input validation loop that ask the user to enter "Yes" or "No". I figured it out but have a feeling there's a better way of approaching this. Here's what I came up with:
{
char temp[5]; // to store the input in a string
int test; // to be tested in the while loop
cout << "Yes or No\n";
cin.getline(temp, 5);
if (!(strcmp(temp, "Yes")) || !(strcmp(temp, "No"))) // checks the string if says Yes or No
cout << "Acceptable input"; // displays if string is indeed Yes or No
else //if not, intiate input validation loop
{
test = 0;
while (test == 0) // loop
{
cout << "Invalid, try again.\n";
cin.getline(temp, 5); // attempts to get Yes or No again
if (!(strcmp(temp, "Yes")) || !(strcmp(temp, "No"))) // checks the string if says Yes or No
test = 1; // changes test to 1 so that the loop is canceled
else test = 0; // keeps test at 0 so that the loop iterates and ask for a valid input again
}
cout << "Acceptable input";
}
cin.ignore();
cin.get();
return 0;
}
I apologize for my poor notes, not sure what is relevant. I'm also using the cstring header.
Even better IMO:
std::string answer;
for(;;) {
std::cout << "Please, type Yes or No\n";
getline(std::cin, answer);
if (answer == "Yes" || answer == "No") break;
}
You also can transform answer into lower case that allows user to type not only "Yes", but also "yes", "yEs", etc. See this question
I think you want a do while loop:
bool test = false;
do
{
cout << "Yes or No\n";
cin.getline(temp, 5);
if (!(strcmp(temp, "Yes")) || !(strcmp(temp, "No"))) // checks the string if says Yes or No
{
cout << "Acceptable input"; // displays if string is indeed Yes or No
test = true;
}
else
{
cout << "Invalid, try again.\n";
}
} while (!test);