Qt String Comparison - c++

Suppose I have:
QString x;
Is the following code fragment:
if(x.compare("abcdefg") == 0){
doSomething();
}
else{
doSomethingElse();
}
... functionally equivalent to:
if(x == "abcdefg"){
doSomething();
}
else{
doSomethingElse();
}
I could prove this for myself by writing a fairly trivial program and executing it, but I was surprised I couldn't find the question / answer here, so I thought I'd ask it for the sake of future me / others.

QString::compare will only return zero if the string passed to it and the string it is called on are equal.
Qstring::operator== returns true if the strings are equal otherwise, false.
Since compare only returns zero when the strings are equal then
(qstrign_variable.compare("text") == 0) == (qstrign_variable == "text")
If qstrign_variable contains "text" in the above example. If qstrign_variable contains something else then both cases evaluate to false.
Also note that std::string has the same behavior

Related

Optimized code for two string compare in if condition

I want to do two string compare and used two different if condition. Is there any better way to do string compare in one if condition
if (strcmp(Buff1(), Config1) == 0)
{
if (strcmp(Buff2, Config2) == 0)
{
// my code goes here
}
}
The equivalent code is:
if ((strcmp(Buff1(), Config1) == 0)) &&
(strcmp(Buff2, Config2) == 0))
{
// my code goes here
}
Note: The compiler should generate the same machine code for both code samples. The difference is cosmetic and primarily aimed at the reader of the code.
You do get a difference when you add else clauses:
if (strcmp(Buff1(), Config1) == 0)
{
if (strcmp(Buff2, Config2) == 0)
{
// my code goes here
}
else
{
// else 1
}
}
else
{
// else 2
}
Compared to:
if ((strcmp(Buff1(), Config1) == 0)) &&
(strcmp(Buff2, Config2) == 0))
{
// my code goes here
}
else
{
// Single else clause
}
In addition to Klas's answer(just in case you're not familiar with the AND operator) - the AND operator ('&&') checks the first condition and it continues to check the second condition -only if- the first condition is true.
So in your specific question, it checks if the first couple of strings are equal and only if true (are equal), it checks if the second couple are also equal.
The obvious optimization (not mentioned yet), if you know anything about those strings, is to first perform the compare that is more likely to fail.

Overloaded Operator < to compare strings, sort linked list using string.compare?

If anything in this code looks weird (like the illogical use of pointers) it's because it's for an assignment, so no need to let me know that there's absolutely no reason to use pointers in this situation. Thank you for you help in advance.
The code works for me except one thing, the insertNode function uses an overloaded < from the Pet class. this operator is supposed to compare the strings using the string.compare() function and return true or false based on the resulting value. However no sorting is done at all and the input file is just read in normally from beginning to end.
The problem is in the snippet below
bool Pet::operator <(Pet &right)
{
if (name.compare(right.name) < 0)
return true;
else if (name.compare(right.name) > 0)
return false;
}
It seems to me that there is nothing wrong with this that would cause nothing to be changed. I haven't been able to test if the operators are right (> 0 and < 0) but i'm more concerned that it is doing nothing at all.
Your comparison function doesn't handle the case when the strings are equal.
bool Pet::operator <(Pet &right)
{
if (name.compare(right.name) < 0)
return true;
else if (name.compare(right.name) > 0)
return false;
}
string.compare returns a negative value if it's less then it's argument, 0 when they are equal and a positive value when it's bigger. You don't handle the case when it returns 0 and it therefore falls off the end of the function which is undefined behavior.
Change the else if to:
else if (name.compare(right.name) >= 0)
#Benjamin is right, your whole function could be shortened down to:
bool Pet::operator <(Pet &right)
{
return name.compare(right.name) < 0
}
I somehow always oversee these things when answering questions...

std::list Strict Weak Ordering

