Why wont my "intellect" variable add by 5? - c++

if (checkForRoll == "intellect" && checkForRoll == "Intellect") {//checks for intellect
intellect = intellect + 5;
} else if (checkForRoll == "strength" && checkForRoll == "Strength") {
strength = strength + 5;
}
cout << intellect;
When I execute this, the intellect int does not add by 5. Why?

You are requiring your string to equal both intellect and Intellect which is impossible. Change the "and" (&&) to an "or" (||).

Your variable checkForRoll can't be 'strength' && 'Strength', it can be 'strength' || 'Strength' however.

CheckForRoll cannot be both "intellect" and "Intellect".
Assuming you are using a std::string convert to upppercase, and do one comparision.
std:string checkForRoll = "inTeLleCt";
std::transform(checkForRoll.begin() , checkForRoll.end() , checkForRoll.begin(), ::toupper);
if (checkForRoll == "INTELLECT")
{
....
}

This will only work of checkForRoll is a string
If it is a char* then you can't test for equality with ==. You need to use strcmp() to compare.

To make your life easier, I suggest you use std::toupper or std::tolower to convert the string before you compare. See also std::transform.
This simplifies your life by using only one comparison.
"Try it, you'll like it!"

I think you should replace && with ||
P.S. you could also write intellect += 5

Related

Efficiency & Readabilty of a C++ For Loop that Compares two C-style Strings

So I've created my own function to compare two C Strings:
bool list::compareString(const char array1[], const char array2[])
{
unsigned char count;
for (count = 0; array1[count] != '\0' && array2[count] != '\0' && (array1[count] == array2[count] || array1[count + 32] == array2[count] || array1[count] == array2[count+32]); count++);
if (array1[count] == '\0' && array2[count] == '\0')
return true;
else
return false;
}
The parameter of my for loop is very long because it brings count to the end of at least one of the strings, and compares each char in each array in such a way that it their case won't matter (adding 32 to an uppercase char turns that char into its lowercase counterpart).
Now, I'm guessing that this is the most efficient way to go about comparing two C Strings, but that for loop is hard to read because of its length. What I've been told is to use a for loop instead of a while loop whenever possible because a for loop has the starting, ending, and incrementing conditions in its starting parameter, but for this, that seems like it may not apply.
What I'm asking is, how should I format this loop, and is there a more efficient way to do it?
Instead of indexing into the arrays with count, which you don't know the size of, you can instead operate directly on the pointers:
bool list::compareString(const char* array1, const char* array2)
{
while (*array1 != '\0' || *array2 != '\0')
if (*array1++ != *array2++) return false; // not the same character
return true;
}
For case insensitive comparison, replace the if condition with:
if (tolower(*array1++) != tolower(*array2++)) return false;
This does a safe character conversion to lower case.
The while loop checks if the strings are terminated. It continues while one of the strings is not yet terminated. If only 1 string has terminated, the next line - the if statement, will realize that the characters don't match (since only 1 character is '\0', and returns false.
If the strings differ at any point, the if statement returns false.
The if statement also post-increments the pointers so that it tests the next character in the next iteration of the while loop.
If both strings are equal, and terminate at the same time, at some point, the while condition will become false. In this case, the return true statement will execute.
If you want to write the tolower function yourself, you need to check that the character is a capital letter, and not a different type of character (eg. a number of symbol).
This would be:
inline char tolower(char ch)
{
return (ch >= 'A' && ch <= 'Z' ? (ch + 'a' - 'A') : ch);
}
I guess you are trying to do a case-insensitive comparison here. If you just need the fastest version, use a library function: strcasecmp or stricmp or strcmpi (name depends on your platform).
If you need to understand how to do it (I mean, is your question for learning purpose?), start with a readable version, something like this:
for (index = 0; ; ++index)
{
if (array1[index] == '\0' && array2[index] == '\0')
return true; // end of string reached
if (tolower(array1[index]) != tolower(array2[index]))
return false; // different characters discovered
}
Then measure its performance. If it's good enough, done. If not, investigate why (by looking at the machine code generated by the compiler). The first step in optimization might be replacing the tolower library function by a hand-crafted piece of code (which disregards non-English characters - is it what you want to do?):
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
return c + 'a' - 'A';
}
Note that I am still keeping the code readable. Readable code can be fast, because the compiler is going to optimize it.
array1[count + 32] == array2[count]
can lead to an OutOfRangeException, if the length of the array is smaller than 32.
You can use strcmp for comparing two strings
You have a few problems with your code.
What I'd do here is move some of your logic into the body of the for loop. Cramming everything into the for loop expression massively reduces readability without giving you any performance boosts that I can think of. The code just ends up being messy. Keep the conditions of the loop to testing incrementation and put the actual task in the body.
I'd also point out that you're not adding 32 to the character at all. You're adding it to the index of the array putting you at risk of running out of bounds. You need to test the value at the index, not the index itself.
Using an unsigned char to index an array gives you no benefits and only serves to reduce the maximum length of the strings that you can compare. Use an int.
You could restructure the code so that it looks like this:
bool list::compareString(const char array1[], const char array2[])
{
// Iterate over the strings until we find the string termination character
for (int count = 0; array1[count] != '\0' && array2[count] != '\0'; count++) {
// Note 0x20 is hexadecimal 32. We're comparing two letters for
// equality in a case insensitive way.
if ( (array1[count] | 0x20) != (array2[count] | 0x20) ) {
// Return false if the letters aren't equal
return false;
}
}
// We made it to the end of the loop. Strings are equal.
return true;
}
As for efficiency, it looks to me like you were trying to reduce:
The size of the variables that you're using to store data in
memory
The number of individual lines of code in your solution
Neither of these are worth your time. Efficiency is about how many steps (not lines of code, mind you) it will take to perform a task and how those steps scale as the inputs get bigger. For instance, how much slower would it be to compare the content of two novels for equality than two single word strings?
I hope that helps :)

