Sign in to follow this  
BrandonSnider

(C++ Beginner) I hate to post here, but... why won't my "if" statement evaluate a string?

Recommended Posts

BrandonSnider    102
I've worked with other languages in the past including basic and a lot of scripting languages, and I have worked a decent bit on C++ too. I haven't worked on C++ in quite a while now, and last night I was trying to refresh myself on the basics... so--and this is a little embarrassing--I wrote this small piece of code for a console program to send my girlfriend:

[CODE]
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
//Vars
string username = "";

//Execute
cout << "Hello \n";
cin.get();
cout << "What is your name? ";
getline (cin, username);
cout << "Your name is: " << username;
cin.get();
if (username == "Tiffany" || "tiffany" || "Tiffany McClure" || "tiffany McClure" || "Tiffany Mcclure" || "tiffany mcclue")
{
cout << "Your name is Tiffany... \n The Creator has a message for you: \n I love you Cupcake";
cin.get();
}
else
{
cout << "Your name is not Tiffany.";
cin.get();
}
return 0;
}
[/CODE]

The problem is... it doesn't appear that the "if (username == "Tiffany" || "tiffany" || "Tiffany McClure" || "tiffany McClure" || "Tiffany Mcclure" || "tiffany mcclue")" statement evaluates correctly, as the program always displays the cout message in the "if" block, even if the if statement should be false.


I know these are beginner C++ concepts that have nothing to do with game development, but... this is like the only forum acct. I have for anything like this, and I hate to create another just to ask this somewhat stupid question.

I appreciate any help with this, I'm trying to pick up C++ again so that maybe I can do something useful with it.


EDIT: Oops. I haven't been on this site in a while. Forgot there was a "For Beginners" Section. This probably belongs there. Sorry about that. Edited by bls61793

Share this post


Link to post
Share on other sites
3DModelerMan    1173
The || && and ! operators operate on entire logical expressions. username == "Tiffany" is an entire expression, but "tiffany" is just a string literal.I made that mistake too when I first started out.

Share this post


Link to post
Share on other sites
mind in a box    887
I don't know how std::string handles this, but you should be able to do [font=courier new,courier,monospace]if(stricmp(username.c_str(), "Tiffany McClure")==0) [/font]to do a case insensitive comparison.
(stricmp measures some kind of "difference" between the strings, so you have to check for == 0)

Share this post


Link to post
Share on other sites
Alex Melbourne    294
[quote name='Servant of the Lord' timestamp='1342385514' post='4959358'][...] convert [...] strings to all lowercase...[/quote]

I was going to suggest this. This is a great technique. Saves space and it means you catch strange possibilities like "TiffAnY MCClurE"; which would otherwise take up huge amounts of space if you tried to catch every single version. Edited by BinaryPhysics

Share this post


Link to post
Share on other sites
Aardvajk    13205
[quote name='Krohm' timestamp='1342422636' post='4959485']
[quote name='BinaryPhysics' timestamp='1342395942' post='4959383']
Saves space
[/quote]How?
[/quote]


Stops the exe having to have all the different supported permutations of the string stored in its data section.

"Saves space" is pushing it though, overhead of calling method is likely to outweight space saving but of course this is irrelevant and space saving is hardly the reason to use this approach.

Share this post


Link to post
Share on other sites
Krohm    5030
I seriously hope you're jocking.
Using this to [i]not [/i]store the permutations is [i]not [/i]saving [i]space[/i].
Rather, doing the permutation thing is [i]brain damaged[/i]. And don't even get me started on checking the match. I'm sure I've seen it on the daily WTF.
Thus, not storing them is not about saving space but rather doing things right.

Share this post


Link to post
Share on other sites
mark ds    1786
[quote name='Krohm' timestamp='1342444871' post='4959585']
Using this to [i]not [/i]store the permutations is [i]not [/i]saving [i]space[/i].
[/quote]

Actually, it saves a quarter of a meg ;-)

Which is eight times as much memory as my first computer had! Edited by mark ds

Share this post


Link to post
Share on other sites
[quote name='Krohm' timestamp='1342444871' post='4959585']
I seriously hope you're jocking.
Using this to [i]not [/i]store the permutations is [i]not [/i]saving [i]space[/i].
Rather, doing the permutation thing is [i]brain damaged[/i]. And don't even get me started on checking the match. I'm sure I've seen it on the daily WTF.
Thus, not storing them is not about saving space but rather doing things right.
[/quote]
I'm confused about what you are disagreeing with.

