How can reduce recursion within this function - c++

can't figure out how to prevent recursion within this function, any suggestions or
recommendations? I've tried a couple of my own solutions but ran into the error of having
the program crash if wrong inputs and repeatedly entered.
Thanks in advance, DK.
static void CheckPlayerInput()
{
// gets the character entered (as a char)
cin >> input;
//check is actually a char
if (cin.fail())
{
//more recursion, could cause issues, could you find another way?
cout << "Invalid character, try again!" << endl;
CheckPlayerInput();
}
//converts char to upper case
input = toupper(input);
//check the input character
// maps the input keys to the grid reference
//calling the FillSquare method
switch (input)
{
case '1': FillSquare(0, 0); break; //top-left
case '2': FillSquare(0, 1); break; //top-centre
case '3': FillSquare(0, 2); break; //top-right
case '4': FillSquare(1, 0); break; //middle-left
case '5': FillSquare(1, 1); break; //middle-centre
case '6': FillSquare(1, 2); break; //middle-right
case '7': FillSquare(2, 0); break; //bottom-left
case '8': FillSquare(2, 1); break; //bottom-centre
case '9': FillSquare(2, 2); break; //bottom-right
//IF NOT ANY OF THE ABOVE
default:
{
//more recursion, could cause issues
//
cout << "Invalid character, try again!" << endl;
CheckPlayerInput();
}
break;
}
}

Use a do while loop instead
static void CheckPlayerInput()
{
bool invalid = false;
do
{
invalid = false;
// gets the character entered (as a char)
cin >> input;
...
default:
{
//more recursion, could cause issues
//
cout << "Invalid character, try again!" << endl;
invalid = true;
}
break;
}
}
while(invalid);
}
The while loop will repeat as long as the input is invalid

I guess there are many different ways to implement it.
The below might be my approach.
Note:
Filling the square feels like a dedicated task and should therefore be inside it's own function.
Maybe you should use non-static / non-global methods and instead use objects.
Your method CheckPlayerInput is not checking the input. Instead, it's processing it.
static bool
_fillSquare(char type)
{
switch (type)
{
case '1': FillSquare(0, 0); break; //top-left
case '2': FillSquare(0, 1); break; //top-centre
case '3': FillSquare(0, 2); break; //top-right
case '4': FillSquare(1, 0); break; //middle-left
case '5': FillSquare(1, 1); break; //middle-centre
case '6': FillSquare(1, 2); break; //middle-right
case '7': FillSquare(2, 0); break; //bottom-left
case '8': FillSquare(2, 1); break; //bottom-centre
case '9': FillSquare(2, 2); break; //bottom-right
default : return false;
}
return true;
}
// this method does not `check` the player input, but it
// `processes` it. The name should reflect that.
static void
processPlayerInput()
{
// try to retrieve and process input until
// a valid input was given
while (true)
{
cin >> input;
if (!cin.fail ())
continue;
input = toupper(input);
bool success = _fillSquare(input);
if (!success)
{
cout << "Invalid character, try again!" << endl;
continue;
}
return;
}
}

Related

Using while>>cin to keep asking user for input in C++

Code for a blackjack card counting program.
the issue is that it does not exit the while loop upon receiving no cin input from the user.
for example)
User would input x chars and then hit enter to exit the while loop.
#include<iostream>
using namespace std;
int main(){
int count = 0;
char currcard;
cout<<"Enter cards seen on table: "<<endl;
while (cin>>currcard)
{
switch (currcard)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
count++;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
count--;
break;
default:
cout<<"Invalid Entry";
break;
}
}
cout <<"Current count: "<< count << endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
Expecting program to exit when enter is hit by user
You can use cin.get() like this.
while (cin>>currcard)
{
// your logic
if (cin.get() == '\n') {
break;
}
}
In this way, your input is supposed to be something like 1 2 3 4 A J Q ending with Enter.
EDIT
As OP wants undetermined length of input, I suggest to switch the input itself from char to std::string.
This way access is gained to more intuitive and effective I\O operations:
#include <iostream> // std::cin, cout, endl
#include <string> // std::string: can omit this line
#include <cctype> // isspace(): can omit
int main(){
int count = 0;
std::string currcard{""};
std::cout << "Enter cards seen on table: "<< std::endl;
std::getline(std::cin, currcard);
for (char c : currcard) {
if (isspace(c))
continue;
switch (c) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
++count;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
--count;
break;
default:
//std::cout << "Invalid Entry\n";
break;
}
}
std::cout <<"Current count: "<< count << std::endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
Notice I have added a check for white spaces, and removed the message for invalid entries: both simply get ignored. But if needed that line can be uncommented.
Old solution
You can use cin.getline() as suggested in the comments, in conjunction with a flag that triggers exit from the loop once three inputs are given:
#include <iostream>
int main(){
static int count = 0, flag = 0;
char currcard;
std::cout << "Enter cards seen on table: "<< std::endl;
while(std::cin.getline(&currcard, 3)){
switch (currcard)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
++count;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
--count;
break;
default:
std::cout << "Invalid Entry\n";
--flag;
break;
}
++flag;
if (flag == 3)
break;
}
std::cout <<"Current count: "<< count << std::endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
There is also a flag decrement for invalid entries.