I am having a lot of trouble using the std::list::sort function, it works a majority of the time, however every once in a while it throws an assertion 'invalid operator<'. Looking into this issue I have realized it is because my sort function is not following strict weak ordering, however when I look at my code I do not understand why it is not following strict weak ordering as it seems correct, what is it I am missing here?
The purpose of this function is to sort a list of elements into a formula string based on the hill system, ie. Carbon First, Hydrogen Second, all others alphabetically. The FormulaStruct simply represents a single element and amount in the full formula.
struct FormulaStruct
{
FormulaStruct(const std::string & strSymbol, int nNum, bool bHasCarbon)
:
m_strSymbol(strSymbol),
m_nNum(nNum), m_bHasCarbon(bHasCarbon)
{
}
bool operator < (const FormulaStruct & rhs)
{
//If the symbols are equal
if(m_strSymbol == rhs.m_strSymbol)
return true;
if(m_bHasCarbon)
{
if(m_strSymbol == "C")
return true;
else
if(rhs.m_strSymbol == "H")
return false;
}
return m_strSymbol < rhs.m_strSymbol;
}
bool operator == (const FormulaStruct & rhs)
{
return m_strSymbol == rhs.m_strSymbol;
}
std::string m_strSymbol;
int m_nNum;
bool m_bHasCarbon;
};
list<FormulaStruct> FormulaList; //A list of FormulaStructs, assumed to be filled
FormulaList.sort();
EDIT
bHasCarbon is the condition when there is carbon in the formula, as the hill system requires that if there is carbon in the formula than hydrogen will be next, otherwise everything is alphabetical including hydrogen, this is dictated in another section of my code.
Other answers have already addressed the m_strSymbol == rhs.m_strSymbol issue.
But, based on your description ("C" first, "H" next, everything else in order), it seems like you could want, if you have C++11:
return std::tie(m_strSymbol != "C", m_strSymbol != "H", m_strSymbol)
< std::tie(rhs.m_strSymbol != "C", rhs.m_strSymbol != "H", rhs.m_strSymbol);
This is an easy way to write StrictWeakOrderings (stolen from here)
Or, if you don't have C++11 (or Boost pre-C++11), you can do something like this:
// order of checks here is important, in case both are "C"
if(rhs.m_strSymbol == "C")
return false;
if(m_strSymbol == "C")
return true;
// neither symbol is "C"
if(rhs.m_strSymbol == "H")
return false;
if(m_strSymbol == "H")
return true;
// neither symbol is "C" or "H"
return m_strSymbol < rhs.m_strSymbol;
I'm pretty sure I did that right, but as stated in the article posted above, doing it manually is prone to error and probably should be avoided...also, this could definitely be optimized further to reduce the number of string comparisons, at the risk of introducing bugs and obfuscating the code.
But it's unclear what m_bHasCarbon means and what effect that's supposed to have, so I'm not sure if this is what you need or not.
//If the symbols are equal
if(m_strSymbol == rhs.m_strSymbol)
return true;
Meaning it is true for both a<b and b<a if the symbols are equal.
Perhaps you should return false, since a==b and thus !a<b, in this case.
Also your second set of compares are confusing.. what is m_bHasCarbon.

Is this the right way to use recursion?

