Stupid C++ question about if-else - c++

I have this code:
#include <iostream>
using namespace std;
int main()
{ char c='6';
if(c == '+' || '-' || '*' || '^' || '/' || '%')
{
cout<<"good";
}
else {cout<<"bad";}
return 0;
}
I want to write "good" if the char is '+' or '-' etc, and write "bad" if the char is anything else.
But this code writes "good" always with any char.
Where is the problem? Thanks.

if(c == '+' || '-' || '*' || '^' || '/' || '%')
parses to
if( (c == '+') || ('-'!=0) || ('*'!=0 || ('^'!=0) || ('/'!=0) || ('%'!=0))
It will always evaluate to true because '-' is indeed not equal to zero. Of course it's a sort of flaw with the type-safety that a char "degrades" to a boolean and evaluates to true. (The proper type-safe solution would be simply not to compile your code unless you explicitly cast).
What you wanted to know was whether c is one of those values. There are many ways to do that. Apart from an indented if you could use a library feature:
C function strchr:
if( strchr( "+-*^/%", c ) != NULL )
switch statement
switch (c )
{
case '+': case '-': case '*': case '^': case '/': case '%':
// true logic
break;
default:
// false logic
};
regex
(overkill here but purists would like it).
std::bitset
This takes a lot of "setup" but if you have a fixed set of chars and lots of variable chars to see if it exists in the set, this is the quickest way to do it.
// one-time setup
std::bitset<256> myCharSet;
myCharSet.set('+');
myCharSet.set('-');
myCharSet.set('*');
myCharSet.set('^');
myCharSet.set('/');
myCharSet.set('%');
// subsequently
if( myCharSet.test( static_cast<unsigned char>(c) ) )
{
// true logic
}
else
{
// false logic
}
static array
Similar solution to bitset but you don't mind wasting a few bytes.
static bool charset[256] = { false };
static bool init = false;
if( !init )
{
charset['+'] = true; // etc
init = true;
}
if( charset[ static_cast<unsigned char>(c) ] )
{
// true logic
}
else
{
// false logic
}
And you could make a class that does this that initialises from a string of the characters you want to check for (plus some logic as to whether a 0 byte is true or false, if the string you pass is null-terminated).
As with bitset this is constant-time lookup.
There are other options (eg with C++ std::string class using find and std::find) but these will do for now.

Change your if to:
if(c == '+' || c == '-' || c == '*' || c == '^' || c == '/' || c == '%')
or better yet:
switch (c)
{
case '+': case '-': case '*' : case '^' : case '/' : case '%':
cout << "good\n"; break;
default: cout << "bad\n"; break;
}

it should be
if(c == '+' || c == '-' || c == '*' || c == '^' || c == '/' || c == '%')
...
otherwise the expression is always evaluating to true. Any of those characters have a value different from 0, so true for c++.

Simple answer:'-' is the ASCII (the way the computer encodes character) value of that character - which is not 0 therefore it's true (computer's logic).
Same for all the other characters. So we got:
c == '+' || true || true || true || true || true which is always true.
What you should've done:
c == '+' || c == '-' || c == '*' || c == '^' || c == '/' || c == '%'
The mistake was probably you thinking "It needs to be equal to this or that or that or that" and so on. This happened to everyone, just remember that computers don't speak English.

Related

I'm trying to create a bool function that evaluates a char and returns true if char is '(' ')' '*' '-' '+' [duplicate]