'X' or 'x' is meant to be used to quit the calculator. I receive the error "primary expected" (c++) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am a newbie trying to solve the exercise from chapter 6 of Stroustrup's PPP. Everything works fine but 'X' and 'x'. I enter expressions followed by '=' and I receive correct results, but when I hit 'X' or 'x' to quit the program I receive the error "primary expected". Any idea what am I missing?. I am using GCC 8.3.0, VS Code and 'g++ -o nameofexecutable.exe sourcefile.cpp' to compile. I also use windows 10. Here is my code:
#include "std_lib_facilities.h"
class Token {
public:
char kind;
double value;
Token(char ch)
:kind(ch), value(0) { }
Token(char ch, double val)
:kind(ch), value(val) { }
};
class Token_stream {
public:
Token_stream();
Token get();
void putback(Token t);
private:
bool full;
Token buffer;
};
// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0)
{}
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t){
if (full) error("putback() into a full buffer");
buffer = t;
full = true;
}
Token Token_stream::get(){
if (full) {
full=false;
return buffer;
}
char ch;
cin >> ch;
switch (ch) {
case '=':
case 'x': // for "quit" it does not work!
case 'X': // for "quit" it does not work!
case '(': case ')': case '+': case '-': case '*': case '/': case '%':
return Token(ch);
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch);
double val;
cin >> val;
return Token('8',val);
}
default:
error("Bad token");
}
}
Token_stream ts;
double expression();
// deal with numbers and parentheses
double primary()
{
Token t = ts.get();
switch (t.kind) {
case '(':
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected");
return d;
}
case '8': // '8' is used to represent a number
return t.value;
default:
error("primary expected");
}
}
// deal with *, /, and %
double term()
{
double left = primary();
Token t = ts.get();
while(true) {
switch (t.kind) {
case '*':
{
left *= primary();
t = ts.get();
break;
}
case '/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
case '%':
{
int d = primary();
int l = left;
if (d == 0) error("divide by zero");
left = l%d;
t = ts.get();
break;
}
default:
ts.putback(t);
return left;
}
}
}
// deal with + and -
double expression()
{
double left = term();
Token t = ts.get();
while(true) {
switch(t.kind) {
case '+':
left += term();
t = ts.get();
break;
case '-':
left += term();
t = ts.get();
break;
default:
ts.putback(t);
return left;
}
}
}
int main()
try
{
cout << "A simple calculator"<<endl;
cout << "Floating point numbers are acepted"<<endl;
cout << "You can use: '+','-','*','/', and '%'" << endl;
cout << "Enter X or x to quit" << endl;
cout << "Use '=' to solve" << endl;
double val;
while (cin) {
Token t = ts.get();
if (t.kind == 'x') break; // 'q' for quit
if (t.kind == '=') // ';' for "print now"
cout << "=" << val << '\n';
else
ts.putback(t);
val = expression();
}
keep_window_open();
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
keep_window_open();
return 2;
}
Padawan needs to learn about the break statement when using switch/case.
The break prevents execution from falling from one case to the next:
char ch;
cin >> ch;
switch (ch) {
case '=':
// Do something for '=';
break; // exit the case
case 'x': // for "quit" it does not work!
case 'X': // for "quit" it does not work!
return 0; // exit from function.
// No need for break here since return breaks out of the switch.
case '(': case ')': case '+': case '-': case '*': case '/': case '%':
return Token(ch);
// No need for break here since return breaks out of the switch.
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch);
double val;
cin >> val;
return Token('8',val);
}
// No need for break here since return breaks out of the switch.
default:
error("Bad token");
}

C++ program to convert string to numeric digits

