2010-03-18 10 views
3

Ce code très simple:comparaison entre chaîne littérale

#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; 
} 

génèrent deux avertissement: comparaison avec les résultats chaîne littérale dans un comportement non spécifié.

Pouvez-vous expliquer exactement pourquoi ce code ne fonctionne pas, mais si je change

char opt[] 

à

char *opt 

cela fonctionne, mais génère l'avertissement? Est-ce lié à la terminaison \ 0? Quelle est la différence entre les deux déclarations d'opt? Que faire si j'utilise const qualifier? La solution consiste à utiliser std :: string?

+2

L'un des doublons: http://stackoverflow.com/questions/1997778/c-comparing-c-string-problem –

+0

Lorsque vous faites 'if (option ==" foo ")', vous ne comparez pas deux chaînes - vous comparez deux * pointeurs * –

Répondre

10

tableaux char ou pointeurs char ne sont pas vraiment la même chose que des objets de classe de chaîne en C++, donc ce

if (option == "foo") 

Ne compare pas la chaîne option à la chaîne littérale "foo" il compare l'adresse de option avec l'adresse de la chaîne littérale "foo" ". Vous devez utiliser l'une des nombreuses fonctions de comparaison de chaînes si vous voulez savoir si l'option est la même que "foo". strcmp est la manière évidente pour ce faire, ou vous pouvez utiliser std::string au lieu de char*

+0

pourquoi si je déclare opter comme char * ça marche? –

+2

Cela "fonctionne" pas parce que vous l'avez déclaré comme char * mais parce que vous l'avez assigné pour pointer vers la chaîne littérale "foo". Ensuite, quand vous le comparerez plus tard au littéral "foo", l'adresse sera la même _si le compilateur a combiné les deux "foo" s_ Compilateurs reconnaîtront souvent que vous avez utilisé la même chaîne littérale à deux endroits et les deux se réfèrent à la même littérale, mais cela ne va pas fonctionner dans le cas général. –

+0

Si le commentaire de John n'est pas assez clair, 'char x [] =" ... "' crée un bloc contigu de 'char's en mémoire et copie le contenu, tandis que' char * x = "... "' crée un seul pointeur et affecte l'adresse du littéral. –

1

Vous pouvez utiliser l'opérateur == pour comparer des chaînes uniquement si vous utilisez std::string (ce qui est une bonne pratique). Si vous utilisez des chaînes char */char [] de style C, vous devez utiliser les fonctions C strcmp ou strncmp.

Vous pouvez également utiliser la std::string::operator == pour comparer std::string avec une chaîne C:

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

if (foo == bar) 
    ... 
+0

ok, mais si je ne veux pas utiliser C includes et utiliser char * comme argument de la fonction, c'est bien de faire si (std :: string (option) = = std :: string ("foo"))? –

+0

si (std :: string (option) == "foo") fonctionnerait, j'ai édité la réponse pour cela. –

+0

@wiso: Pourquoi voulez-vous utiliser char * au lieu d'une chaîne, mais ne pas inclure les fonctions cstring? –

0

On dirait que vous êtes venu de Java/C# :) En C++ chaîne est juste un pointeur vers la mémoire où les personnages sont stockés et ombles nulle au fin. Si les chaînes "semblent" égales, elles peuvent pointer vers différentes zones de la mémoire et ne seront pas égales. Pour vérifier l'égalité, utilisez la classe std :: string de C++ ou la fonction C strcmp.

+0

Le même problème se produit en Java. La comparaison avec '==' est incorrecte car elle ne compare que les références et non les chaînes référencées. Là encore, en Java, une seule copie de chaque chaîne littérale est conservée en mémoire, donc comparer deux références String au même littéral fonctionnera (comme si vous utilisiez 'char *' au lieu de 'char []' en C/C++ avec compilateurs qui suppriment les littéraux en double) –

+0

Ok, donc Java pas. Dans C# str == "asd" invoque str.Equals ("asd"), car il y a une surcharge de l'opérateur – Andrey

2

La raison pour laquelle cela ne fonctionne pas est que la comparaison ne compare pas les chaînes, mais les pointeurs de caractères.

La raison pour laquelle il peut fonctionner lorsque vous utilisez char * est parce que le compilateur peut décider de stocker la chaîne « opt » une fois et le réutiliser pour les deux références (je suis sûr que je l'ai vu quelque part établir compilateur indique si le compilateur le fait).

Dans le cas de char opt [], le compilateur copie la chaîne littérale dans la zone de stockage réservée au tableau opt (probablement sur la pile), ce qui provoque la différence entre les pointeurs.

Renze

0

Pour C++ j'utiliser le 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 sait se créer à partir de char [], char *, etc., de sorte que vous peut encore appeler la fonction de cette façon aussi.

Questions connexes