Is there special syntax to follow when comparing chars in C++? - c++

I've been learning C++, and I tried to create a basic calculator app. The goal is to obtain two numbers from 0-9 from the user, and a mathematical operation (+, -, *, /); if some other character is typed, I want to loop the program to keep prompting for the proper input.
But whenever I run the program, it doesn't recognize the numbers 0-9, and keeps repeating the loop. These are the main 3 functions I am using. From main, I'm simply calling them, so I doubt the problem is there. Help please?
Oh and I know I'm never supposed to use go-to, but I wanted practice.
And if you could point out more efficient ways of writing this code, that's awesome.
Thanks a million.
int GetUserInput(){
using namespace std;
cout << "Please enter a number between 0-9." << endl;
char inputChar;
cin >> inputChar;
while (inputChar != ('1' || '2' || '3' || '4' || '5' || '6' || '7' || '8' || '9' || '0')) {
cout << "Please enter a number between 0-9." << endl;
cin >> inputChar;
}
return static_cast <int> (inputChar);
}
char GetMathematicalOperation(){
using namespace std;
cout << "Please enter a mathematical operator (+, -, *, /)" << endl;
// Storing user input character into char inputChar
char inputChar;
inputloop:
cin >> inputChar;
switch(inputChar) {
case('+'):
case('-'):
case('*'):
case('/'):
break;
default:
cout << "Please enter a mathematical operator (+, -, *, /)" << endl;
goto inputloop;
}
return inputChar;
}
int CalculateResult(int x, char Operator, int y){
if (Operator = '+')
return x+y;
if (Operator = '-')
return x-y;
if (Operator = '*')
return x*y;
if (Operator = '/')
return x/y;
return 0;
}

The || operator needs to operate on boolean expressions, which characters are not. You'd need to expand it out to while (inputChar != '1' && inputChar != '2' && ....
Alternatively, you could exploit the fact that the character codes of digits are sequential. In other words, you could do while (inputChar < '0' || inputChar > '9').
Also, in your CalculateResult function, you need to change those = to == - otherwise, you overwrite the Operator variable, rather than comparing to it.

In C++
('1' || '2' || '3' || '4' || '5' || '6' || '7' || '8' || '9' || '0') == true
More specifically, a char that has a value that is not specifically 0 (the value, not the character) evaluates to true when compared with the == or != operator.
So your expression
inputChar != ('1' || '2' || '3' || '4' || '5' || '6' || '7' || '8' || '9' || '0')
Is equivalent to
inputChar != true
You would do better to put all those chars into a container and check if the user input exists in the container.
Untested code
char mychars[] = {'1','2','3','4','5','6','7','8','9','0'};
std::set<char> inputChars;
inputChars.insert(mychars, mychars+10);
if(inputChars.find(inputChar) != inputChars.end())
{
...
}

You could also use isdigit to do something like:
while(!isdigit(inputChar)) {
// code here
}

You want to check whether the inputChar is outside the range '0' to '9', so you need something like this:
while (inputChar < '0' || inputChar > '9')

Your condition is wrong...you need to check (inputchar != '0') && (inputchar != '1') && ... && (inputchar != '9')