C++ const char if-statement

So I'm trying to get this program that will say good or bad depending on your answer and I didn't want to have a really long if and else if statement with a bunch of strings so I put a bunch of possible answers in two chars and I want it to answer depending on what you say. The program only replies to the good answers saying good even if you enter in one of the bad answers.
const char* good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
const char* bad[5] = {
"bad", "bad pal", "bad eugene", "not good", "not good pal"
};
string input01 = "";
int main() {
cout << "Hello" << endl;
system("PAUSE");
system("CLS");
cout << "How are you doing today?" << endl;
cin >> input01;
transform(input01.begin(), input01.end(), input01.begin(), ::tolower);
if (input01 == good[0 > 5] || good[0 < 5]){
system("CLS");
cout << "good" << endl;
system("pause");
}
else if (input01 == bad[0 > 5] || bad[0 < 5]){
system("CLS");
cout << "bad" << endl;
system("pause");
}
}
This: if (input01 == good[0 > 5] || good[0 < 5]) probably doesn't do what you expect (because I can't imagine wanting what it really does).
0 > 5 is evaluated as a test of whether 0 is greater than 5. Since it's obviously not, that produces false. Since it's being used in a context where an integer is needed, that's converted to 0, so that part of the expression becomes if (input01 == good[0].
Likewise, 0 < 5 tests whether 0 is less than 5 (which it obviously is) so the result is true, which converts to 1, so that part of the expression is good[1]. Since that in turn is being used as a Boolean expression, it's treated as equivalent to good[1] != 0.
So what you have overall is if (input01 == good[0] || good[1] != 0).
That seems close enough to useless that I'm pretty sure it's not what you wanted. In particular, good[1] is a pointer. A pointer will compare equal to 0 if and only if it's a null pointer. Since it's initialized to point at something, it's not a null pointer, so that part of the expression will always evaluated as true.
of course, your other if statement is about equally useless.
If you want to check whether input01 is equal to any of the items in good, you might (for one example) use std::find:
if (std::find(std::begin(good), std::end(good), input01) == std::end(good))
// input01 was not present in `good`.
To make that work correctly, you'll want to use std::strings though:
std::vector<std::string> good{"good", "great", "amazing", "amazing!", "fantastic"};
It's kind of pointless for only 5 items, but if you lists of good and bad words are likely to get really large, you'd probably be better off sorting them, then using std::binary_search, or else using std::unordered_set instead.
Try:
if ((strcmp(input.c_str(), good[0]) == 0) ||
(strcmp(input.c_str(), good[1]) == 0) ||
...
(strcmp(input.c_str(), good[4]) == 0))
Or better switch the keywords to strings,
const string good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
and then
if ((input == good[0]) ||
(input == good[1]) ||
...
(input == good[4]))
Or even better, pack the keywords into a set
const set<string> good{"good", "great", "amazing", "amazing!", "fantastic"};
and then
if (good.find(input) != good.end())
Why don't you just check if the input01 is in your array. You should be able to use the find() function to do this. Something like
if(std::find(std::begin(good), std::end(good), input01) != std::end(good))){do something}
You may not need the std:: references

