So, let me preface that I am still learning C++ and would appreciate some guidance on what I am doing wrong.
My prompt is to write a function that continuously prompts a user for a valid age (between 0 and
100) and the function must only return the age to the caller of the function after a valid age is retrieved. AND For each function, you must declare the function using a function prototype before main and then define the function after main.
Here is my code,
#include <iostream>
using namespace std;
int num;
bool valid;
int validateInput()
{
cout << "Pick a number between 0 and 100" << endl;
cin >> num;
while(bool valid = false)
{
if(num <= 0)
{
cout << "Error: Number is invalid because it's too low" << endl;
bool valid = false;
return 0;
}
else if (num >= 100)
{
cout << "Error: Number is invalid because it's too high" << endl;
bool valid = false;
return 0;
}
else
{
cout << "You are " << num << " years old." << endl;
bool valid = true;
return 0;
}
}
}
int main()
{
validateInput();
return 0;
}
So I am trying to get my program to work but the IF statements keep getting skipped.
Am I misunderstanding something? Any and all help is very much appreciated.
EDIT: Thank you to Arvin and iammilind for your help.
I was able to fix the code so my while loop condition would actually trigger, moved my cout statements into the loop and so I wouldn't get infinite output.
My final working code looked like this.
#include <iostream>
using namespace std;
int num;
bool valid = false;
int validateInput()
{
while(!valid)
{
cout << "Pick a number between 0 and 100" << endl;
cin >> num;
if(num <= 0)
{
cout << "Error: Number is invalid because it's too low" << endl << endl;
bool valid = false;
}
else if (num >= 100)
{
cout << "Error: Number is invalid because it's too high" << endl << endl;
bool valid = false;
}
else
{
cout << "You are " << num << " years old." << endl;
bool valid = true;
return 0;
}
}
}
int main()
{
validateInput();
return 0;
}
You give a false value to the while loop that makes the while loop doesn't start the loop.
do this instead:
bool valid = false;
while (!valid){ // while valid is still false, do the loop
// your code here
}
Further explanation: You're currently using sentinel-controller loop
reference: https://simplecplusplus.wordpress.com/tag/sentinel-controlled-loop/
In order for while loop to start running, you've to provide the "true" condition to the while, and it will start looping until the condition turn out to false.
Programming tips for you: next time, you've to see the larger picture of your code every time you're trying to debugging. If you're sure the if-else code is running and have no problem, you have to enlarge your investigation for the bug, maybe it's the while loop that didn't work, not if-else. And if the while loop seems having no problem, maybe its the function or the caller of the function
while(bool valid = false) never allows the execution to enter the loop. Hence the if conditions are never called.
Use it as below:
while(valid == false) { // see '==' sign. `while(not valid)` is also fine
// ... your 'if' conditions
}
Actually you are creating a locally scope variable within while() by having a bool before it. So bool valid hides bool ::valid (declared outside).
Also, once the loop ends, you may want to reset it to false again. Otherwise this function will never be able to used again!
Using globals (bool valid) for such functionality is a bad design.
Related
Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!
There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.
It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I have the following code and it somehow verify if the input is number, but the error occurs while looping back to ask the user for the second time to enter the number.
I can't figure it out.
#include <iostream>
#include <limits>
using namespace std;
void botVarification();
void userDecision();
bool isHuman(string humanInput);
int main()
{
botVarification();
return 0;
}
void botVarification()
{
string humanInput;
cout << "Enter the number to verify that you are not a bot: ";
cin >> humanInput;
bool isHuman = true;
do {
for (int humanInputvalidator; humanInputvalidator < humanInput.length() && isHuman; humanInputvalidator++) {
if (!(humanInput[humanInputvalidator] >= 48 && humanInput[humanInputvalidator] <= 57)) {
isHuman = false;
cout << "Not success, try again!";
cin >> humanInput;
}
else
cout << "Success" << '\n';
break;
}
} while (!(isHuman));
}
$ clang++-7 -Wall -o main main.cpp
main.cpp:23:39: warning: variable 'humanInputvalidator' is
uninitialized when used here [-Wuninitialized]
for (int humanInputvalidator; humanInputvalidator < hum...
^~~~~~~~~~~~~~~~~~~
main.cpp:23:37: note: initialize the variable 'humanInputvalidator' to
silence this warning
for (int humanInputvalidator; humanInputvalidator < hum...
^
= 0
1 warning generated.
So let's fix that.
Additionally, on the second iteration of getting input from the user, humanInputvalidator < humanInput.length() && isHuman will always be false. You'll want to reinitialize isHuman = true inside the do while loop.
Functions are a great way to simplify your code!
Use functions! It's a great way to simplify your code and decrease the number of variables in any single context.
bool isThisHumanInput(std::string data) {
for (int i = 0; i < data.length(); i++)
if (!(data[i] >= 48 && data[i] <= 57))
return false;
return true;
}
void botVarification()
{
string humanInput;
bool isHuman;
do {
cout << "Enter the number to verify that you are not a bot: ";
cin >> humanInput;
isHuman = isThisHumanInput(humanInput);
if (isHuman) {
cout << "Success" << '\n';
} else {
cout << "Not success, try again!\n";
}
} while (!isHuman);
}
There's several changes that are necessary to get this code functioning correctly. Here's one working version, with the functions and includes that you don't actually use yet removed and a typo corrected.
Highlights: We have to initialize humanInputvalidator, we have to reset isHuman to true at the beginning of the do-while loop, and the logic for exiting the inner for loop and printing "Success!" was all changed.
#include <iostream>
#include <string>
void botVerification();
int main()
{
botVerification();
return 0;
}
void botVerification()
{
std::string humanInput;
std::cout << "Enter the number to verify that you are not a bot: ";
std::getline(std::cin, humanInput); // getline to capture whitespace
bool isHuman;
do {
isHuman = true; // Reset to true at the beginning of each loop
// Initialize humanInputvalidator
for (int humanInputvalidator = 0; humanInputvalidator < humanInput.length() && isHuman; humanInputvalidator++) {
// Rewrite comparison using char literals for clarity
if (!(humanInput[humanInputvalidator] >= '0' && humanInput[humanInputvalidator] <= '9')) {
isHuman = false;
std::cout << "Not success, try again! ";
std::getline(std::cin, humanInput);
// No need to break since we test isHuman in the for loop
}
}
} while (!(isHuman));
// Print success after input is fully verified, not at some intermediate stage
std::cout << "Success!\n";
}
First of all, you need to initialize humanInputvalidator when you define it in the for loop. Variables in C++ do not have default values.
Also, in case you find an incorrect character in humanInput, you make the user input again. This happens while you are iterating over the characters in the string. This is not really good. In this particular case it does not break, but it may in some other one, so keep that in mind.
Moreover, in the for loop you alway break on the first iteration. Your break statement is just below the if-else and I think your intention was that it be inside the else branch.
All in all, I cannot pinpoint any specific reason for the infinite loop you are getting but these are at least a few things you can fix and then see what happens. I would also suggest to simplify your code and make it more readable, by splitting out the invalid input check to a separate function, like this:
bool isInputValid(const string& humanInput)
{
for (int humanInputvalidator = 0; humanInputvalidator < humanInput.length(); humanInputvalidator++) {
if (!(humanInput[humanInputvalidator] >= 48 && humanInput[humanInputvalidator] <= 57)) {
return false;
}
}
return true;
}
void botVarification()
{
string humanInput;
cout << "Enter the number to verify that you are not a bot: ";
cin >> humanInput;
do {
if (isInputValid(humanInput))
{
cout << "Success" << '\n';
break;
}
cout << "Not success, try again!";
cin >> humanInput;
} while (true);
}
The battleship program I wrote is supposed to loop a infinite amount of times until a condition is met. However it stops after the first execution. What is the matter with my loop? The code runs, however towards the end it outputs game over twice when its not supposed to. There are still more ships remaining in the game.
#include<iostream>
#include<fstream>
#include<string>
#include<cmath>
using namespace std;
bool FleetSunk();
void Fire(int&, int&, char&);
char ocean[25][25];
int main()
{
int x;
int y;
char spot;
ifstream input;
input.open("ocean.txt");
for(x=0;x<25;x++)
{
for(y=0;y<25;y++)
{
input >> ocean[x][y];
}
}
FleetSunk == false;
do
{
cout << "Please input x coordinate: ";
cin >> x;
cout << endl << "Please input y coordinate: ";
cin >> y;
cout<< endl;
Fire(x,y,spot);
FleetSunk();
}while(FleetSunk() == false);
}
void Fire(int& x, int&y, char&spot)
{
spot = ocean[x][y];
if(spot == '#')
{
cout << "You Have hit a ship"<< endl;
ocean[x][y] = 'H';
}
else if(spot == 'H')
{
cout << "HIT AGAIN" << endl;
}
else if(spot == '-')
{
cout << "MISS" << endl;
}
}
bool FleetSunk()
{
int m;
int n;
for(m=0;m < 25; m++)
{
for(n=0;n<25;n++)
{
if(ocean[m][n] == '#')
{
cout << "You still have ships remaining" << endl;
}
else
{
cout<< "You have hit all the ships. GAME OVER!" << endl;
return true;
}
}
}
}
Your FleetSunk function has two problems. One should have been a compiler warning, and one is a logical problem.
Firstly, not all paths in the function return a value... Technically. Although in your case that's not quite true because of the logic problem. Let me be more specific: If your entire board is populated with '#', and no shots are taken, then the function behaviour is undefined. It completes the loop and then does not return a value.
So now let's do the logic. You cannot know whether there are any un-hit ship locations until you have examined the entire board. That means you cannot exit from your inner loop in the way you are doing. How about instead you return false if you encounter an "alive" position, and return true at the end of the function (which is only reached if you never encounter an "alive" position).
bool FleetSunk()
{
for( int m = 0; m < 25; m++ )
{
for( int n = 0; n < 25; n++ )
{
if( ocean[m][n] == '#' ) return false;
}
}
return true;
}
See in the comments under your question for other suggestions related to how you are calling FleetSunk in your loop. I also recommend (as evident in my code example) that you don't write stuff to cout in a function that is testing for some condition. It's the responsibility of the caller to do that, not the function itself.
Finally, I would just like to say that the line FleetSunk == false; above your loop really does not do what you might think. That will take the function pointer, convert it to boolean and compare it with false. It's a crazy thing to do, and also useless because the resulting value isn't used for anything. Just delete that line.
The code I am using is:
#include <iostream>
using namespace std;
int reverse (int number){
int t = number, m = 0;
do
{
m = m*10 + t%10;
} while(t /= 10);
return m == number;
}
bool isPalindrom(int number){
bool Palindrom = reverse(number);
if(Palindrom == true){
return true;
} else {
return false;
}
return 0;
}
int main()
{
int number;
cout << "Please input a number " << endl;
cin >> number;
if(isPalindrom){
cout << "This is a Palindrom" << endl;
} else {
cout << "This is not a Palindrom" << endl;
}
}
The issue I am having is that isPalindrom is always evaluating to true. I believe it is because I am trying to set this up incorrectly. The program asks us to use the two functions bool isPalindrom(int number) and int reverse(int number). I'm just learning to use functions in C++ so i'm not to sure what I should do. Should I have reverse return the numbers flipped self (m) then in palindrom compare number to m and if it evaluates to true, it will return true. Then in the main check with an if statement to see if isPalindrom is true/false.
You are not calling the function correctly.
if(isPalindrom){
cout << "This is a Palindrom" << endl;
} else {
cout << "This is not a Palindrom" << endl;
}
To call it you have to supply a parameter like this
if (isPalindrom(number)) {
....
In your code isPlanindrom is (I believe, but actually it does not matter if I am right on this point) a function pointer and because it is in the condition of if it gets converted to a bool, which is true always.
PS: I just noticed that I was too fast in writing the answer. I just saw this one problem and didnt look at the rest of the code. It seems like you need to learn about very basics which would be too much to cover here in an answer. My suggestion: Get a book and rtfm :P
In main, you are evaluating the existence of a function called isPalindrom; you aren't actually calling the function. if(isPalindrom){ should become if(isPalindrom(number)){.
You forget to call isPalindrom with an argument. Here's the fix:
#include <iostream>
using namespace std;
bool reverse (int number){
int t = number, m = 0;
do
{
m = m*10 + t%10;
} while(t /= 10);
return m == number;
}
bool isPalindrom(int number){
return reverse(number);
}
int main()
{
int number;
cout << "Please input a number " << endl;
cin >> number;
if(isPalindrom(number)){
cout << "This is a Palindrom" << endl;
} else {
cout << "This is not a Palindrom" << endl;
}
}
I've also:
simplified your isPalindrom() function to a simple return statement;
set the return of reverse from int to bool.
You can try a LiveDemo
Short answer: you forgot to call isPalindrom.
Long answer: isPalindom decays to a nonnull function pointer, and nonnull pointers test true, this you always see the the if branch taken.
Also:
Yes, judging both by the name and the return type, reverse is intended to return the reverse of a number.
And correspondingly, it is the job of isPalindom to do the actual comparisons.
Furthermore, in most cases,
if (boolean) { return true; }
else { return false; }
should be replaced with
return boolean;
Finally, you really ought to be testing whether or not cin succeeded and your input is valid. (e.g. is the user allowed to enter 0? -73? Zero?)
hi im trying to do a while loop, im new to programming and reading online i cant really get my head around it, i have used flag to show that the inputted name matches the name in the data file, i want to do this so that after i know it doesnt match it loops it the whole thing again, i have no clue how to implement this,
{
clrscr();
cout << "This Is The Option To Delete A Record\n";
char yesno;
char search;
char name[21];
int flag = 0;
cout << "Enter Employee Name : ";
Input(name,20);
for (int r=0;r<row;r++)
{
if( strnicmp(name, emp[r].first_name, strlen(name) ) == 0 )
{
flag = 1;
clrscr();
cout << "Employee Number - " << emp[r].employee_number << endl;
cout << "Name - " << emp[r].first_name << " " << emp[r].surname << endl;
cout << "Department Number - " << emp[r].department_number << endl;
cout << "Week Ending Date - " << emp[r].weekend << endl;
cout << "Delete This Record (Y/N)? : ";
Input(yesno);
yesno = tolower(yesno);
if ( yesno == 'y' )
{
emp[r].deleted = true;
cout << "Record Has Been Deleted";
}
else if ( yesno == 'n')
{
cout << "Record Hasn't Been Deleted";
}
}
}
if (flag == 0)
{
cout << "There Are No Matching Records" << endl;
}
pressKey();
}
It's pretty simple, so have a bunch of code you want to keep executing it while a flag is zero, so that's just
int flag = 0;
while (flag == 0)
{
// whole bunch of code
}
That's it, just replace 'whole bunch of code' with the code you've written above.
Implementing this in a while loop would look like this:
bool flag=false;
while(!flag){
...
if(<find a match>) flag=true;
}
Assuming you understand the for loop, I think you can understand the while loop quite easily based on the comparison of for and while.
See, you used a for loop:
for (int r=0;r<row;r++){
// do stuff
}
There are 3 key points here.
int r=0 This is your initial condition.
r<row This is your condition which keeps the loop running.
r++ This is what happens at the end of each iteration of loop.
To rephrase the statements above:
Considering r equals zero initially, while r is less than row, increment r.
Now we can easily see how while loop is striking us:) To implement this, consider the following while loop example:
int r=0; //(1)
while(r<row){ //(2)
//do stuff
r++; //(3)
}
See, now the 2 loops do practically the same thing.
If you want to do operations based on a flag, you can also prefer an infinite loop:
while(1==1){
if(some condition)
break;
}
as well as an infinite for loop:
for(;;){
if(if some condition)
break;
}
Again, 2 loops are practically the same.
so basically, you have a file with some data. And also, you accept some data from the user.
And then you perform a comparison between the appropriate fields of the two sets.
Why would you want to do it all over again once the entire comparison (file process) is done?
if you simply want to run an infinite loop, you can do this:
while(true)
{
//your code
}
you can do same with a for loop also. infact for loop and while loop both are same except for the syntax. i.e. an infinite for loop.
for (int r=0;r<row;r++)
{
if(r==row-1)
{
r=0;
}
}
I guess what you want to do is to, once one set of user input doesn't match the file content, you want to take another set and match it again and so on.
so you don't need an infinite or always executing loop for this.
Just make your comparison module a separate function which should accept the set of user inputs. All you do is accept user inputs and show the result. And give the user an option to re-enter inputs.
Below is simple algo for what you want.
int main()
{
char a='a';
while(a != '~')
{
TakeUserInput();
if(PerformComparison())
{
cout << "Success";
break;
}
}
}
inside TakeUserInput() you do all those cin << to set a global array or set of global variable. also, you cin << a, to terminate program at your will.
and inside PerformComparison(), you do what you have posted here in your question.