Given strings s and t compute recursively, if t is contained in s return true.
Example: bool find("Names Richard", "Richard") == true;
I have written the code below, but I'm not sure if its the right way to use recursion in C++; I just learned recursion today in class.
#include <iostream>
using namespace std;
bool find(string s, string t)
{
if (s.empty() || t.empty())
return false;
int find = static_cast<int>(s.find(t));
if (find > 0)
return true;
}
int main()
{
bool b = find("Mississippi", "sip");
string s;
if (b == 1) s = "true";
else
s = "false";
cout << s;
}
If anyone find an error in my code, please tell me so I can fix it or where I can learn/read more about this topic. I need to get ready for a test on recursion on this Wednesday.
The question has changed since I wrote my answer.
My comments are on the code that looked like this (and could recurse)...
#include <iostream>
using namespace std;
bool find(string s, string t)
{
if (s.empty() || t.empty())
return false;
string start = s.substr(0, 2);
if (start == t && find(s.substr(3), t));
return true;
}
int main()
{
bool b = find("Mississippi", "sip");
string s;
if (b == 1) s = "true";
else
s = "false";
cout << s;
}
Watch out for this:
if (start == t && find(s.substr(3), t));
return true;
This does not do what you think it does.
The ; at the end of the if-statement leaves an empty body. Your find() function will return true regardless of the outcome of that test.
I recommend you turn up the warning levels on your compiler to catch this kind of issue before you have to debug it.
As an aside, I find using braces around every code-block, even one-line blocks, helps me avoid this kind of mistake.
There are other errors in your code, too. Removing the magic numbers 2 and 3 from find() will encourage you to think about what they represent and point you on the right path.
How would you expect start == t && find(s.substr(3), t) to work? If you can express an algorithm in plain English (or your native tongue), you have a much higher chance of being able to express it in C++.
Additionally, I recommend adding test cases that should return false (such as find("satsuma", "onion")) to ensure that your code works as well as calls that should return true.
The last piece of advice is stylistic, laying your code out like this will make the boolean expression that you are testing more obvious without resorting to a temporary and comparing to 1:
int main()
{
std::string s;
if (find("Mississippi", "sip"))
{
s = "true";
}
else
{
s = "false";
}
std::cout << s << std::endl;
}
Good luck with your class!
Your recursive function needs 2 things:
Definite conditions of failure and success (may be more than 1)
a call of itself to process a simpler version of the problem (getting closer to the answer).
Here's a quick analysis:
bool find(string s, string t)
{
if (s.empty() || t.empty()) //definite condition of failure. Good
return false;
string start = s.substr(0, 2);
if (start == t && find(s.substr(3), t)); //mixed up definition of success and recursive call
return true;
}
Try this instead:
bool find(string s, string t)
{
if (s.empty() || t.empty()) //definite condition of failure. Done!
return false;
string start = s.substr(0, 2);
if (start == t) //definite condition of success. Done!
return true;
else
return find(s.substr(3), t) //simply the problem and return whatever it finds
}
You're on the right lines - so long as the function calls itself you can say that it's recursive - but even the most simple testing should tell you that your code doesn't work correctly. Change "sip" to "sipx", for example, and it still outputs true. Have you compiled and run this program? Have you tested it with various different inputs?
You are not using recursion. Using std::string::find in your function feels like cheating (this will most likely not earn points).
The only reasonable interpretation of the task is: Check if t is an infix of s without using loops or string functions.
Let's look at the trivial case: Epsilon (the empty word) is an infix of ever word, so if t.empty() holds, you must return true.
Otherwise you have two choices to make:
t might be a prefix of s which is simple to check using recursion; simply check if the first character of t equals the first character of s and call isPrefix with the remainder of the strings. If this returns true, you return true.
Otherwise you pop the first character of s (and not of t) and proceed recursively (calling find this time).
If you follow this recipe (which btw. is easier to implement with char const* than with std::string if you ask me) you get a recursive function that only uses conditionals and no library support.
Note: this is not at all the most efficient implementation, but you didn't ask for efficiency but for a recursive function.

Why use if-else if in C++?

Why would you use if-else statements if you can make another if statement?
Example with multiple ifs:
input = getInputFromUser()
if input is "Hello"
greet()
if input is "Bye"
sayGoodbye()
if input is "Hey"
sayHi()
Example with else-if:
input = getInputFromUser()
if input is "Hello"
greet()
else if input is "Bye"
sayGoodbye()
else if input is "Hey"
sayHi()
If you have non-exclusive conditions:
if(a < 100)
{...}
else if (a < 200)
{...}
else if (a < 300)
....
this is very different from the same code without the "else"s...
It's also more performant.
In your first example, every if will be checked, even if input is "Hello". So you have all three checks.
In your second example, execution will stop once it found a branch, so if the user types "Hello" it will be only one check instead of three.
The difference may not be much in your simple example, but imagine that you're executing a potentially expensive function and you might see the difference.
you mean like this:
if (a == true && b == false && c == 1 && d == 0) {
// run if true
}
if (a == false || b == true || c != 1 || d != 0) {
// else
}
An else-statement would be much clearer and easier to maintain.
If you need to chose exactly one action from given set of actions, depending on some conditions, the natural and most clear choice is either switch (don't forget to break after each branch) or combination of if and else. When I write
if (conditon1)
{
action1();
}
else if (condition2)
{
action2();
}
else if (conditon3)
{
action3();
}
.
.
.
else {
action_n();
}
it is clear to the reader that exactly one of actions is to be performed. And there is no possibility that because of mistake in conditions more than one action is performed.
Following your same example if we use sequence of if conditions, whatever the input is it will run all 3 conditions. Replacing sequence of if with if-else conditions will run only first condition in best case whereas all 3 in worst case.
So conclude with that if-else will save our running time in most cases, therefore using if-else is preferred over using sequence of if conditions.
input = getInputFromUser()
if input is "Hello"
greet()
if input is "Bye"
sayGoodbye()
if input is "Hey"
sayHi()