Does C++ have any type of utility to return to the beginning of a function after a function call? For example, example the call to help() in the calculate function.
void help()
{
cout << "Welcome to this annoying calculator program.\n";
cout << "You can add(+), subtract(-), multiply(*), divide(/),\n";
cout << "find the remainder(%), square root(sqrt()), use exponents(pow(x,x)),\n";
cout << "use parentheses, assign variables (ex: let x = 3), and assign\n";
cout << " constants (ex: const pi = 3.14). Happy Calculating!\n";
return;
}
void clean_up_mess() // purge error tokens
{
ts.ignore(print);
}
const string prompt = "> ";
const string result = "= ";
void calculate()
{
while(true) try {
cout << prompt;
Token t = ts.get();
if (t.kind == help_user) help();
else if (t.kind == quit) return;
while (t.kind == print) t=ts.get();
ts.unget(t);
cout << result << statement() << endl;
}
catch(runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
}
While technically my implementation of a help function works fine, it's not perfect. After help is called, and returns, it proceeds with trying to cout << result << statement() << endl; which isn't possible because no values have been entered. Thus it gives a little error message (elsewhere in the program) and then proceeds on with the program. No problem with functionality, but it's ugly and I don't like it (:P).
So is there any way for when the help function returns, to return to the beginning of calculate and start over? (I played around with inserting a function call in if(t.kind == help_user) block to call calculate, but as I figured that just delays the problem rather than solving it.)
You can use goto, but the moment you do that consider yourself over. It's considered bad practice and good uses of it are rare and far apart.
I think what you're looking for is continue:
void do_calculate(void)
{
while (true)
{
cout << prompt;
Token t = ts.get();
if (t.kind == help_user)
{
help();
continue; // <- here
}
else if (t.kind == quit)
{
return;
}
while (t.kind == print)
{
t = ts.get();
}
ts.unget(t);
cout << result << statement() << endl;
}
}
void calculate()
{
try
{
do_calculate();
}
catch (const std::exception& e)
{
cerr << e.what() << endl;
clean_up_mess();
}
}
I have also reformatted your code. I think this is more readable, to each his own but just wanted to let you compare.
The try/catch clause is now no longer interfering with the calculation function.
The 'if' statements use brackets for consistency. Also, it's much easier to read, because I know whatever the if is controlling is within these brackets.
The catch will catch a std::exception, rather than runtime_error. All standard exceptions inherit from std::exception, so by catching that you know you can catch anything.
This might be what you're looking for?
if (t.kind == help_user) {
help();
continue;
}
You can return to the top of a loop with the continue statement. That's the easiest way to achieve what you want since you have a while loop surrounding your code:
if (t.kind == help_user) {
help();
continue;
}
There's also the goto statement though that is almost always a bad idea. I'll leave that to you to read about on your own. For more information read up on "control flow".
In this specific instance I'd probably opt for just restructuring your code slightly by adding an else statement, like so:
if (t.kind == help_user)
help();
else if (t.kind == quit)
return;
else {
while (t.kind == print)
t=ts.get();
ts.unget(t);
cout << result << statement() << endl;
}
Yes, it is called logic:
void calculate()
{
while(true)
{
try {
cout << prompt;
Token t = ts.get();
if (t.kind == help_user)
help();
else
{
if (t.kind == quit) return;
while (t.kind == print) t=ts.get();
cout << result << statement() << endl;
}
ts.unget(t); // if statement above needs this then leave it in and
// add one call after help() as well ... not sure from code
}
catch(runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
}
Related
I don't understand why but the std::vector is not giving anything after i put a class pointer in the array.
// runs at start
void States::AssignState(GameState* state) {
_nextVacentState++;
_states.push_back(state);
}
// executes in a loop
void States::ExecuteCurrentState() {
// protection incase there is nothing in the array or the current state is not grater than the size of the array (not the problem after i nerrowed the problem down)
if (_nextVacentState == 0) std::cout << "Error: There is no states, setup some states then try again" << std::endl; return; // there is no states
if (_currentState >= _states.size() - 1) std::cout << "Error: Current State is grater than all possable states" << std::endl; return;
// The program just freezes at this and i can figure out why
_states[0]->tick();
std::printf("S");
}
This is one of the reasons I'd suggest getting in the habit of using curly braces for all if statements, even ones that live on a single line.
A problem line:
if (_nextVacentState == 0) std::cout << "Error: There is no states, setup some states then try again" << std::endl; return;
Let's add some newlines to make it clearer what's happening
if (_nextVacentState == 0)
std::cout << "Error: There is no states, setup some states then try again" << std::endl;
return;
That return statement is getting executed unconditionally, because only the first statement after if(_nextVacentState==0) is actually part of the if. So the compiler executes it as if it had been written like this:
if (_nextVacentState == 0)
{
std::cout << "Error: There is no states, setup some states then try again" << std::endl;
}
return;
But, what you want needs to be written like this instead:
if (_nextVacentState == 0)
{
std::cout << "Error: There is no states, setup some states then try again" << std::endl;
return;
}
You have same problem in the next if check for _currentState, as well.
I am stuck with the input with no enter input.
I tried to use kbhit() + getch() from conio.h and it doesn't work on my system (Win10 and Ubuntu - unistd.h and termios.h). Program just skips block with these functions.
Then I used GetAsynkKeyState from windows.h. It works in the game (Level) though buggy, but doesn't in a Menu. Program as well skips (or something) block with input dispatch.
Menu input:
// The menu interface
bool Menu::SelectLevel() {
cout << "Select the level:" << endl;
size_t arrow_pos = 0;
// Prints level's names and char to exit the game
for (size_t i = 0; i <= _levels.size(); ++i) {
// Draw arrow before selected level
if (i == arrow_pos) {
cout << '>' << i + 1 << " - " << _levels[i].first[0] << endl;;
}
// Draw arrow before the exit select
else if (i == _levels.size() && i == arrow_pos) {
cout << '>' << "Exit" << endl;
}
// Draw the exit option
else if (i == _levels.size()) {
cout << ' ' << "Exit" << arrow_pos << endl;
}
// Draw levels list
else {
cout << ' ' << i + 1 << " - " << _levels[i].first[0] << endl;
}
}
// Input from keyboard TODO DOESN'T WORK!:
// If 's' pressed move arrow down
PoollingDelay(1);
if (GetAsyncKeyState(0x53) & 0x8000) {
++arrow_pos;
// If arrow reached top it goes to the bottom
if (arrow_pos == _levels.size() + 1) {
arrow_pos = 0;
}
}
// If 'w' pressed move arrow up
else if (GetAsyncKeyState(0x57) & 0x8000) {
--arrow_pos;
// If arrow reached bottom it goes to the top
if (arrow_pos == 65535) {
arrow_pos = _levels.size() + 1;
}
}
// If Return pressed
else if (GetAsyncKeyState(VK_RETURN) & 0x8000) {
// Don't think it would be worthy
if (arrow_pos < 1 || arrow_pos > _levels.size() - 1) {
throw runtime_error("Wrong select: " + to_string(arrow_pos));
}
// If player tired of this shit
if (arrow_pos == _levels.size() - 1) {
ClearTerminal();
return false;
}
// Play
PlayLevel(arrow_pos);
}
ClearTerminal();
return true;
}
Level input:
// TO DO DOESN'T WORK!:
void Level::ReadCommand() {
PoollingDelay(100);
if (GetAsyncKeyState(0x57)) {
Move(_NORTH);
}
else if (GetAsyncKeyState(0x41)) {
Move(_WEST);
}
else if (GetAsyncKeyState(0x53)) {
Move(_SOUTH);
}
else if (GetAsyncKeyState(0x44)) {
Move(_EAST);
}
else if (GetAsyncKeyState(0x45)) {
throw runtime_error(exit_the_lvl);
}
}
Short answer: you can't using only C++ and its standard library.
This is because the language is not designed to handle low-level hardware events. To do this, you need to rely on a separate library, dedicated to handle I/O. Lots of them, some are more or less easy to integrate. For simple games, SDL is nice.
Beginner programmer here, working in Visual Studio.
vector<string> fileParse(vector<string> & inputStrings, string & fileName) {
ifstream x;
x.open(fileName);
cout << "attempting to open file" << endl;
if (!x.is_open()) {
cout << "Bad input file name. Input was: " << fileName << endl;
throw lab0badInput;
}
else {
string temp;
while (x >> temp) {
inputStrings.push_back(temp);
}
x.close();
}
return inputStrings;
}
Calling throw causes my program to crash instead of throwing the correct value and exiting. Can somebody explain why?
Thanks!
use try and catch block instead :
try { /* */ } catch (const std::exception& e) { /* */ }
So I am running a program that has the users input a command. I have a text file with a list of acceptable command words. I open the file first to make sure that what the user input is indeed a valid command, but after that step I close the file. After that, I use some if/else statements to run a function corresponding to the command. One command is to list all of the valid commands, which requires me to open the file again and simply output the contents. At this step, however, the program simply outputs nothing. Here is the code:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
void mainMenu();
void comJunc(string comString);
void comList();
bool isCommand(string comString);
int main()
{
mainMenu();
return 0;
}
void mainMenu()//This function inputs a command
{
string comString;
bool isCom = false;
cout << endl;
cout << "||Welcome to the main menu||\n\nPlease enter a command. For a list of commands type \"comlist\"\n";
do
{
cout << ">";
cin >> comString;//Input command "comlist"
isCom = isCommand(comString);//Checks if command is valid
if(isCom == false)
cout << endl << "**Error** Command \"" << comString << "\" was not found. Type \"comlist\" for help\n";
}while(isCom == false);
comJunc(comString);
return;
}
bool isCommand(string comString)
{
bool sFlag = false;
string inString;
ifstream comFile;
if(comFile.is_open() == false)
{
comFile.open("commands.txt");
}
while(getline(comFile, inString))
{
if(comString == inString)
sFlag = true;
}
comFile.close();
return sFlag;
}
void comJunc(string comString)//Executes function based on command
{
//comlist, continue, start, customize, exit
if(comString == "comlist")
{
comList();//Calles comList function
}
else if(comString == "exit")
{
//does nothing (exits)
}
else
cout << "Error in comJunc";
return;
}
void comList()
{
string inString;
ifstream comFile;
if(comFile.is_open() == false)
{
comFile.open("command.txt");
}
while(getline(comFile, inString))//This loop is not executed
{
cout << "Random text";//Text is not displayed
cout << endl << inString;
}
cout << endl;
comFile.close();
return;
}
The console looks like this:
||Welcome to the main menu||
Please enter a command. For a list of commands type "comlist"
>
At which point I type "comlist"
The desired result is for the command.txt file to output its contents. It should look like this:
comlist
command2
command3
command4
command5
Instead, the screen is left blank and the program exits as usual.
Any help would be greatly appreciated. Thanks.
ok, so im kinda new to C++ and im trying to build a basic login program. iv got it to work except for one problem... this is what iv got
void InitialLogin()
{
cout << "\t\t ===========LOGIN==========" << endl;
cout << "\t\n\n\n\tUsername/>> " ;
getline(cin, sUsername);
cout << "\t\n\tPassword/>> ";
getline(cin, sPassword);
if (sUsername == "myname" && sPassword == "mypass")
{
cout << "\n\t\t\t--ACCESS GRANTED--";
system("CLS");
}
else if (sUsername != "myname" && sPassword != "mypass")
{
SetConsoleTextAttribute(h, FOREGROUND_RED);
cout << "\n\t\t\t--ACCESS DENIED--\n\n\n";
SetConsoleTextAttribute(h, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
main();
}
}
after i run this, if the login was successfull i have the following run after the screen is cleard...
void Initialization()
{
cout << "/>> Aquireing file list......" << endl;
cout << "/>> file list aquired........" << endl;
cout << "/>> determing file location.." << endl;
}
now my problem is, if i get the username or password wrong say once i get the initialization output twice, if i get it wrong twice, the output is three times.
i need to know how to clear the overflow or buffer or something...
please help :)
Your function is attempting to call main(). This is not legal C++.
You should return a status to see if the login worked or not. Then just loop until the status either becomes "true", or the user has run out of chances. Here is a small example:
bool InitialLogin();
int main()
{
int numChances = 3;
int numCount = 0;
bool loginOk = false;
while (numCount < numChances && !loginOk )
{
loginOk = InitialiLogin();
++numCount;
}
if ( !loginOk )
{
// number of chances ran out
return 0;
}
else
{
// proceed. Login was successful
}
}
bool InitialLogin()
{
//...
if (sUsername == "myname" && sPassword == "mypass")
{
//...
return true;
}
// anything here means that the login failed. There is no need for an if()
//...
return false;
}
I feel you are getting this because you are calling the main() function when both the password and username are incorrect (As a side note you might want to change the && in this check to || as you want access to be denied if either the password or username are incorrect).
You might want to consider getting the InitialLogin() function to return a bool to show weather the login was successful or not. If not the get it to run InitialLogin() again if successful then get it to proceed with the code.
In the place where you call InitialLogin() you can use a while loop to get it to repeat.
while(!InitialLogin()){}
So when InitialLogin() is not false (bad login) it will try again and when it is not true (good login) it will continue onto next section of code.