Are you saying that this...
[code]
if(name == "person mcperson" || name == "Person Mcperson" || name == "Person McPerson"
|| name == "PERSON MCPERSON" || name == "person MCPERSON" || name == "PERSON mcperson" || ...etc... )
{
//...
}[/code]

...is better than this:
[code]std::string name = "Person McPerson";
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
if(name == "person mcperson")
{
//...
}[/code]

Or are you just saying to cache the lowercase name when possible, so you don't have to convert it every function call?

As for 'saving space', I fully agree that any 'space' you save is absurdly small and unimportant if developing for a modern PC. For me, the benefit of the second one is about writing cleaner and easier-to-maintain code, and also ensuring you catch [i]all[/i] the valid possibilities and not just some of them.

[quote name='mark ds' timestamp='1342452766' post='4959616']
Actually, it saves a quarter of a meg ;-)
Which is eight times as much memory as my first computer had!
[/quote]
How does it save a quarter of a megabyte? Worst case scenario, with the example I gave ("Person McPerson"), it'd save 32 kilabytes I think - and only if someone bothered to type out every possible lowercase vs uppercase version of "Person McPerson", starting with "person mcperson", "Person mcperson", "PErson mcperson", "PERson mcperson", and so on, which is unlikely.

Share this post


Link to post
Share on other sites
kunos    2254
[quote name='bls61793' timestamp='1342363560' post='4959267']
[CODE]
if (username == "Tiffany" || "tiffany" || "Tiffany McClure" || "tiffany McClure" || "Tiffany Mcclure" || "tiffany mcclue")

[/CODE]

[/quote]

Am I the only one thinking that looks pretty elegant? Is there any language that implements this way of checking the same variable for different boolean cases?

It looks to me like "Tiffany" is the real string to look for here, so I would convert to lowercase and check for "tiffany".. what if she wrotes "Tiffany Cupcake" ? :P You'll miss that.

Share this post


Link to post
Share on other sites
King Mir    2490
[quote name='kunos' timestamp='1342466480' post='4959691']
[quote name='bls61793' timestamp='1342363560' post='4959267']
[CODE]
if (username == "Tiffany" || "tiffany" || "Tiffany McClure" || "tiffany McClure" || "Tiffany Mcclure" || "tiffany mcclue")

[/CODE]

[/quote]

Am I the only one thinking that looks pretty elegant? Is there any language that implements this way of checking the same variable for different boolean cases?

It looks to me like "Tiffany" is the real string to look for here, so I would convert to lowercase and check for "tiffany".. what if she wrotes "Tiffany Cupcake" ? [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img] You'll miss that.
[/quote]Some languages allow this:
[code]switch(name){
case "Tiffany":
case "tiffany":
case "Tiffany McClure":
...
break;
default:
...
}[/code]Close enough?

Share this post


Link to post
Share on other sites
[quote name='King Mir' timestamp='1342470870' post='4959728']
Some languages allow this:
[code]switch(name){
case "Tiffany":
case "tiffany":
case "Tiffany McClure":
...
break;
default:
...
}[/code]Close enough?
[/quote]
C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. [img]http://public.gamedev.net//public/style_emoticons/default/happy.png[/img] Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
Cornstalks    7030
Am I the only one who noticed the typo ([font=courier new,courier,monospace]... "tiffany McClure" || "Tiffany Mcclure" || "tiffany [u][b]mcclue[/b][/u]"[/font])? One big reason checking each permutation sucks is because it's too easy to introduce human error.

I'd say convert to lower (or upper) case and check the string. I love regular expressions, but I probably wouldn't use them here.

Share this post


Link to post
Share on other sites
King Mir    2490
[quote name='Servant of the Lord' timestamp='1342471896' post='4959736']
[quote name='King Mir' timestamp='1342470870' post='4959728']
Some languages allow this:
[code]switch(name){
case "Tiffany":
case "tiffany":
case "Tiffany McClure":
...
break;
default:
...
}[/code]Close enough?
[/quote]
C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. [img]http://public.gamedev.net//public/style_emoticons/default/happy.png[/img]
[/quote]Which is why I said "some languages" and not "c++ and some languages". Why do you think switches are ugly?

Share this post


Link to post
Share on other sites
[quote name='King Mir' timestamp='1342474441' post='4959760']
[quote name='Servant of the Lord' timestamp='1342471896' post='4959736']
C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. [img]http://public.gamedev.net//public/style_emoticons/default/happy.png[/img]
[/quote]Which is why I said "some languages" and not "c++ and some languages"[/quote]Ah, I thought your "some languages" was a not-so-subtle "hint hint", referring to C++ itself (What with the topic being about C++, and the "Close enough?" comment).