This question already has answers here:
C++ "OR" operator
(9 answers)
Closed 3 years ago.
I'm getting a warning code C682 and im newer to programming so I'm not sure exactly what is wrong.
bool isOperator(char ch)
{
if (ch == '(' or ')' or '*' or '-' or '+')
{
return true;
}
else
return false;
}
I want it to return true if the char is one of those and false if it's something else.
or is a logical operator in C++ so you need to put conditional operators:
return ch == '(' or ch == ')' or ch == '*' or ch == '-' or ch == '+');
otherwise you evaluate 'c' and others as an expression which is always true.
Some may see this more readabale (it is less repeatative):
bool isOperator(char ch)
{
switch( ch ) {
case '(' :
case ')' :
case '*' :
case '-' :
case '+' :
return true;
}
return false;
}
or more C++ way (though it is more expensive but in your case of 5 variants unlikely to matter):
bool isOperator(char ch)
{
const std::string_view ops( "()*-+" );
return ops.find( ch ) != std::string_view::npos;
}
Alternatively, you could implement it as a search into an array. This way you can add and remove operators easily.
#include <algorithm>
#include <iterator>
bool isOperator(char op) {
const char operators[] = {'(', ')', '+', '-', '*'};
return std::find(std::begin(operators), std::end(operators), op) != std::end(operators);
}
The right way to write it would be
if (ch == '(' or ch == ')' or ch == '*' or ch == '+')
In addition to the other answers here, you could use std::any_of:
bool isOperator(char ch)
{
static const std::array arr { '(', ')', '*', '-', '+' };
return std::any_of(arr.begin(), arr.end(), [ch](char const& c) {
return ch == c;
});
}
Lets go over a few things:
Replace or with the actual operator || in c++ which is equivalent to or. (Note that or is a ISO646 standard and can be used, but depends on preference)
Next we need to ensure ch is added for every character you are checking
After that we should have in a more simple form:
return (ch == '(') || (ch== ')') || (ch == '*') || (ch == '-') || (ch == '+');
Note: We can also do it the way you have by if/else
bool is_operator_match = false;
if (ch == '(') || (ch== ')') || (ch == '*') || (ch == '-') || (ch == '+')
{
is_operator_match = true;
}
return is_operator_match;

Pig Latin Program

