Using C++ What could possibly the best way for a sequence to run only once? To make it clearer for example that I have a program in where you need to guess a string, if the user entered hint I would display the hint of the word but I would only allow it once... I am currently doing this:
bool hintLock = false;
...
if (guess == "hint"){
if (!hintLock){
cout << hint << endl;
hintLock = true;
}
else
cout << "I've given you the hint" << endl;
}
Here's my code:
#include <iostream>
#include <string>
using namespace std;
void main(){
string guess;
bool hintLock = false;
cout << "Guess one of StackExchange's best site: Type \"hint\" for hint" << endl << endl;
do{
cout << "Guess > ";
cin >> guess;
if (guess == "hint"){ // Here it is
if (!hintLock){
cout << hint << endl;
hintLock = true;
}
else
cout << "I've given you the hint" << endl;
}
}
while (guess != "stackoverflow");
cout << "You've got it right!" << endl;
}
Is there any much better statement to do this? or is it already the best?
I suspect that either you are overanalyzing things or you haven't adequately described the real problem. From the code you've posted, I see no reason why you shouldn't wrap the code you want to execute in to a function and then simply call that function one time.
void blahBlah()
{
// blah blah
}
int main()
{
if (userInput == "hint")
blahBlah();
}
Perhaps what you meant is that in your program you have a main loop which executes until program termination, and in that loop you accept input from the user. The user is allowed to ask for a hint, but only once during the program's run. The first time the ask for a hint they are given one, but subsequent times they are not.
I still believe simple is better than fancy (read: complex). To that end, I start with having a bool scoped outside of the main loop which you check each time they ask for help:
int main()
{
bool displayedHint = false;
// program's main loop
for (bool endProgram = false; !endProgram; )
{
std::string command = getUserInput();
if (command == "hint")
{
if (displayedHint)
{
cout << "I already gave you a hint!\n";
}
else
{
displayHint();
displayedHint = true;
}
}
}
}
If you want to make sure it only shows once for any particular run of the program (anything more global than that is pretty complicated and platfrom-specific), all you need is a global boolean to protect the function. For example:
bool shownHint = false;
void showHint() {
if (!shownHint) {
cout << "The hint is: ........" << endl;
shownHint = true;
} else {
cout << "Hint has already been shown, no cheating!" << endl;
}
Whenever you think you might want to show the hint, call showHint() and it will show (or not) as appropriate.
The trick is making sure the variable is global (or a static, in a class, which looks almost the same), so that it doesn't get reset during your loop or otherwise while the program is running.
If you need to persist between runs, you could write to a file, check a server, set a registry key, or any number of other options.
I think that the most appropriate iteration statement is do-while. It allows at least one iteration
for example
do
{
std::cout << "Enter your word: ";
std::string answer;
std::cin >> answer;
// some other stuff
} while ( false );
Or
bool allow = true;
do
{
std::cout << "Enter your word: ";
std::string answer;
std::cin >> answer;
// some other stuff
} while ( allow = !allow );
You can use flags that are boolean, that represent a state in your system. Once the state is "defined", you can then query the state and find if it is "set" or "cleared"..
to be more precise
bool hasHinted = false; // unset or cleared( also definition of a state variable)
if(hasHinted == false){
//do something
hasHinted = true; // set
}else{
// do nothing
}
I think the OP is looking for a piece of code similar to singleton init. i.e.: only create the singleton once, and after that always return the pointer.
void Init() {
static bool isInitialized = false;
if (!isInitialized) {
isInitialized = true;
doRealInit();
}
}
the same thing done with std::call_once as a comment suggests:
std::once_flag flag;
void do_once() {
std::call_once(flag, [](){ std::cout << "Called once" << std::endl; });
}
in my opinion it's not really more readable or shorter.
Related
I'm making a terminal app just to increase my OOP skills. I have this RunApplication()function and LoginCustomer()function to make a customer log in to the application.
This code is my RunApplicationfunction:
void RunApplication(){
while (key!='q'){
printUI();
std::cin >> key;
if (key == '1'){
LoginCustomer();
}
..... // There are many other if statements but not included here since there are many and irrelevant.
and this is my LoginCustomerfunction:
void LoginCustomer(){
std::cout << "***************************" << std::endl;
std::cout << "1 ----> Show Available Cars" << std::endl;
std::cout << "2 ----> Show Available Motors" << std::endl;
std::cout << "3 ----> Show Available Trucks" << std::endl;
std::cout << "always 'l' ----> Logout" << std::endl;
std::cout << "always 'q' ----> Exit" << std::endl;
std::cout << "***************************" << std::endl;
std::cin >> key;
if (key == 'l') //if you want to go back main page which was loaded into terminal with RunApplication()
return;
else if(key == 'q')
exit(EXIT_FAILURE);
}
return; // What if I just call RunApplication() here again instead a simple return, wouldn't program be the most inefficient program ?
else if(key == 'q')
exit(EXIT_FAILURE);
My question is can I forbid a function to be called more than one time in a program(or main) ? Because if you think about it, in the LoginCustomer If you press "l" it gets you to the main page by simply ending the LoginCustomer()using returncommand. But what if I would just use RunApplication()there again instead of returncommand wouldn't be there a inefficiency in program ? So I was thinking is there any keywordto forbid a function to be called more than one time ?
My question is can I forbid a function to be called more than one time in a program(or main) ?
You can use local static variables to have a guarantee that the code is called only once.
Example:
struct FunctionObject
{
FunctionObject()
{
std::cout << "I will be called only once" << std::endl;
}
};
void Do()
{
static FunctionObject fo;
}
int main()
{
std::cout << "First" << std::endl;
Do();
std::cout << "Second" << std::endl;
Do();
}
But for your UI example I would prefer a design with simple state machine which take care that states can only be activated in a given order.
I'm making a terminal app just to increase my OOP skills.
Your example code did not have any object nor any OOP design. Maybe you have some classes/objects elsewhere, but I can't see any OOP design in your code.
You can use std::call_once: https://en.cppreference.com/w/cpp/thread/call_once
static std::once_flag flag;
std::call_once(flag, []{
//code here..
});
Local variables are stored and created on the stack. Static local variables are constant and remain between calls so:
bool my_one_off_function ()
{
static int iCount = 0; // static only intialized at start of program
if (! iCount++) // First time only will be zero
{
do_first_call_stuff ();
return true;
}
else
return false;
}
Alternatively, in your specific case, when the login request is received, you could just check if the login credentials already exist before calling the login function. This would be the more "elegant" solution because it allows logout etc.
I have a function which takes an int value from another function. When I type a wrong int value it works as intended (calls the same function recursively & lets me enter a new number) but when I type anything other than an int (a, %, etc) it calls the function recursively but gets stuck in an infinite loop. Any help/insight would be great as I am in the learning stages of C++ Programming.
Here is my Full code snippet (49 Lines)
To summarize what I am asking is how would I properly go about displaying an error and returning back to the Main Menu without triggering the infinite loop when a non-int value is given.
int MainMenu();
void MainMenuSelection(int x);
int main()
{
MainMenuSelection(MainMenu());
return 0;
}
int MainMenu() {
int selection;
std::cout << "C++ Tutorials Main Menu\n";
std::cout << "----------------------------------------------\n";
std::cout << "1 - Chapter #1\n";
std::cout << "2 - Chapter #2\n";
std::cout << "3 - Chapter #3\n";
std::cout << "----------------------------------------------\n";
std::cout << "Please enter a cooresponding value: ";
std::cin >> selection;
if (std::cin.fail()) {
std::cout << "Input must be an integer";
}
else {
return selection;
}
}
void MainMenuSelection(int x) {
if (x == 1) {
std::cout << "\nChapter #1 is unavailable.\n";
std::cout << std::string(22, '\n');
MainMenuSelection(MainMenu());
}
else if (x == 2) {
std::cout << std::string(2, '\n');
ChTwoMenuSelection(ChTwoMenu());
}
else if (x == 3) {
std::cout << std::string(2, '\n');
ChThreeMenuSelection(ChThreeMenu());
}
else {
std::cout << "\nThere was an incorrect value submitted.";
std::cout << std::string(22, '\n');
MainMenuSelection(MainMenu());
}
}
The function MainMenuSelection( int x ) requires an int. The function call in the main function thinks it gets this by calling a function which should return an int namely int MainMenu(). But this function does not do what you should expect from a function which has been declared in this way. You should make sure that a function should ALWAYS return the value (except for a void of course).
There are static code analyzers like Cppcheck which can help you to analyse your code and find possible problems like the one you stated above.
Another tip would be to think about what happens when you execute the code. Especially when your code is still quite small you can manually go through the statements to see what path it takes, so you can find out where the program fails.
I have been working on this little program in Visual Basic 2013 in an attempt to create a sort of tiered structure for user-input commands. Basically, I want the first of a two word input to direct the program to an area of code with a set of responses for the second word. In this program, the first word can either be "human" or "animal." These words direct the program to functions that select the kind of animal or human.
#include "stdafx.h"
#include <iostream>
#include <sstream>
void ifAnimal(std::string b) //This is the set of responses for a first word of "Animal"
{
if (b == "pig")
{
std::cout << "It is a pig." << std::endl;
}
if (b == "cow")
{
std::cout << "It is a cow." << std::endl;
}
}
void ifHuman(std::string b) //This is the set of responses for a first word of "Human"
{
if (b == "boy")
{
std::cout << "You are a boy." << std::endl;
}
if (b == "girl")
{
std::cout << "You are a girl." << std::endl;
}
}
int main()
{
while (1)
{
std::string t;
std::string word;
std::cin >> t;
std::istringstream iss(t); // Set up the stream for processing
int order = 0;
//use while loop to move through individual words
while (iss >> word)
{
if (word == "animal")
{
order = 1;
continue; //something wrong with these continues
}
if (word == "human")
{
order = 2;
continue;
}
if (order == 1)
{
std::cout << "The if statement works" << std::endl;
ifAnimal(word);
}
if (order == 2)
{
std::cout << "This one too" << std::endl;
ifHuman(word);
}
}
}
return 0;
}
The problem is that whenever the program reaches the continue statements, the if statements calling my functions are not triggered. No text is displayed at all. If the continue statements are removed, the if statements trigger, but then the corresponding function has the wrong word. Am I unaware of something that those continues are doing? Is there a better way to accomplish what I want to do?
what continue means is skip the rest of the loop and go back to the top. whatever is after the continue statement won't be executed if continue gets hit.
It looks like you expect your word to be two words at the same time, so once you execute ifAnimal() none of the cases in ifAnimal will be met. word will never be "pig" or "cow" when you call that method because you only ever call that method when word is equal to "animal", and you don't change it after that.
Continue means "Go immediately to the top of the loop, and start over again". You do not want that at all.
//use while loop to move through individual words
while (iss >> word)
{
if (word == "animal")
{
order = 1;
}
else if (word == "human")
{
order = 2;
}
if (order == 1)
{
std::cout << "The if statement works" << std::endl;
ifAnimal(word);
}
if (order == 2)
{
std::cout << "This one too" << std::endl;
ifHuman(word);
}
}
So its often come up in my classes that i need to be able to have a program where the user can do things multiple times.
so I write something like
boolean continue=true;
while (continue) {
//do code
boolean isAnswerGood=false;
while (!isAnswerGood) {
cout << "Do you wish to continue" << endl;
string answer;
getline(cin, answer);
if (answer=="y") //or something else
isAnswerGood=true;
else if (answer=="n") {
isAnswerGood=true;
continue=false;
} else
cout << "That wasnt "y" or "n" please type something again" << endl;
}
}
This seems bloated and a lot of code for something so simple. Im willing to think outside of the box with this one, so if anyone can give me a clue as to a better solution to this, id appreciate it.
Break it into separate functions. (Almost always the answer to "how do I write an eloquent...?")
For example:
do {
// something
} while (UserWantsMore());
/////////
bool UserWantsMore() {
std::string answer = GetAnswer("Continue?");
while (!GoodAnswer(answer))
answer = GetAnswer("Please answer 'yes' or 'no'!");
return IsAnswerYes(answer);
}
bool GoodAnswer(const std::string& answer) {
return !answer.empty() && (answer[0] == 'y' || answer[0] == 'n');
}
bool IsAnswerYes(const std::string& answer) {
return !answer.empty() && answer[0] == 'y';
}
std::string GetAnswer(const char* prompt) {
std::cout << prompt << std::cend;
std::string answer;
std::getline(std::cin, answer);
return answer;
}
Sorry, but that is about the right amount of code. C and C++ are relatively verbose compared to some other languages.
However, if this is a common problem, you can abstract it out and make a function out of it. The function would be very similar to what you already have, but then you would call it something like this:
boolean again = true;
while (again) {
// do code
again = ask_user("Do you wish to continue?", "y", "n");
}
The arguments to ask_user() should be the question to ask, the answer to accept that means "yes", and the answer to accept that means "no". The error message (about an unexpected input) can be made using the second and third arguments, so we don't really need to pass it in.
Of course, the problem could be even more complicated than this... what if your code will be used by non-English speakers? If you needed to handle localization, you could make a basic function that has all strings passed in including the error message, and then make a wrapper that the user calls with a language specification. Here's an example, this time using the "infinite loop" in C++:
for (;;) {
// do code
if (!ask_user_yesno("en_us")) // locale: English, USA
break;
}
If you are just wanting to make what you already have do the same thing with a little less code, this will work.
string answer="y";
while (answer=="y") {
//do code
for(;;) {
cout << "Do you wish to continue" << endl;
getline(cin, answer);
if ((answer=="y")||(answer=="n")) break;
cout << "That wasnt \"y\" or \"n\" please type something again" << endl;
}
}
Slightly less code, but slightly more obfuscated:
string answer="y";
while (answer!="n") {
if (answer=="y") {
//do code
} else {
cout << "That wasnt \"y\" or \"n\" please type something again" << endl;
}
cout << "Do you wish to continue" << endl;
getline(cin, answer);
}
Here's a version that uses <termios.h> to get the answer. It uses more code, but behaves more "eloquently".
int getch (void)
{
int c;
struct termios oldt;
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return c;
}
bool again (std::string prompt, std::string yes, std::string no)
{
bool doyes = false;
bool dono = false;
for (;;) {
std::cout << prompt;
int c = getch();
std::cout << std::endl;
doyes = (yes.find(c) != yes.npos);
dono = (no.find(c) != no.npos);
if (doyes || dono) break;
std::cout << "Type [" << yes << "] for yes, or [" << no << "] for no.";
std::cout << std::endl;
}
return doyes;
}
You can use it as others have suggested:
do {
// the interesting code
} while (again("Do you wish to continue? ", "y", "n"));
How about something like:
void DoYesCode()
{
// Do the code for the yes stuff...
}
...
do{
cout << "Do you wish to continue" << endl;
string answer;
getline(cin, answer);
if (answer=="y")
DoYesCode();
else if (answer=="n")
break;
else
cout << "That wasnt 'y' or 'n' please type something again" << endl;
} while(true);
I am practicing some code implementing different data structures. For this example I am trying to implement a simple stack data structure. So far it works as intended, but I keep getting Hex characters when trying to display my stack. Could anyone help me with figuring out why this is the case?
Also I am trying to get better at structuring my code properly, can anyone that is already involved in the industry please give me some constructive criticism as to what I have coded so far. Thanks.
#include <iostream>
using namespace std;
// stack_MAX == maximum height of stack
const int stack_MAX = 10;
class stack{
public:
stack(){
//Constructor initializes top of stack
top = -1;
}
bool isFull(int top){
//isFull() will check to make sure stack is not full
//Will return TRUE if stack is FULL, and FALSE if
//stack is NOT FULL
if(top == stack_MAX - 1)
return true;
else
return false;
}
bool isEmpty(int top){
//isEmpty() will check to make sure stack is not empty
//Will return TRUE if stack is EMPTY, and FALSE if
//stack is NOT EMPTY
if(top == -1)
return true;
else
return false;
}
void push(int x){
//push() will push new element on top of stack
if(isFull(top)){
cout << "Sorry, but the stack is full!" << endl;
exit(1);
}
else{
top++;
x = stk[top];
}
}
void pop(){
//pop() will pop the top element from the stack
if(isEmpty(top)){
cout << "Sorry, but the stack is empty!" << endl;
exit(1);
}
else{
cout << stk[top] << " is being popped from stack!" << endl;
top--;
}
}
void display_stack(){
//diplay_stack() will show all elements currently in the stack
int temp; //will temporarily hold position of stack
temp = top;
while(!isEmpty(temp)){
cout << stk[temp] << endl;
temp--;
}
}
private:
int top;
int stk[stack_MAX];
};
int menu(){
int choice;
cout << "Welcome to my stack!" << endl;
cout << "What would you like to do? (select corresponding #)" << endl << endl;
cout << "1. Push" << endl;
cout << "2. Pop" << endl;
cout << "3. Display" << endl;
cout << "4. Quit" << endl;
cin >> choice;
return choice;
}
int main()
{
int selection, x;
stack myStack;
selection = menu();
while(selection != 4)
{
switch(selection){
case 1:
cout << "please enter number to be pushed: ";
cin >> x;
myStack.push(x);
selection = menu();
break;
case 2:
myStack.pop();
selection = menu();
break;
case 3:
myStack.display_stack();
selection = menu();
break;
default:
cout << "Oops that's not a selection, try again" << endl;
selection = menu();
break;
}
}
cout << "Thank you for stopping by and using my stack!" << endl;
system("pause");
return 0;
}
A statement in your push functin is wrong, modified as below:
void push(int x)
{
//push() will push new element on top of stack
if(isFull(top))
{
cout << "Sorry, but the stack is full!" << endl;
exit(1);
}
else
{
top++;
/***************************
x = stk[top];
****************************/
stk[top] = x;
}
}
Advice:
Learn to debug, here is the tutorial
Include the head file cstdlib when you want to use exit in your
code
Do not name your class with the same name for any classes in STL
As pointed out by prehistoric penguin, your push() function is incorrect:
x = stk[top];
Should be changed to:
stk[top] = x;
I wanted to comment anyway to offer some general comments as you requested:
If statements like this can be replaced by a single line of code:
if(top == stack_MAX - 1)
return true;
else
return false;
becomes:
return (stack_MAX - 1 == top);
Put constant expressions on the left-hand side of your comparison expression. For example:
(top == stack_MAX - 1)
becomes:
(stack_MAX - 1 == top)
The reason is that one day you will accidentally type something like:
(top = stack_MAX - 1)
and you or somebody else will waste a lot of time debugging it :)
Your isFull() and isEmpty() functions shouldn't take a parameter. They should just use the private member variable top. How would somebody call these functions without access to top, which you've correctly made a private member?
In general, avoid using. In my opinion it defeats the whole purpose of namespaces. using namespace std is a commonly used exception, but even then, is it so hard to type std::cout?
Always put curly braces around the clauses of your if statement, even if they are just one line. It's easy to forget to add braces if you need to add more statements to a clause later on, which can be quite confusing.
Your code formatting is pretty good, but pick a bracket style and be consistent. Either always put the opening curly brace on the same line as the function header / control statements etc, or always put it on the line afterwards.
Hope that helps.