[quote]Why do you think switches are ugly?[/quote]
Not switches, per se, but using switches (which are typically meant to branch logic) to imitate the use of AND logic (which is what && is for).
In some situations it may be the best solution, but in general I prefer to use if() when I mean logical IF, and && when I mean logical AND. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
King Mir    2490
[quote name='Servant of the Lord' timestamp='1342478231' post='4959787']
[quote name='King Mir' timestamp='1342474441' post='4959760']
[quote name='Servant of the Lord' timestamp='1342471896' post='4959736']
C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. [img]http://public.gamedev.net//public/style_emoticons/default/happy.png[/img]
[/quote]Which is why I said "some languages" and not "c++ and some languages"[/quote]Ah, I thought your "some languages" was a not-so-subtle "hint hint", referring to C++ itself (What with the topic being about C++, and the "Close enough?" comment).[/quote]I was responding to kunos's question if any languages allowed the syntax he quoted.

[quote][quote]Why do you think switches are ugly?[/quote]
Not switches, per se, but using switches (which are typically meant to branch logic) to imitate the use of AND logic (which is what && is for).
In some situations it may be the best solution, but in general I prefer to use if() when I mean logical IF, and && when I mean logical AND. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[/quote]Totally don't agree here. Switching on a variable is what switches are for.

Share this post


Link to post
Share on other sites
Switching, yes, but you aren't switching (the code execution path isn't really changing much), you're faking multiple logical ANDs, and using more lines to do so, with - in my opinion - slightly less code clarity.

[quote name='King Mir' timestamp='1342485609' post='4959819']
[quote name='Servant of the Lord' timestamp='1342478231' post='4959787']
Ah, I thought your "some languages" was a not-so-subtle "hint hint", referring to C++ itself (What with the topic being about C++, and the "Close enough?" comment).[/quote]I was responding to kunos's question if any languages allowed the syntax he quoted.[/quote]