I'm not getting errors, but the output is incorrect. I'm not sure what I'm doing wrong. I can only use functions from string library.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main() {
string message, pig_message;
getline(cin, message);
unsigned int x = message.find_first_of("aeiou");
if (message[x] == 'a' || 'e' || 'i' || 'o' || 'u' ) {
pig_message = message + "yay";
cout << pig_message;
}
else if (!(message[x] == 'a' || 'e' || 'i' || 'o' || 'u' )) {
pig_message = message.substr(1) + message[0] + "ay";
cout << pig_message;
}
system("pause");
return 0;
}
The first if statement is always true. You should change it to
if (message[x] == 'a' || message[x] == 'e' || message[x] == 'i' || message[x] == 'o' || message[x] == 'u' ) {
Also, you could change the else if (...) { line to just
else {
if you want it to be executed every time the first if statement is not true.
Your comparison statement is incorrect.
Make sure your function is actually iterating through the letters, and that you're concatenating the strings correctly.
So:
unsigned int x = message.find_first_of("aeiou"); // Returns the first match
if(message[x] == 'a' || message[x] == 'e'...) // Currently your code reads as only checking for a.
Think of it as IF message[x] = a, IF e, IF i
vs
if message[x] = a, IF message[x] = i
What does your code do after it finds a match?
pig_message = message + 'yay' would add "yay" to the whole message string.
It would then print it out and move on, without doing anything to the other vowels.
I'm new to C++ myself but that's how I've understood your code.
It might be better to go through the whole input string one letter at a time in a for loop with your if else statements to add the strings inside the loop.

Concise way to say equal to set of values in C++

For example I have the following string,
if (str[i] == '(' ||
str[i] == ')' ||
str[i] == '+' ||
str[i] == '-' ||
str[i] == '/' ||
str[i] == '*')
My question is there a concise way to say if this value one of these set of values in c++?
You can search for single character str[i] in a string with your special characters:
std::string("()+-/*").find(str[i]) != std::string::npos
Not glorious because it is C instead of C++, but the C standard library is always accessible from C++ code, and my first idea as an old dinosaur would be:
if (strchr("()+-/*", str[i]) != NULL)
Simple and compact
You may use the following:
const char s[] = "()+-/*";
if (std::any_of(std::begin(s), std::end(s), [&](char c){ return c == str[i]})) {
// ...
}
It really depends on your application actually. For such a small check and depending the context, one acceptable option could be to use a macro
#include <iostream>
#define IS_DELIMITER(c) ((c == '(') || \
(c == ')') || \
(c == '+') || \
(c == '-') || \
(c == '/') || \
(c == '*') )
int main(void)
{
std::string s("TEST(a*b)");
for(int i = 0; i < s.size(); i ++)
std::cout << "s[" << i << "] = " << s[i] << " => "
<< (IS_DELIMITER(s[i]) ? "Y" : "N") << std::endl;
return 0;
}
A more C++ish way of doing it would be to use an inline function
inline bool isDelimiter(const char & c)
{
return ((c == '(') || (c == ')') || (c == '+') ||
(c == '-') || (c == '/') || (c == '*') );
}
This post might be interesting then : Inline functions vs Preprocessor macros
Maybe not "more concise", but I think this style is succinct and expressive at the point of the test.
Of course is_arithmetic_punctuation needn't be a lambda if you're going to use it more than once. It could be a function or a function object.
auto is_arithmetic_punctuation = [](char c)
{
switch(c)
{
case '(':
case ')':
case '+':
case '-':
case '/':
case '*':
return true;
default:
return false;
}
};
if (is_arithmetic_punctuation(str[i]))
{
// ...
}

Find the first printf format sequence in a C++ string

I search the most concise and efficient way to find the first printf format sequence (conversion specification) in a C++ string (I cannot use std::regex as they are not yet implement in most in compilers).
So the problem is to write an optimized function that will return the beginning of the first printf-format sequence pos and its length n from an input string str:
inline void detect(const std::string& str, int& pos, int& n);
For example, for:
%d -> pos = 0 and n = 2
the answer is: %05d -> pos = 15 and n = 4
the answer is: %% %4.2f haha -> pos = 18 and n = 5
How to do that (clever and tricky ways are welcome)?
Scan forward for %, then parse the content from there. There are some quirky ones, but not THAT bad (not sure you want to make it an inline tho').
General principle (I'm just typing as I go along, so probably not the BEST form of code ever written - and I haven't tried to compile it at all).
inline void detect(const std::string& str, int& pos, int& n)
{
std::string::size_type last_pos = 0;
for(;;)
{
last_pos = str.find('%', last_pos)
if (last_pos == std::string::npos)
break; // Not found anythin.
if (last_pos == str.length()-1)
break; // Found stray '%' at the end of the string.
char ch = str[last_pos+1];
if (ch == '%') // double percent -> escaped %. Go on for next.
{
last_pos += 2;
continue;
}
pos = last_pos;
do
{
if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' ||
ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' ||
ch == '#' || ch == '\'')
{
last_pos++;
ch = str[last_pos+1];
}
else
{
// The below string may need appending to depending on version
// of printf.
if (string("AacdeEfFgGiopusxX").find(ch) != std::string::npos)
{
// Do something about invalid string?
}
n = last_pos - pos;
return;
}
} while (last_pos < str.length());
}
}
edit2: This bit is probably better written as:
if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' ||
ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' ||
ch == '#' || ch == '\'') ...
if (string("0123456789.-*+lLzhtj #'").find(ch) != std::string::npos) ...
Now, that's your homework done. please report back with what grade you get.
Edit: It should be noted that some things that a regular printf will "reject" is accepted by the above code, e.g. "%.......5......6f", "%5.8d", "%-5-6d" or "%-----09---5555555555555555llllld". If you want the code to reject these sort of things, it's not a huge amount of extra work, just need a little bit of logic to check "have we seen this character before" in the "check for special characters or digit", and in most cases the special character should only be allowed once. And as the comment says, I may have missed a couple of valid format specifiers. It gets further trickier if you also need to cope with "this 'l' is not allowed with 'c'" or such rules. But if the input isn't "malicious" (e.g. you want to annotate where on which line there are format specifiers in a working C source file), the above should work reasonably well.

Evaluating a single char in an if statement: C++

I am having some troubles with my if loop.
First off I have I assigned char sign.
void evaluate_ps(istream& input)
{
char sign;
input >> sign;
cout << sign << endl;
check(sign);
}
That prints / so my sign has the value '/'
Then I go to my void check(char operation) function
void check(char operation)
{
if(operation != '-' || operation != '+' ||
operation != '*' || operation != '/')
{
return false;
}
else return true;
}
and it's returning false... WHY!!!! I can't seem to figure this out.
Thanks everyone.
This happens because you are using the || (OR) operator. When operation is / the check operation != '-' returns true. Since || is short circuited, the entire expression returns true.
Change it to && (AND):
if (operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Another way to write this is:
if (!(operation == '-' || operation == '+' ||
operation == '*' || operation == '/'))
You probably meant all your || to be &&:
if(operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Otherwise, it will always enter the if-statement since a character will always not equal one of 4 different things.
The if statement is responding to the / not equaling one of the other values
Think about "or" even in a general sense
if blue is not green or is not red or is not blue say nope
you would need to do something like the following:
if (operation != '+' && operation != '-' && operation != '/' && operation != '*') {
return false;
}
return true;
this way its like this
if blue is not green and is not red and is not blue say nope