while (inputChar != ('1' || '2' || '3' || '4' || '5' || '6' || '7' || '8' || '9' || '0'))
You have to compare against each character.
while ((inputChar != '1') || (inputChar != '2') ....
Or simply -
while ((inputChar < 47) || (inputChar > 57))
Next,
if (Operator = '+')
Compiler should have given you warning. Its an assignment. You actually need == operator instead if you intend to do comparison.

Another solution: if (std::string("0123456789").find(inputChar) != std::string::npos). The variable npos - no position - means not found.

Related

Trying to create a basic "encrypter"

It's a simple concept and not very secure, but just a practice session as i am a very early beginner (2 to 3 weeks)
I basically wanted to interject a random amount of random characters, like numbers and expressions, in to the inputted message after each letter. So for example, "HELLO" would become "H45[E[./43L/54L43[]O".
However i just seem to be getting back the exact input, without the jargon being added in between. Any ideas?
Here is my code:
#include <iostream>
#include <ctime>
#include <string>
std::string encryptFunc(std::string address){
int i = 0;
int store = address.length();
std::string Output;
while(i < store){
if(address[i] == ' ' || address[i] == 'a' || address[i] == 'b' || address[i] == 'c' || address[i] == 'd' || address[i] == 'e' || address[i] == 'f' || address[i] == 'g' || address[i] == 'h' || address[i] == 'i' || address[i] == 'j' || address[i] == 'k' || address[i] == 'l' || address[i] == 'm' || address[i] == 'n' || address[i] == 'o' || address[i] == 'p' || address[i] == 'q' || address[i] == 'r' || address[i] == 's' || address[i] == 't' || address[i] == 'u' || address[i] == 'v' || address[i] == 'w' || address[i] == 'x' || address[i] == 'y' || address[i] == 'z' || address[i] == 'A' || address[i] == 'B' || address[i] == 'C' || address[i] == 'D' || address[i] == 'E' || address[i] == 'F' || address[i] == 'G' || address[i] == 'H' || address[i] == 'I' || address[i] == 'J' || address[i] == 'K' || address[i] == 'L' || address[i] == 'M' || address[i] == 'N' || address[i] == 'O' || address[i] == 'P' || address[i] == 'Q' || address[i] == 'R' || address[i] == 'S' || address[i] == 'T' || address[i] == 'U' || address[i] == 'V' || address[i] == 'W' || address[i] == 'X' || address[i] == 'Y' || address[i] == 'Z'){
srand(time(NULL));
int randJargonSelect = rand()%26; //which character of individual jargon is currently selected to be placed
char jargonSelection[] = {'1','2','3','?', '<', '~', '#', '/', '#', '+', '*', '&', '^', '%', '$', '!', '-', '0', '9', '8', '7', '6', '5', '4', '`', '|' };
char randPlacementJargon = jargonSelection[randJargonSelect]; //the variable holder for the character of jargon to place
int randJargonAmount = rand()%500; //the amount of jargon chars to place
Output = address[i], randPlacementJargon * randJargonAmount;
}
std::cout << Output;
i++;
};
std::string nada = " ";
return nada;
}
int main(){
std::string userin;
std::cout << "Please enter the message you wish to encrypt" << std::endl;
std::cout << "Enter here: "; std::getline(std::cin, userin);
std::cout << " " << std::endl;
std::cout << "Here is your Encoded Message: " << encryptFunc(userin) << std::endl;
std::cout << " " << std::endl;
system("pause");
return 0;
}
Thanks again. I know there are probably 100 better ways of doing this, but i just wish to understand it for the sake of learning.
First, let's talk a bit about style. The way your code looks is extremely important to readability, not just for yourself but for others. There are tools that can style code for you, like clang-format. Here's your code with the only change being that I ran your code through clang-format set to Google's style. I chose this style because it seems good for presentation on this site.
Whether you use a tool or not, being aware of and using good and consistent style is important.
#include <ctime>
#include <iostream>
#include <string>
std::string encryptFunc(std::string address) {
int i = 0;
int store = address.length();
std::string Output;
while (i < store) {
if (address[i] == ' ' || address[i] == 'a' || address[i] == 'b' ||
address[i] == 'c' || address[i] == 'd' || address[i] == 'e' ||
address[i] == 'f' || address[i] == 'g' || address[i] == 'h' ||
address[i] == 'i' || address[i] == 'j' || address[i] == 'k' ||
address[i] == 'l' || address[i] == 'm' || address[i] == 'n' ||
address[i] == 'o' || address[i] == 'p' || address[i] == 'q' ||
address[i] == 'r' || address[i] == 's' || address[i] == 't' ||
address[i] == 'u' || address[i] == 'v' || address[i] == 'w' ||
address[i] == 'x' || address[i] == 'y' || address[i] == 'z' ||
address[i] == 'A' || address[i] == 'B' || address[i] == 'C' ||
address[i] == 'D' || address[i] == 'E' || address[i] == 'F' ||
address[i] == 'G' || address[i] == 'H' || address[i] == 'I' ||
address[i] == 'J' || address[i] == 'K' || address[i] == 'L' ||
address[i] == 'M' || address[i] == 'N' || address[i] == 'O' ||
address[i] == 'P' || address[i] == 'Q' || address[i] == 'R' ||
address[i] == 'S' || address[i] == 'T' || address[i] == 'U' ||
address[i] == 'V' || address[i] == 'W' || address[i] == 'X' ||
address[i] == 'Y' || address[i] == 'Z') {
srand(time(NULL));
int randJargonSelect =
rand() % 26; // which character of individual jargon is currently
// selected to be placed
char jargonSelection[] = {'1', '2', '3', '?', '<', '~', '#', '/', '#',
'+', '*', '&', '^', '%', '$', '!', '-', '0',
'9', '8', '7', '6', '5', '4', '`', '|'};
char randPlacementJargon =
jargonSelection[randJargonSelect]; // the variable holder for the
// character of jargon to place
int randJargonAmount =
rand() % 500; // the amount of jargon chars to place
Output = address[i], randPlacementJargon * randJargonAmount;
}
std::cout << Output;
i++;
};
std::string nada = " ";
return nada;
}
int main() {
std::string userin;
std::cout << "Please enter the message you wish to encrypt" << std::endl;
std::cout << "Enter here: ";
std::getline(std::cin, userin);
std::cout << " " << std::endl;
std::cout << "Here is your Encoded Message: " << encryptFunc(userin)
<< std::endl;
std::cout << " " << std::endl;
return 0;
Now, let's look at your code. I'll start with the main function since it's smaller. There are two small things here, and one can be considered somewhat subjective. The line std::cout << " " << std::endl; is wholly unnecessary. If you just want a blank line, print '\n' (newline character). And you wouldn't need an entire statement for that, either, just stick it at the beginning of your next actual cout. std::cout << "\nHere is your Encoded Message: " << .... The second thing is to prefer '\n' over std::endl. std::endl does two things, print the '\n' and flush the stream. You don't have to constantly flush the stream.
This is note in your main, but it transitions us. You attempt to print the result of encryptFunc() but it returns a single space, the one you declare and return at the end of the function. Your function also prints, and this is bad.
Functions should be singular in purpose. You named it encryptFunc(), not encryptAndPrintFunc(). You also don't need to name your function with any form of "func." We all know it's a function. And you're not really encrypting, I'd say it's more like padding, so I'm going to change the name.
Let's also look at the parameter name, address. That makes no sense. You're not passing an address, your passing a message to be encoded. We'll change that name, I'm choosing message.
std::string pad(std::string message) { ... }
So we've got this, and it already is more understandable what your code intends to do.
I'm going to rename Output to output. Names starting with an upper case letter is generally reserved for classes/structs. You want to pad after a space or a letter. You have a massive Boolean expression for your if. We're going to change this loop to a for loop, and simplify things with the library <cctype>. This is a great library for ASCII work. If you don't know what ASCII is, look up an ASCII table. For beginner programming stuff, ASCII is great. The loop change means we don't need i (not the way you use it anyway) or store.
std::string pad(std::string message) {
std::string output;
for (auto c : message) {
if (std::isalpha(c) || std::isspace(c)) {
// Still working
The for loop I'm using is a range-based for loop. The value of i will be each char of message. Next we're going to change out the older C-style random number stuff for C++ versions. This involves <random>.
std::string pad(std::string message) {
std::string output;
const std::string jargon("123456790?<>~#/#+*&^%$!-`|");
static std::mt19937 prng(std::random_device{}());
static std::uniform_int_distribution<std::size_t> jargonSelector(
0, jargon.length() - 1);
static std::uniform_int_distribution<int> numJargon(1, 5);
for (auto c : message) {
if (std::isalpha(c) || std::isspace(c)) {
// Still working
The keyword static is there for situations when you might call this function many times. If that's the case, you don't want to constantly re-initialize your Pseudo-Random-Number-Generator or distributions. static is how we accomplish that. const ensures that jargon is never modified.
Now, we're getting to the actual issue of your code. This line: output = message[i], randPlacementJargon * randJargonAmount; doesn't do what you expect. The comma operator performs the first expression, discards the result, and returns the result of the second expression. So, you made output hold a single character, then did a random multiplication that wasn't saved anywhere. That's why the original string printed again, your function printed it one character at a time.
You could have known that statement was not working as intended if you were compiling with warnings enabled. -Wall -Wextra should be considered mandatory. Let the compiler help you.
Here's the full program:
#include <iostream>
#include <random>
#include <string>
std::string pad(std::string message) {
std::string output;
const std::string jargon("123456790?<>~#/#+*&^%$!-`|");
static std::mt19937 prng(std::random_device{}());
static std::uniform_int_distribution<std::size_t> jargonSelector(
0, jargon.length() - 1);
static std::uniform_int_distribution<int> numJargon(1, 5);
for (auto c : message) {
if (std::isalpha(c) || std::isspace(c)) {
int padSize = numJargon(prng);
output.push_back(c);
for (int i = 0; i < padSize; ++i) {
output.push_back(jargon[jargonSelector(prng)]);
}
}
};
return output;
}
int main() {
std::string userin;
std::cout << "Please enter the message you wish to encrypt" << '\n';
std::cout << "Enter here: ";
std::getline(std::cin, userin);
std::cout << "\nHere is your Encoded Message: " << pad(userin) << '\n';
std::cout << " " << '\n';
return 0;
}
Once a character is determined to be a letter or space (worth noting that std::isspace returns true for any whitespace character): the size of the pad is determined, the original letter is pushed back into output, then a small loop to push back the pad size's worth of 'jargon' characters.
At the end of the function, the object output is returned instead of the single space nothing string you were returning. I also removed the print statement from the function because that's not the function's job.
Here's a sample output:
Please enter the message you wish to encrypt
Enter here: Hello World!
Here is your Encoded Message: H#32e~/l94l%-4o5`> ?#W/o*5!r>!l&+#d15~3
I fixed it by simply moving my variables inside the loop so that they repeat each time, as they were previously outside the loop, and only being carried out once.
If You Are Beginner I Suggest You To Use Caesar Cipher Its The Most Easiest Way To Encrypt Text Here Is An Example:-
#include <iostream>
#include <string>
using namespace std;
string CaesarCipher(string text, int key)
{
string result;
for (int i = 0; i < text.length(); i++)
{
if (isupper(text[i]))
result += char(int(text[i] + key - 65) % 26 + 65);
else if (text[i] > 47 && text[i] < 58)
result += char(int(text[i] + key - 48) % 10 + 49);
else
result += char(int(text[i] + key - 97) % 26 + 97);
}
return result;
}
int main()
{
int key;
string text, result;
cout << "Warning: Do Not Use Special Chars Like : $ % # # !" << "\n";
cout << "Enter The Text You Want To Encrypt: ";
cin >> text;
cout << "Enter The Key Number For Chars Shifting: ";
cin >> key;
result = CaesarCipher(text, key);
cout << "Encrypted Text: " << result << "\n";
system("pause");
return 0;
}
Key Number Is The Number Of Times You Want To Shift The Char To Another Char In Ascii.
Example Using Key 4 For Test String: test -> xiwx
I Suggest You To Read Ascii Table To Understand The Code More Easier.
I Made A CrackMe On Github That Have Alot Of Basic Information About Encrypting And Anti Debugging: https://github.com/coderx64-cyber/Anti-CrackMe-V2

Unable to compare characters (c++)

I'm trying to make a simple mad libs program in c++, and i want to check and see if a word that a user entered starts with a vowel, and if it does, change the "a" before the word, to an "an". I've been able to get the first character stored, but it will not compare to the other characters in the If statement. Am i doing this completely wrong?
#include <string>
#include <iostream>
using namespace std;
int main() {
string adj_3;
string anN;
char firstChar;
// GETTING USER'S WORD
cout << "ADJECTIVE: " << endl;
getline(cin, adj_3);
// GETTING FIRST CHARACTER
firstChar = adj_3[0];
// SEEING IF IT'S A VOWEL (not working)
if(firstChar == ('a' || 'e' || 'i' || 'o' || 'u' || 'A' || 'E' || 'I' || 'O' || 'U')) {
anN = "n";
}
else {
cout << "not working" << endl;
}
cout << "I am having a" << anN << " " << adj_3 << " time at camp." << endl;
}
The || operator needs to be applied to two arguments, like so:
if (firstChar == 'a' || firstChar == 'e' || firstChar == 'i' || ...)
firstChar == 'a' evaluates to a boolean. firstChar == 'a' || firstChar == 'e' takes the two booleans that results from those two operations, and returns another boolean, which is then fed into the next || operation as the first argument. In this way you can "chain" the || operations until one of them is true, or until they're all false.
See here for examples and explanation.
hnefatl's answer is one way.
You can also use switch case without break statements to check vowel. Something like:
switch(firstChar)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U': cout<<"Vowel";
}
On top of that switch-case have many advantages over if-else ladder as stated here https://stackoverflow.com/a/1028463/6594779.
Logical operator || combines two boolean expressions, e.g. a==0 || b==1, and returns true if either of the two operands is true. If you pass a single character like 'a' as operand, this will be interpreted as true, since the value of 'a' is 97 and 97 != 0 => true. Hence, your expression ('a' || 'e' || 'i' || 'o' || 'u' || 'A' || 'E' || 'I' || 'O' || 'U') will always be true, and firstchar == (....) is the same as firstchar == true, which will probably give false.
You could write...
if (firstChar == 'a' || firstChar == 'e' || firstChar == 'i' || ...)
or...
if (strchr(firstChar, "aeiouAEIOU") != NULL)) ...
You can use an array too wherein you store all the vowels and then compare it. Something like shown below:
char vowels[10]={'a','e','i','o','u','A','E','I','O','U'};
int flag=0;
for(int i=0;i<10;i++)
{
if(vowels[i]==firstChar)
{
flag=1;
anN="n";
}
}
if(flag==1)
cout << "I am having a" << anN << " " << adj_3 << " time at camp." << endl;
else
cout << "not working" << endl;

Pig Latin - strings

So I am supposed to convert English words to Pig Latin using stringConvertToPigLatin(string word) function. All the answers I could find on the internet were using char[], and I am not allowed to do so.
The program is supposed to begin with adding -way if the first letter is a vowel, and adding -ay if it's a consonant. The problem is that it is always adding "-way", even if my "word" has no vowel at all. What am I doing wrong? This is my function:
string ConvertToPigLatin(string word)
{
char first = word.at(0);
cout << first << endl;
if (first == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U')
{
word.append("-way");
}
else
{
word.append("-ay");
}
return word;
}
As noted in the comments your if statement is wrong. Each comparison needs to be done individually. From the comment.
if (first == 'a' || first == 'A' || first == 'e' || ...)
However, rather than using a long if statement you should consider stuffing all of the vowels into a string and using find. Something like the code below will be easier to read and follow.
#include <iostream>
#include <string>
std::string ConvertToPigLatin(std::string word)
{
static const std::string vowels("aAeEiIoOuU");
char first = word.at(0);
std::cout << first << std::endl;
if (vowels.find(first) != std::string::npos)
{
word.append("-way");
}
else
{
word.append("-ay");
}
return word;
}
int main()
{
std::cout << ConvertToPigLatin("pig") << '\n';
std::cout << ConvertToPigLatin("alone") << '\n';
}
This outputs
p
pig-ay
a
alone-way
I'll explain why your code isn't working:
if (first == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U')
Let's walk through that iff statement using the word "Pig"
First the program checks first == 'a'... first == 'P' so that is false.
Then the program checks to see if false || 'A' is true. Since 'A' is true, false || 'A' is also true.
Short circuit evaluation kicks in, and the code doesn't bother checking the rest of the statement, the if condition is true so -way is appended.
To do what you want, you need to compare first to each letter. I.E.,
if (first == 'a' || first == 'A' || ...
Don't worry too much, this is a pretty standard mistake.

how to only allow 3 values in a "if" and "while" statement to allow the loop to exit

I'm just stuck on some logic statements.
specifically the ones that are in the function char GetInteger() so how would I only allow 3 values to cause the loop to exit.
char GetInteger( /* out */ char& usrinput)
{
do
{
cin >> usrinput;
cin.ignore(200,'\n');
if (usrinput != 0 || usrinput != 1 || usrinput != 2)
{
cout << "Invalid Input." << userinput << " Try Again\n";
}
} while(usrinput != 0 || usrinput != 1 || usrinput != 2);
return userInput;
}
Two issues with this code:
First userinput has a type of char. So when you read from a stream you read a single character (after dropping white space). So when a user types 1<enter> you get the character '1' in the variable userinput. Note the character '1' is not the same as the number 1.
Thus your test should be:
userinput != '1';
Secondly your boolean logic is wrong. When first learning it is sometimes easier to state the problem as a list of values that you would like to be acceptable (not the unacceptable ones).
You want the conditions to be false if the userInput has one of your accepted values (any good value will fail the test and thus not invoke the bad code). The first step to this is to get a true if any of your values are valid.
// If any value is good then true.
userinput == '1' || userinput == '2' || userinput == '3'
To invert this just add a not to the expression.
if (! (userinput == '1' || userinput == '2' || userinput == '3') )
Note: in boolean logic
!(A || B) => (!A && !B)
So you could re-write the above as:
if (userinput != '1' && userinput != '2' && userinput != '3')
I think this was your main mistake you converted the == into != but did not convert the || into &&.
I would also suggest that you could simplify this (as you may get more valid result) byconverting this into a range based test.
if (userinput < '1' || userinput > '3')
{
// Test Failed.
}
Additionally. Since you have the test in two places. You should yank it outinto its own function. Then you can call the function to do the test.
bool isUserInputValid(char userInput)
{
return userInput >= '1' && userInput <= '3';
}
Now we can re-write your original function as:
char GetInteger( /* out */ char& usrinput)
{
do
{
cin >> usrinput;
cin.ignore(200,'\n');
if (!isUserInputValid(userinput))
{
cout << "Invalid Input." << userinput << " Try Again\n";
}
} while(!isUserInputValid(userinput));
return userInput;
}
First of all, you should use int instead of string as you are reading integer.
You can use while(1) instead of putting condition in while. Inside while loop, if your selection is 0 or 1 or 2, you can simply break the loop.

conditional statement in while loop

I must have missed something. I'm doing an exercise to learn c++ and it asks that if a user inputs either c,p,t or g character then carry on, otherwise re-request prompt, so I wrote this:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int main(void){
cout << "Please enter one of the following choices:" << endl;
cout << "c) carnivore\t\t\tp) pianist\n";
cout << "t) tree\t\t\t\tg) game\n";
char ch;
do{
cout << "Please enter a c, p, t, or g: ";
cin >> ch;
cout << "\"" << ch << "\"" << endl;
}while(ch != 'c' || ch != 'p' || ch != 't' || ch != 'g');
cout << "End" << endl;
cin.clear();
cin.ignore();
cin.get();
return 0;
}
This does not work and all I get is the prompt re-requesting it even when pressing either of the correct characters.
However if I change this line:
while(ch != 'c' || ch != 'p' || ch != 't' || ch != 'g');
to
while(ch != 'c' && ch != 'p' && ch != 't' && ch != 'g');
why is that? My understanding is that the "OR" statement should work as one of the tests is correct.
why is that? My understanding is that the "OR" statement should work as one of the tests is correct.
Exactly. There is always one of the tests that passes. A character will either be not 'c', or not 'p'. It can't be both 'c' and 'p'. So the condition is always true, leading to an infinite loop.
The alternative condition with the conjunctions works because it is false as soon as ch is equal to one of the alternatives: one of the inequalities is false, and thus the whole condition is false.
My understanding is that the "OR" statement should work as one of the tests is correct.
Well, you could use ||, but the expression would have to be:
while(!(ch == 'c' || ch == 'p' || ch == 't' || ch == 'g'));
By applying the De Morgan's law, the above simplifies to:
while(ch != 'c' && ch != 'p' && ch != 't' && ch != 'g');