views:

320

answers:

5

This very simple code:

#include <iostream>

using namespace std;

void exec(char* option)
{
    cout << "option is " << option << endl;
    if (option == "foo")
        cout << "option foo";
    else if (option == "bar")
        cout << "opzion bar";
    else
        cout << "???";
    cout << endl;
}

int main()
{
    char opt[] = "foo";
    exec(opt);
    return 0;
}

generate two warning: comparison with string literal results in unspecified behaviour.

Can you explain why exactly this code doesn't work, but if I change

char opt[]

to

char *opt

it works, but generates the warning? Is it related to the \0 termination? What is the difference between the two declaration of opt? What if I use const qualifier? The solution is to use std::string?

+1  A: 

You can use == operator to compare strings only if you use std::string (which is a good practice). If you use C-style char*/char[] strings, you need to use C functions strcmp or strncmp.

You can also use the std::string::operator == to compare std::string with a C string:

std string foo = "foo";
const char *bar = "bar";

if (foo == bar) 
   ...
Laurynas Biveinis
ok, but if I don't want to use C includes and use char* as argument of the function is it good to do if(std::string(option) == std::string("foo")) ?
wiso
if (std::string(option) == "foo") would work, I have edited answer for that.
Laurynas Biveinis
@wiso: Why do you want to work with char* instead of string, but not include cstring functions?
Mark B
You are right. In general I don't like to use c libraries in c++, so I'll switch to std::string. I wanted to use char* in the parameters to don't change the signature of the function.
wiso
+6  A: 

char arrays or char pointers aren't really the same thing as string class objects in C++, so this

if (option == "foo")

Doesn't compare the string option to the string literal "foo" it compares the address of option with the address of the string literal "foo". You need to use one of the many string comparison functions if you want to know if the option is the same as "foo". strcmp is the obvious way to do this, or you can use std::string instead of char*

John Knoeller
why if I declare opt as char* it works?
wiso
It "works" not because you declared it as char* but because you assigned it to point to the string literal "foo". Then when you later compare it to the literal "foo" the address will be the same _if the compiler has combined the two "foo"s_ Compilers will often recognise that you used the same string literal in two places and have them both refer to the same literal, but that isn't going to work in the general case.
John Knoeller
In case it is not clear enough from John comment, `char x[] = "..."` creates a contiguous block of `char`s in memory and copies the contents, while `char * x ="..."` creates a single pointer and assigns the address of the literal.
David Rodríguez - dribeas
A: 

Looks like you came from Java/C# :) In C++ string is just a pointer to memory where characters are stored and with null char at the end. If strings "look" equal they may point to different areas in memory and will not be equal. to check equality either use C++'s class std::string or C function strcmp .

Andrey
The same problem happens in Java. Comparing with `==` is incorrect as it only compares the references and not the referred strings. Then again, in Java only one copy of each string literal is kept in memory, so comparing two String references to the same literal will work (just like if you use `char *` instead of `char []` in C/C++ with compilers that remove duplicate literals)
David Rodríguez - dribeas
Ok, so Java not. In C# str == "asd" invokes str.Equals("asd"), because there is operator overloading
Andrey
+2  A: 

The reason why it doesn't work is because the comparison does not compare strings, but character pointers.

The reason why it may work when you use char* is because the compiler may decide to store the literal string "opt" once and reuse it for both references (I am sure I have seen a compiler setting somewhere that indicates whether the compiler does this).

In the case of char opt[], the compiler copies the string literal to the storage area reserved for the opt array (probably on the stack), which causes the pointers to be different.

Renze

Renze de Waal
A: 

For C++ I would use the std::string solution:

#include <iostream> 
#include <string>

using namespace std; 

void exec(string option) 
{ 
    cout << "option is " << option << endl; 
    if (option == "foo") 
        cout << "option foo"; 
    else if (option == "bar") 
        cout << "option bar"; 
    else 
        cout << "???"; 
    cout << endl; 
} 

int main() 
{ 
    string opt = "foo"; 
    exec(opt);

    exec("bar");

    char array[] = "other";
    exec(array);
    return 0; 
} 

std::string knows how to create itself out of char[], char*, etc, so you can still call the function in these ways, too.

Bill