I'm trying to create a function that converts input words to numeric digits like a mobile numpad. It is for an assignment. I cannot use cstring or character arrays.
Can someone please identify and correct the error in my code? It currently gives the error: ISO C++ forbids comparison between pointer and integer [-fpermissive].
I am not using any pointer variables. I do have used the strlen() function to determine the exact place of a character in a string. Any help is greatly appreciated.
#include<iostream>
#include<conio.h>
#include<string.h>
#include<stdio.h>
using namespace std;
void Letter_correspondence();
int main()
{
Letter_correspondence();
return 0;
}
void Letter_correspondence()
{
cout<<"Enter the letters of the word you want to convert to numbers: ";
char a[]="Hello";
char b[]="world";
int len=strlen(a);
int lenb=strlen(b);
int n;
int l=a[n];
for (n=0;n<=7;n++)
{
while (n<=len)
{
if (l=="a"||l=="b"||l=="c")
{
if (n==2)
{
cout<<"-";
}
cout<<"2";
}
else if (l=="d"||l=="e"||l=="f")
{
if (n==2)
{
cout<<"-";
}
cout<<"3";
}
else if (l=="g"||l=="h"||l=="i")
{
if (n==2)
{
cout<<"-";
}
cout<<"4";
}
else if (l=="j"||l=="k"||l=="l")
{
if (n==2)
{
cout<<"-";
}
cout<<"5";
}
else if (l=="m"||l=="n"||l=="o")
{
if (n==2)
{
cout<<"-";
}
cout<<"6";
}
else if (l=="p"||l=="q"||l=="r"||l=="s")
{
if (n==2)
{
cout<<"-";
}
cout<<"7";
}
else if (l=="t"||l=="u"||l=="v")
{
if (n==2)
{
cout<<"-";
}
cout<<"8";
}
else if (l=="w"||l=="x"||l=="y"||l=="z")
{
if (n==2)
{
cout<<"-";
}
cout<<"9";
}
}
}
}
If I understood this right, you're trying to map characters to different ones and print them. You said you cannot use cstring or character arrays, but you do that here:
char a[]="Hello";
char b[]="world";
Instead, I would just use std::string:
std::string a = "Hello";
You can then iterate through it using a range-based for loop. The best way to print your string would probably be using a switchstatement:
for (char &c : a)
{
switch (tolower(c)) {
case 'a':
case 'b':
case 'c':
std::cout << 2;
break;
case 'd':
case 'e':
case 'f':
std::cout << 3;
break;
case 'g':
case 'h':
case 'i':
std::cout << 4;
break;
case 'j':
case 'k':
case 'l':
std::cout << 5;
break;
case 'm':
case 'n':
case 'o':
std::cout << 6;
break;
case 'p':
case 'q':
case 'r':
case 's':
std::cout << 7;
break;
case 't':
case 'u':
case 'v':
std::cout << 8;
break;
case 'w':
case 'x':
case 'y':
case 'z':
std::cout << 9;
break;
default:
std::cout << c;
}
}
If you're using an old version of C++ that doesn't support range based for loops, change this
for (char &c : a)
{
switch (tolower(c)) {
To this
for (size_t i = 0; i < a.size(); i++)
{
switch (tolower(a[i])) {
And std::cout << c; to std::cout << a[i];.

My code is not executing anything after the for loop

I am having a problem with a test project in a visual studio.
From my understanding, the problem comes from the function 'yeet'.
The function does not finish the loop, since it does not print out "why!!" .
Could someone help me in identifying what is wrong with my code?
Here is my code
string reet(char reet) {
switch (reet) {
case 'a':
return "Zg";
break;
case'b':
return "dA";
break;
case 'c':
return "dG";
break;
case 'd':
return "aw";
break;
case 'e':
return "bw";
break;
case 'f':
return "dQ";
break;
case 'g':
return "cg";
break;
case 'h':
return "ZA";
break;
case 'i':
return "cQ";
break;
case 'j':
return "YQ";
break;
case 'k':
return "eA";
break;
case 'l':
return "dw";
break;
case 'm':
return "cw";
break;
case 'n':
return "ag";
break;
case 'o':
return "eQ";
break;
case 'p':
return "bA";
break;
case 'q':
return "aA";
break;
case 'r':
return "ZQ";
break;
case 's':
return "cA";
break;
case 't':
return "aw";
break;
case 'u':
return "eg";
break;
case 'v':
return "bg";
break;
case 'w':
return "aq";
break;
case 'x':
return "bQ";
break;
case 'y':
return "Yg";
break;
case 'z':
return "Zw";
break;
}
}
void yeet(string input) {
string yeet = input;
string bigBoi = "";
int yeetL = yeet.length() + 1;
for (int x = 0; x < yeetL;) {
bigBoi = bigBoi + reet(yeet[x]);
x++;
cout << bigBoi << endl;
}
cout << "why!" << endl;
}
int main() {
string input;
cin >> input;
yeet(input);
}
For further Information, I am Using C++ on Microsoft Visual Studio 2013.

Somewhy the program always returns 'false'?

Why does this code always return 'false' and activates the goto even when I type a digit? Can anyone please help me? Thank you!
char userValue = '4';
auto h = true;
tryAgain:
std::cout << "Please type a digit: ";
std::cin >> userValue;
switch (userValue) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
h = true;
default:
h = false;
}
switch (h) {
case true:
std::cout << "This character is a digit.";
case false:
std::cout << "Wrong! Try again!" << std::endl;
goto tryAgain;
}
You simply forgot to break out of the case if it has been processed.
That way it will fall through the cases and handle the false case after the true case has been handled.
switch (h) {
case true:
std::cout << "This character is a digit.";
break;
case false:
std::cout << "Wrong! Try again!" << std::endl;
goto tryAgain;
//not necessarily needed because goto leaves the scope anyway.
//break;
}
The same issue here, break if you wan't to stop the fallthrough:
switch (userValue) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
h = true;
break;
default:
h = false;
break;
}