Ah, my mistake then. Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
Cornstalks    7030
[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
*snip*
[...] AND logic (which is what && is for).
[...] and && when I mean logical logical AND. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[/quote]
[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
[...] you're faking multiple logical ANDs
[/quote]
I presume you mean logical OR ([font=courier new,courier,monospace]operator ||[/font]), correct?

[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
and using more lines to do so
[/quote]
Depends on how you format your code. I'd probably break the [font=courier new,courier,monospace]if[/font] condition into multiple lines if it was that long anyway. But that's me.

I don't think I'd use a switch for only two code paths (like in this example), but I might use it if there are more (or if I was switching on strings and the switch was done by hashes and [font=courier new,courier,monospace]operator ==[/font] was not, and I cared about that).

Share this post


Link to post
Share on other sites
[quote name='Cornstalks' timestamp='1342487648' post='4959826']
[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
*snip*
[...] AND logic (which is what && is for).
[...] and && when I mean logical logical AND. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[/quote]
[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
[...] you're faking multiple logical ANDs
[/quote]
I presume you mean logical OR ([font=courier new,courier,monospace]operator ||[/font]), correct?[/quote]

[b]</facepalm>[/b] Yes, logical OR. [img]http://public.gamedev.net//public/style_emoticons/default/wacko.png[/img]

[quote][quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
and using more lines to do so
[/quote]
Depends on how you format your code. I'd probably break the [font=courier new,courier,monospace]if[/font] condition into multiple lines if it was that long anyway. But that's me.[/quote]

Certainly, I typically write longer comparisons like this:
[code]if(blah || blah || blah
|| blah || blah)
{
//...
}[/code]

...and, depending on the logic of the function, may even group the options into boolean variables.
[code]bool logicalEvaluationA = (blah || blah || blah);
bool logicalEvaluationB (blah || blah);
if(logicalEvaluationA || logicalEvaluationB)
{

}[/code]

...but switch statements just have more visible clutter (to me). Furthermore, the name 'switch()' implies switching, and past usage and experience teaches your mind that that is what those kinds of statements do.

When you read code, you have certain expectations from blocks of code before you even read it. while() implies a loop, as does for(). for() usually implies an iteration or a fixed number of loops, whereas while() usually implies a continuous loop until some condition is meant. if() usually implies conditional logic, if-else() multiple branches, and switch() usually implies a large number of branches.
When these "first glance" expectations are then turned on their head following a closer inspection, my mind has to do a double take, and reevaluate the whole block of code.

Doing things like:
[code]do
{

}
while(false); //Hahah, not actually a loop![/code]

Or:
[code]switch(option)
{
case :
case :
case :
case :
case :
{

} break;
default: //Jokes on you, I'm actually a if-else() statement in disguise!
{

} break;
}[/code]

...increase the time it takes (at least for me) to understand code, because my mind has to then backpedal and throw out some previously made common assumptions about the code that is [i]usually[/i] true, but in this case is not.

Often times when reading through code, you don't actually have to read the fine details of the code, you can just look at the general picture and understand what it's doing. This is really useful. If the code does what it is expected to do, and looks like it should do, that's good. If you have to manually mentally walk through a piece of code to find out what it actually does, because it breaks expectations, that's not good (but is acceptable if that's what is required - for example, a heavily optimized algorithm).

Reading code (from top of the page downward), you start to build an idea of what the code does.
[code]for(int i = 0; i < myVector.size(); i++)[/code]

"[i]...looking at the lady in the red dress? Look again, Neo.[/i]"
[CODE]for(int i = 0; i < myVector.size(); i++)
{
//...code...
if((myVector % 2) == 1)
{
i++;
}
//...code...
}[/CODE]

Additional logic that controls the flow of the entire loop is buried in the body of the loop?!

A 'break', 'return', or even 'continue' is fine, because your mind easily parses those keywords and can argument it's understanding of the code very rapidly. It'll take a few moments longer for your mind to recognize the 'i++' alters the flow of the code (and even longer if it's hidden away admist other code), and it may even have to throw out parts of its previous understanding that your mind has already built up, causing even more mentally delay and extra mental, "Let me double check this" processing as it encounters unexpected deviations from the norm.

[quote]I don't think I'd use a switch for only two code paths (like in this example), but I might use it if there are more (or if I was switching on strings and the switch was done by hashes and operator == was not, and I cared about that).
[/quote]
Well sure, I'm not at all saying switch()s are bad. I'm not even saying case fall-through is bad. When asked about it originally, I was trying to explain that using a switch() when you really want a single if() or if-else() is undesirable as a default thing to go to, because it makes your code less understandable at-a-glance, and departs from the norm of what is expected that a switch() statement does.

For multiple branches of logic, switch() statements are excellent. For other situations, switch() statements are less desirable. 'Less desirable' may be a fine tradeoff if something else is needed in its place, like speed or memory optimization, but if you are decreasing readability and not gaining anything at all, that's not a good tradeoff - so as a default (but I'm not saying "never" or "always" - there are exceptions), one should go for the most commonly expected solution, so code does what one expects it to do.

An extreme example of such a valid [i]optimization vs code expectation tradeoff[/i] would be [url="http://en.wikipedia.org/wiki/Duff"]Duff's Device[/url].
Do you understand that code? Being honest with yourself, how many times did you have to read through it carefully (the first time you ever saw it) before you understood it?

Now this, on the other hand:
[code]int sum = 0;
for(iterator = numbers.begin(); iterator != numbers.end(); iterator++)
{
sum += *iterator;
}[/code]

...you barely even had to read. You already knew, in general, what it did before you even read the fine details of it... and even reading the fine details, you understood it without any mental hiccups or backpedalling, and so having understood it, you continued onward to reading this paragraph of my post - if you were reading real code, you would have continued on reading code further down the page, and the above for() loop wouldn't have interrupted your reading in the least, and certainly wouldn't have caused your understanding of the inner workings of the function to come to a crashing halt like a more extreme example of code-convolution might have.

Using a switch() to choose between multiple hashes of a string? Certainly, because you're [u]switch[/u]ing between multiple code branches. When you see a switch() statement, this is your instant expectation from your prior experience with switch statements.
Using a switch() to imitate "if(optionA OR optionB OR optionC)" won't cause too much mental backpedaling, but it will take a bit longer to process because you are failing to take advantage of the instant mental expectation of if()s which are normally used for that purpose... so by default, one should prefer the more common "if( OR OR )" with its built-in mental benefits and syntactical simplicity. Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
King Mir    2490
I agree with you in general, but not concerning switch. There's not much cognitive difference between this:
[code]switch(myString){
case "--option1":
case "-o1":
case "o1":

...
break;
default:
...
}[/code]
And this:
[code]switch(hash(myString)){
case hash("--option1"):
case hash("-o1"):
case hash("o1"):
...
break;
default:
...
}[/code]

Or doing the same thing with a single character. Not having to write myString== a bunch of times reduces code size, and so clarifies what's going on; it's only comparing values to a single variable. To each his own I guess.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this