if statement with multiple condition not working...

here is my code :
string function1( string input)
{
string output;
int i=0;
if (input.at(i)!='A' || input.at(i)!='a'|| input.at(i)!='E' || input.at(i)!='e' || input.at(i)!='I' || input.at(i)!='i' || input.at(i)!='O'||input.at(i)!='o' || input.at(i)!='U' || input.at(i)!='u')
{
char x=input[i];
input.erase(input.begin()+i);
output=input+x;
}
else
{
output=input+"yay";
}
return output;
}
but its not doing what i want it to do.. can't figure out where its going wrong...
can any1 help?
Basically the issue is that its never going in to the else statement..
if i pass in BJ it should return BJYAY right..
but its giving me JB
Thanks!
Change the || operators of the if statement to &&. The statement you have written is always true. What you want is that the first character is not a vowel, i.e. it does not match 'A' AND it does not match 'E', etc.
Changing the != to == will give you the result requested.

If String's beginning inc spec Values

I'm trying to write a program that checks 15-16 digit inputs and see what bank they belong to. I'm not familiar with the language I'm coding in(c++), and would like some pointers. I know you can't copy and paste without the rest of the code, but it would be to long to post all of it. I just need a little adivce on a couple things.
Right now I have the program checking the length of the input and what the first two values of the string are. I would like to know if there is an easier way then what I have right now.
if(cLen==15 && c[0]== 3 && c[1]==4)
and
if(cLen==15 && c[0]== 3 && c[1]==7)
cause all I need is to find Strings that have the first two nums to be 34 or 37
secondly I need to check if the string has first values of 51 through 55
and lastly I need to check if the string contains 6011 at the beginning.
string validatebankcc(string c, int cLen, bool& ccOK) {
string bankcc;
if(cLen==15 && c[0]== 3 && c[1]==4)
bankcc = "AmericanExpress";
if(cLen==15 && c[0]== 3 && c[1]==7)
bankcc = "AmericanExpress";
if(cLen==16 && "6011 in beginning")
bankcc = "Discover";
if(cLen==16 && c[0]==5 && c[1]==1)
bankcc="MasterCard";
if(cLen==16 && c[0]==5 && c[1]==5)
bankcc="MasterCard";
if(c[0]==4)
bankcc="Visa";
else
bankcc = "Uknown Bank"
return bankcc;
bool got_length_and_prefix(string s, int desired_length, string desired_prefix) {
if (s.length() != desired_length) return false;
if (s.find(desired_prefix) != 0) return false;
return true;
}
string validatebankcc(string c, int /* cLen useless here*/, bool& ccOK) {
ccOK = true;
if (got_length_and_prefix(c, 15, "34")) return "AmericanExpress";
if (got_length_and_prefix(c, 15, "37")) return "AmericanExpress";
if (got_length_and_prefix(c, 16, "6011")) return "Discover";
if (got_length_and_prefix(c, 16, "51")) return "MasterCard";
if (got_length_and_prefix(c, 16, "55")) return "MasterCard";
if (c[0] == '4') return "Visa";
ccOK = false;
return "Unkown Bank";
}
Though overall design is bad. Returning bank name as string is crying for trouble (which also leads to useless ccOK flag, which can be replaced by BANK_UNKNOWN or smth like that. Passing string length along with string which known about it length also smells like trouble.
if (c.find("6011") != string::npos && c.find("6011") == 0) //"6011" in beginning
{
}
Firstly, you don't need to pass around the string length - there is a member function size() for that. Secondly, you should be passing by const &. Finally, you can use find_first_of to simplify this:
Hence your method will look something like this:
string validate_bank_cc(const string& c, bool& ccOk)
{
if((c.size() == 15) && (c.find_first_of("34") == 0))
return "AmericanExpress";
//etc...
}

Converting from a std::string to bool

What is the best way to convert a std::string to bool? I am calling a function that returns either "0" or "1", and I need a clean solution for turning this into a boolean value.
I am surprised that no one mentioned this one:
bool b;
istringstream("1") >> b;
or
bool b;
istringstream("true") >> std::boolalpha >> b;
bool to_bool(std::string const& s) {
return s != "0";
}
It'll probably be overkill for you, but I'd use boost::lexical_cast
boost::lexical_cast<bool>("1") // returns true
boost::lexical_cast<bool>("0") // returns false
Either you care about the possibility of an invalid return value or you don't. Most answers so far are in the middle ground, catching some strings besides "0" and "1", perhaps rationalizing about how they should be converted, perhaps throwing an exception. Invalid input cannot produce valid output, and you shouldn't try to accept it.
If you don't care about invalid returns, use s[0] == '1'. It's super simple and obvious. If you must justify its tolerance to someone, say it converts invalid input to false, and the empty string is likely to be a single \0 in your STL implementation so it's reasonably stable. s == "1" is also good, but s != "0" seems obtuse to me and makes invalid => true.
If you do care about errors (and likely should), use
if ( s.size() != 1
|| s[0] < '0' || s[0] > '1' ) throw input_exception();
b = ( s[0] == '1' );
This catches ALL errors, it's also bluntly obvious and simple to anyone who knows a smidgen of C, and nothing will perform any faster.
There is also std::stoi in c++11:
bool value = std::stoi(someString.c_str());
DavidL's answer is the best, but I find myself wanting to support both forms of boolean input at the same time. So a minor variation on the theme (named after std::stoi):
bool stob(std::string s, bool throw_on_error = true)
{
auto result = false; // failure to assert is false
std::istringstream is(s);
// first try simple integer conversion
is >> result;
if (is.fail())
{
// simple integer failed; try boolean
is.clear();
is >> std::boolalpha >> result;
}
if (is.fail() && throw_on_error)
{
throw std::invalid_argument(s.append(" is not convertable to bool"));
}
return result;
}
This supports "0", "1", "true", and "false" as valid inputs. Unfortunately, I can't figure out a portable way to also support "TRUE" and "FALSE"
I'd use this, which does what you want, and catches the error case.
bool to_bool(const std::string& x) {
assert(x == "0" || x == "1");
return x == "1";
}
Write a free function:
bool ToBool( const std::string & s ) {
return s.at(0) == '1';
}
This is about the simplest thing that might work, but you need to ask yourself:
what should an empty string return? the version above throws an exception
what should a character other than '1' or '0' convert to?
is a string of more than one character a valid input for the function?
I'm sure there are others - this is the joy of API design!
I'd change the ugly function that returns this string in the first place. That's what bool is for.
Here's a way similar to Kyle's except it handles the leading zeroes and stuff:
bool to_bool(std::string const& s) {
return atoi(s.c_str());
}
You could always wrap the returned string in a class that handles the concept of boolean strings:
class BoolString : public string
{
public:
BoolString(string const &s)
: string(s)
{
if (s != "0" && s != "1")
{
throw invalid_argument(s);
}
}
operator bool()
{
return *this == "1";
}
}
Call something like this:
BoolString bs(func_that_returns_string());
if (bs) ...;
else ...;
Which will throw invalid_argument if the rule about "0" and "1" is violated.
If you need "true" and "false" string support consider Boost...
BOOST_TEST(convert<bool>( "true", cnv(std::boolalpha)).value_or(false) == true);
BOOST_TEST(convert<bool>("false", cnv(std::boolalpha)).value_or( true) == false);
BOOST_TEST(convert<bool>("1", cnv(std::noboolalpha)).value_or(false) == true);
BOOST_TEST(convert<bool>("0", cnv(std::noboolalpha)).value_or( true) == false);
https://www.boost.org/doc/libs/1_71_0/libs/convert/doc/html/boost_convert/converters_detail/stream_converter.html
Try this:
bool value;
if(string == "1")
value = true;
else if(string == "0")
value = false;
bool to_bool(std::string const &string) {
return string[0] == '1';
}