How do I do this with switch instead of if esle? - c++

I am taking my first programming course and the assignment was to redo a previous program (this one) using a switch statement. I thought that switch was just used to compare single characters.
The program essentially just receives a string and counts numbers, letters, other characters, and total characters.....
#include <iostream>
using namespace std;
int main()
{
char s[50];
int i;
int total = 0;
int letters = 0;
int numbers = 0;
int others = 0;
cout << "Enter a continuous string of characters with no blank spaces" << endl;
cout << "(example: aBc1234!##$%)" << endl << endl;
cout << "Enter your string: ";
cin >> s;
cout << endl;
i = 0;
while (s[i] != 0)
{
if ((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z'))
letters++;
else if ((s[i] >= '0' && s[i] <= '9'))
numbers++;
else
others++;
i++;
total++;
}
cout << letters << " letters" << endl;
cout << numbers << " numbers" << endl;
cout << others << " other characters" << endl;
return 0;
}

With this particular situation if/else is the best way (as said by #zenith) but if you wished do to it with switch statements you would do
switch(s[i])
{
case `0`:
case '1':
case '2':
//repeat for '3'-'8'
case '9':
//do whatever you want when it is a digit here
break;
case 'A':
case 'a':
case 'B':
case 'b':
//repeat for 'C'-'y'
case 'Z':
case 'z':
//do whatever you want when it is a letter
break;
default:
//do whatever you want when it was not a letter or a digit
break;
}
When a case matches in a switch statement, everything up to the corresponding break is executed - that's how you can group cases like this

You shouldn't. switch statements work based on ==, not <= / >= / < / >.
The cases in a switch statement must be constant expressions. You'd have to make a separate case for each character.
There are situations where switch is a better solution. But this is not one of those situations. Here if and else is the way to go.

You need a mapping from all the characters of interest onto the behaviors.
enum char_category { OTHER, LETTER, NUMBER };
unsigned char mapping[256];
memset(mapping, OTHER, sizeof mapping);
for( char ch = '0'; ch <= '9'; ++ch ) mapping[ch] = NUMBER;
for( char ch = 'A'; ch <= 'Z'; ++ch ) mapping[ch] = mapping[tolower(ch)] = LETTER;
Then you can use a jump table:
switch ( mapping[s[i]] )
{
case NUMBER:
break;
case LETTER:
break;
case OTHER:
break;
}
Or you could completely skip the conditionals:
int count[3] = { 0, 0, 0 };
count[mapping[s[i]]]++;
letters = count[LETTER];
numbers = count[NUMBER];
other = count[OTHER];
Note that the work of setting up the mapping is only justified if you have more than a few dozen input characters.

switch(s[i]) {
case '0':
...
case '9': numbers++; break;
default: {
switch(toupper(s[i])) {
case 'A':
case 'B':
...
case 'Z': letters++; break;
default: others++;
}
}
}

Related

ASCII Strength Game will not calculate "Bot" word value

I'm making a game that tests the ASCII strength of a user versus a bot. (There is also a 2 player mode but that's working fine.) The full description is given at the top of my .cpp file. As a basic breakdown, the bot opens a txt file with 500 common four letter words and inserts them into a size 500 array. It then randomly generates a number to pick a random one, and then goes through the process of tovalue() to recieve its ASCII value, where in tovalue() runs through chartoint() four times, one for each character of the word. My issue is that the program calculates the ASCII value perfectly fine of the user generated word, but always returns 0 (0000) for the botword, no matter what the word.
I've tried a few iterations of the generateword() function including using a vector but always get the same resutls. I've done a lot of digging about this and haven't quite found any solutions, although I suspect that the chartoint() function could be better optimized, just not sure how to impliment any better solutions for this specific case. Also, don't think the problem is with chartoint() since it works fine for user input, but I'm pretty sure the problem is with generateword(). Suggestions for making chartoint() would be helpful, but its not my main priority right now since I just need the program to 100% work first. Also, I've confirmed that all of the words in my .txt file are all caps and only four characters per line.
// Write the code for a game called “ASCII Strength” of a four-letter word selected by Player 1
// followed by a four-letter word selected by Player 2. The result would be the sum
//of the ASCII value of each of the letters of the selected words and whoever has higher sum (called ASCII strength) wins.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;;
int chartoint(char a) {
switch (a) {
case 'A':
return 1;
break;
case 'B':
return 2;
break;
case 'C':
return 3;
break;
case 'D':
return 4;
break;
case 'E':
return 5;
break;
case 'F':
return 6;
break;
case 'G':
return 7;
break;
case 'H':
return 8;
break;
case 'I':
return 9;
break;
case 'J':
return 10;
break;
case 'K':
return 11;
break;
case 'L':
return 12;
break;
case 'M':
return 13;
break;
case 'N':
return 14;
break;
case 'O':
return 15;
break;
case 'P':
return 16;
break;
case 'Q':
return 17;
break;
case 'R':
return 18;
break;
case 'S':
return 19;
break;
case 'T':
return 20;
break;
case 'U':
return 21;
break;
case 'V':
return 22;
break;
case 'W':
return 23;
break;
case 'X':
return 24;
break;
case 'Y':
return 25;
break;
case 'Z':
return 26;
break;
}
return 0;
}
int tovalue(string input) {
int first = chartoint(input[0]);
int second = chartoint(input[1]);
int third = chartoint(input[2]);
int fourth = chartoint(input[3]);
cout << first << second << third << fourth; // EXISTS TO TEST CALCULATION
int value = first + second + third + fourth;
return value;
}
string generateword() {
string arr[500];
ifstream file("words.txt");
if (file.is_open())
{
for (int i = 0; i < 500; i++) {
string temp;
getline(file, temp);
arr[i] = temp;
}
file.close();
}
else
{
cout << "Error: Unable to open file.";
exit(0);
}
srand(time(0));
int random_index = rand() % 500;
string random_word = arr[random_index];
return random_word;
}
int main()
{
cout << "Welcome to ASCII strength, a game where the strongest word wins!";
cout << "\nTo play, you must enter a four letter word. The program will calculate the 'ASCII strength' of your word and compare it to your opponent.";
cout << "\nWhoever has the higher sum will win!";
char another;
another = 'y';
while (another == 'y' || another == 'Y') {
cout << "\nWould you like to play against a friend, or against a bot? (F/B)";
char mode;
cin >> mode;
if (mode == 'F' || mode == 'f') {
cout << "\nPlayer 1, please input your four letter word in all caps: ";
string answer1;
cin >> answer1;
int value1;
value1 = tovalue(answer1);
cout << "\nPlayer 2, please input your four letter word in all caps: ";
string answer2;
cin >> answer2;
int value2;
value2 = tovalue(answer2);
if (value1 > value2) {
cout << "\nPlayer 1 wins!";
}
else if (value2 > value1) {
cout << "\nPlayer 2 wins!";
}
else if (value1 == value2) {
cout << "\nTie!";
}
}
else if (mode == 'B' || mode == 'b') {
cout << "\nPlease input your four letter word in all caps: ";
string answer;
cin >> answer;
int valueanswer;
valueanswer = tovalue(answer);
string botword;
botword = generateword();
cout << "\nThe bot generates a random word based on a list of popular four letter words.";
cout << "\nThe bot has generated this word: " << botword;
int valuebot;
valuebot = tovalue("botword");
cout << valueanswer << " " << valuebot; // THIS EXISTS PURELY TO TEST WHETHER THE VALUES ARE PROPERLY CALCULATING
if (valueanswer > valuebot) {
cout << "\nYou win!";
}
else if (valuebot > valueanswer) {
cout << "\nThe bot wins!";
}
else if (valueanswer == valuebot) {
cout << "\nTie!";
}
}
cout << "\nWould you like to start a new game? (y/n)";
cin >> another;
}
}
Your problem is this line:
valuebot = tovalue("botword");
Since all characters in "botword" are lowercase, you get all 0 score. You probably meant to write
valuebot = tovalue(botword);

C++ Newbie: Why don't these nested loops work for this program?

I'm in the middle of taking an online C++ course, and I've been having issues with this homework problem. I tried reaching out to my professor twice, but he hasn't responded. I've sought out many solutions, but since I'm new in the course, many of the solutions involve using techniques I haven't learned yet (like character arrays.) I can get the conversion program to work, but I want the program to allow to process as many user inputs as the user wants.
When I run the program, the program accepts my first input that is 'y' or 'Y' to run the program. It then will ask for a string to convert to the telephone number. This works. However, I need the program to ask the user if they want to run the program again to convert another string to a telephone number or to terminate the program.
I put in another cin at the end of the first while loop to prompt for another input, but it gets skipped over everytime and keeps doing the while loop.
Question: Why is the last prompt to repeat the program get skipped every time I've run it? What am I missing?
Here's the problem and what I've done so far:
Problem:
To make telephone numbers easier to remember, some companies use
letters to show their telephone number. For example, using letters,
the telephone number 438-5626 can be shown as GET LOAN.
In some cases, to make a telephone number meaningful, companies might
use more than seven letters. For example, 225-5466 can be displayed as
CALL HOME, which uses eight letters. Instructions
Write a program that prompts the user to enter a telephone number
expressed in letters and outputs the corresponding telephone number in
digits.
If the user enters more than seven letters, then process only the
first seven letters.
Also output the - (hyphen) after the third digit.
Allow the user to use both uppercase and lowercase letters as well as
spaces between words.
Moreover, your program should process as many telephone numbers as the
user wants.
My code so far:
#include <iostream>
using namespace std;
int main()
{
char letter, runLetter;
int counter = 0;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
while (runLetter == 'y' || runLetter == 'Y')
{
cout << "Enter in a telephone number as letters: " << endl;
while (cin.get(letter) && counter < 7 )
{
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter-32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
}
cout << "Goodbye. " << endl;
return 0;
}
Thanks in advance for any help. I know this might be an easy solution, but I've been tinkering with this program for a couple of days now.
Tried moving the last user prompt in and out of each if/else structure and different while loops. Not sure what I can do to make the program take a new input after the first iteration.
A very good hint to your problem is the comment from #AlanBirtles. Also I know you are a beginner and you may not know about std::string but you should use it because you are learning C++ not C. in a nutshell, it is a C++ way of dealing with char arrays, also better than just that.
Here is your code with minimum changes to do what you are looking for. The main changes is the use of std::string, the use of std::getline and the definition of the counter inside the while loop.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char letter;
std::string runLetter;
std::string number;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline( std::cin, runLetter);
while (runLetter == "y" || runLetter == "Y")
{
int counter = 0;
cout << "Enter in a telephone number as letters: " << endl;
std::getline(std::cin, number);
for (int i = 0; i < number.size(); i++)
{
letter = number[i];
if (counter < 7)
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter - 32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline(std::cin, runLetter);
}
cout << "Goodbye. " << endl;
return 0;
}
I found the following errors in your code:
You do not reset the variable counter to 0 in the second loop iteration, so that counter has the value 7 in the entire second loop iteration, which causes the inner while loop not to be entered. This bug should be clearly visible when running your program line by line in a debugger while monitoring the values of all variables.
You always read exactly 7 characters from the user per loop iteration, which is wrong. You should always read exactly one line per loop iteration. In other words, you should read until you find the newline character. You can ignore every character after the 7th letter, but you must still consume them from the input stream, otherwise they will be read in the next loop iteration(s), which you do not want. However, this does not mean that you can simply ignore everything after the 7th character, because the number of characters is not necessarily identical to the number of letters. For example, if a 7 character string has one space character, then it only has 6 letters. As stated in the task description, the user should be allowed to enter spaces in the string.

Pig Latin converter using toupper

I'm having trouble converting using toupper on the first character in my string.
I used tolower(first[0]) to turn the first letter into lower case.
Why doesn't toupper(first[0]) make the first character upper case?
Also, is there a way to move the first character in a string to the last spot?
Thanks a lot in advance.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
char ans;
do{
string first, last;
char first_letter, first_letter2;
cout << "This program will convert your name "
<< "into pig latin.\n";
cout << "Enter your first name: \n";
cin >> first;
cout << "Enter your last name: \n";
cin >> last;
cout << "Your full name in pig latin is ";
for(int x = 0; x < first.length(); x++){
first[x] = tolower(first[x]);
}
for(int x = 0; x < last.length(); x++){
last[x] = tolower(last[x]);
}
first_letter = first[0];
bool identify;
switch (first_letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
identify = true;
break;
default:
identify = false;
}
if(identify == true){
toupper(first[0]);
cout << first << "way" << " ";
}
first_letter2 = last[0];
bool identify2;
switch (first_letter2)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
identify2 = true;
break;
default:
identify2 = false;
}
if(identify2 == true){
toupper(first[0]);
cout << last << "way" << endl;
}
cout << "You you like to try again? (Y/N)\n";
cin >> ans;
} while(ans == 'y' || ans == 'Y');
return 0;
}
Just a simple blunder, compare
first[x] = tolower(first[x]);
with
toupper(first[0]);
usual case of the 'can't see the obvious thing missing' syndrome... I hate those mistakes.
As for moving the first character to the end I'd usually just use substr() for a simple case:
str = str.substr(1) + str[0];

Error C2679: binary '+' : no operator found which takes a right-hand operand of type

First up, yes, this is homework that I'm struggling with, so help would be appreciated. We're making a calculator in C++ that is supposed to function differently on the + and - operators.
With '+' it is supposed to to add the two numbers together (i.e., 45 + 54 = 4554).
With '-' it is supposed to remove the first digit of the first element from the second element (i.e., 1217 - 1 = 27) We're supposed to do this by overloading the + and - operators, which I seem to be struggling with. Thanks in advance for the help!
class WhackyRPN
{
public:
int value;
int operator+ (WhackyRPN a[]);
int operator- (WhackyRPN s[]);
int getValue();
void setValue(int);
};
void WhackyRPN::setValue(int val){
value = val;
}
int WhackyRPN::getValue(){
return value;
}
int WhackyRPN::operator+ (WhackyRPN a[]){
string combinedNum = to_string(a[1].getValue()) + to_string(a[0].getValue());
int finalNum = stoi(combinedNum);
return finalNum;
}
int WhackyRPN::operator- (WhackyRPN s[]){
int minusNum;
string firstNum = to_string(s[0].getValue());
string secondNum = to_string(s[1].getValue());
string minusString = to_string(minusNum);
for (int i = 0; i < firstNum.length(); i++){
if (firstNum.at(0) != secondNum.at(i)){
minusString.at(i) += secondNum.at(i);
}
}
minusNum = stoi(minusString);
return minusNum;
}
int main()
{
WhackyRPN stackPos[4];
string indent = " ";
string userInput;
stackPos[0].setValue(0);
stackPos[1].setValue(0);
stackPos[2].setValue(0);
stackPos[3].setValue(0);
while (1){
system("cls");
cout << "---STACK---" << endl;
cout << indent << stackPos[3].getValue() << endl;
cout << indent << stackPos[2].getValue() << endl;
cout << indent << stackPos[1].getValue() << endl;
cout << indent << stackPos[0].getValue() << endl;
cout << "CMD: ";
cin >> userInput;
if (userInput == "exit" || userInput == "Exit" || userInput == "EXIT"){
exit(0);
}
switch (userInput[0]){
case 'q':
case 'Q':
exit(0);
case 'p':
case 'P':
stackPos[0] = stackPos[1];
stackPos[1] = stackPos[2];
stackPos[2] = stackPos[3];
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
stackPos[3].setValue(stackPos[2].getValue());
stackPos[2].setValue(stackPos[1].getValue());
stackPos[1].setValue(stackPos[0].getValue());
stackPos[0].setValue(stoi(userInput));
break;
case '+': //combine pos[1] and pos[0];
int finalNum = stackPos[1] + stackPos[0];
stackPos[3].setValue(stackPos[2].getValue());
stackPos[2].setValue(stackPos[1].getValue());
stackPos[1].setValue(stackPos[0].getValue());
stackPos[0].setValue(finalNum);
break;
case '-': //remove pos[0].firstNum from pos[1]
int minusNum = stackPos[0] - stackPos[1];
stackPos[3].setValue(stackPos[2].getValue());
stackPos[2].setValue(stackPos[1].getValue());
stackPos[1].setValue(stackPos[0].getValue());
stackPos[0].setValue(minusNum);
break;
case '/': //divide pos[1] by pos[0]
if (stackPos[0].getValue() == 0){
cout << "Cannot divide by 0" << endl;
system("pause");
break;
}
int endQuotient = stackPos[1].getValue() / stackPos[0].getValue();
stackPos[3].setValue(stackPos[2].getValue());
stackPos[2].setValue(stackPos[1].getValue());
stackPos[1].setValue(stackPos[0].getValue());
stackPos[0].setValue(endQuotient);
break;
case '*': //multiply pos[1] by pos[0]
int endProduct = stackPos[1].getValue() * stackPos[0].getValue();
stackPos[3].setValue(stackPos[2].getValue());
stackPos[2].setValue(stackPos[1].getValue());
stackPos[1].setValue(stackPos[0].getValue());
stackPos[0].setValue(endProduct);
break;
default:
break;
}
}
system("pause");
return 0;
}
You get the error that you do because there really is no overload of operator+ which stackPos[1] + stackPos[0] could resolve to. The only overload you have is of type WhackyRPN::operator+(WhackyRPN*);(it is a pointer even though you have written an array - read here and here. But that isn't relevant to this question.) The signature should be WhackyRPN::operator+(WhackyRPN). More idiomatic would be WhackyRPN::operator+(const WhackyRPN&). For more, read this great answer.
replace
int finalNum = stackPos[1] + stackPos[0];
with
int finalNum = stackPos[1].getValue() + stackPos[0].getValue();
In your program, you have the array of objects stackPos[], which has functions setValue() and getValue() which take and return integer respectively. You need to use getValue() here as the array elements themselves are not integer, they are objects.
This is exactly what your error statement is saying as well. But you seem to already know that because you have implemented it in * and / operations.
Hope this helps.

How do you count the number of consonants and vowels in a menu

I am having trouble with my program, there's something wrong in how it counts vowels and consonants
#include<iostream>
using namespace std;
int main(){
int num[10],even = 0,odd = 0;
char choice;
int vowelcount = 0;
int concount = 0;
string word;
cout<<"MENU:"<<endl<<"[N]umber"<<endl<<"[L]etter"<<endl<<"Choice : ";
cin>>choice;
switch(choice){
case 'n': case 'N':
cout << "Enter 10 integers: \n";
for(int i = 0; i < 10; i++) {
cin >> num[i];
if((num[i] % 2) == 0) {
even++;
}
}
odd = 10 - even;
cout << "Even: " << even << endl;
cout << "Odd: " << odd << endl;
system("pause");
cout<<"Do you want to repeat the program ? Y/N ";
break;
case 'l': case 'L':
cout<< "Enter 10 Letters : \n";
cin>> word;
for (int i=0; word [i] != '\0'; i++){
word[i] = tolower (word[i]);
for (int i=0; word [i] != '\0'; i++)
switch(choice){
case 'A' :
case 'E' :
case 'I' :
case 'O' :
case 'U' :
vowelcount++;
break;
default:
concount++;
}
}
cout<<" total vowels = " <<vowelcount << endl;
cout<<" total consonant = " <<concount << endl;
system("pause");
return 0;
}
}
Okay, several problems here. First off, always try to give more information then 'there is something wrong'. I simply copied your example in to visual studio and was pretty quickly able to figure out your problems, but with more information I probably wouldn't have needed to do this. Also, there's no need for the entire question to be uppercase. :)
So... your switch statement is being done on a variable called choice. This variable is the one that you're using to select your menu option. You need to be running your switch statement on the character you're testing. Also, you've got two loops and you only need the one.
Right now, because you're running the program on choice and you have two loops, each time through each loop choice is always 'l' or 'L' which are consonants, but it's being run a number of times equal to the length of the input string squared. So your response is 0 for the number of vowels, because it never sees any, and the length of your input string squared because you have the nested loops and it's counting 'L' that many times.
Instead of using a switch statement, you could use a string and the std::string::find method:
std::string vowels = "AEIOUaeiou";
std::string consonants = "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
if (vowels.find(letter) != std::string::npos)
{
++vowelcount;
}
else
{
if (consonants.find(letter) != std::string::npos)
{
++consonantcount;
}
}