Cで「a」!=「a」となるのはなぜですか?


110
void main() {
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

なぜ出力No, not equalですか?


100
void main??? ええと...
ポールR

47
組み込みCコンパイラでは、戻りコードを渡すオペレーティングシステムがない可能性があるため、void main()を使用できます。
Jeanne Pindar、2011年

26
このような質問はどのようにして頻繁に投票されるのですか?それは本当に興味深いことではありません...つまり、文字列は配列であり、配列はポインタであるということは、Cの古い帽子ですよね。
Felix Dombek、2011年

64
@Felix、それは簡潔に書かれた質問であり、この言語の初心者にとって一般的な混乱のポイントに対処します。SOはエキスパート専用ではありません-初心者向けでもあります。このような対象を絞った質問は、初心者を将来紹介するのに適しています。
bdonlan 2011年

37
@Felix:あなたは間違っている。 配列はポインタではありません
John Dibling、2011年

回答:


209

比較しているのは、異なる場所に格納されている異なる文字列の2つのメモリアドレスです。そうすることは基本的に次のようになります。

if(0x00403064 == 0x002D316A) // Two memory locations
{
    printf("Yes, equal");
}

次のコードを使用して、2つの文字列値を比較します。

#include <string.h>

...

if(strcmp("a", "a") == 0)
{
    // Equal
}

さらに、"a" == "a"コンパイラーによっては、実際にtrueを返す場合があります。コンパイラーは、スペースを節約するために、コンパイル時に等しい文字列を1つに結合する場合があります。

2つの文字値(ポインターではない)を比較する場合、それは数値比較です。例えば:

'a' == 'a' // always true

12
GCCはまた、オプションを持っている-fmerge-constantsし、-fno-merge-constantsいくつかのGCCの上一定のマージは関係なく、常にそのオプションの有効化されているようですが、有効にする/無効にする文字列と翻訳単位間でのマージ浮動小数点定数を。
Adam Rosenfield、2011年

2
「a」の代わりに「a」を使用すると機能します。1つ目はcharで、これは実際には数値です。
GolezTrol、2011年

@GolezTrol:Cでは、リテラル「a」は実際にint型を持っています。:-)また、ポインタは数値である必要はありません。
バスティアンレオナール、2011年

int数値でもありませんか?しかし、文字はバイトだと思いました。Intは4バイトです。ポインタ自体も整数です。それらには、一連のデータ(実際に数値である必要はないデータ)のアドレスが含まれています。
GolezTrol、2011年

'a' == 'A' // not true... MySQLは異なることを頼みます。
スティーブン

52

パーティーには少し遅れますが、とにかく返事をします。技術的には同じビットですが、少し異なる観点から(以下のCの用語):

Cでは、式"a"文字列リテラルを示します。これは、名前のない静的な配列でconst char、長さは2です。配列は文字'a'で構成され'\0'、終端のnull文字は文字列の終わりを示します。

ただし、Cでは、配列を値で関数に渡すことができないのと同じように、または(初期化後に)配列に値を割り当てることができません。配列にはオーバーロードされた演算子がない==ため、直接比較することはできません。検討する

int a1[] = {1, 2, 3};
int a2[] = {3, 4, 5};
a1 == a2 // is this meaningful? Yes and no; it *does* compare the arrays for
         // "identity", but not for their values. In this case the result
         // is always false, because the arrays (a1 and a2) are distinct objects

それが==配列を比較していない場合、それは実際には何をしますか?Cでは、ほとんどすべてのコンテキスト(これを含む)で、配列は(配列の最初の要素を指す)ポインターに減衰し、ポインターが等しいかどうかを比較すると、期待どおりの結果になります。これを行うと、効果的に

"a" == "a"

名前のない2つの配列の最初の文字のアドレスを実際に比較しています。C標準によれば、比較の結果はtrueまたはfalse(つまり1または0)になる"a"可能性があります-sは実際には同じ配列または2つの完全に無関係な配列を表す場合があります。技術的な面では、結果の値は不定(すなわち、それはありません比較が許可されていることを意味し、未定義の動作や構文エラー)が、いずれかの値が有効であると実装(コンパイラ)は、実際に何が起こるかの文書には必要ありません。

他の人が指摘したように、「c文字列」(つまり、ヌル文字で終了する文字列)を比較するにはstrcmp、標準ヘッダーファイルにある便利な関数を使用しますstring.h。関数には、0等しい文字列の戻り値があります。戻り値を明示的に比較することは良い習慣と考えられています0演算子 `! 'を使用代わりに勧めします。つまり、

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)

47

C99によると(セクション6.4.5 / 6)

文字列リテラル

これらの配列が異なるかどうかは、その要素が適切な値を持っているかどうかは不明です

したがって、この場合、両方"a"のが異なるかどうかは不明です。最適化されたコンパイラーは単一"a"を読み取り専用の場所に保持し、両方の参照がそれを参照する可能性があります。

ここでgccの出力を確認してください


19

それらは2つの独立したconst char*のポインタであるため、実際の値はありません。0x019181217 == 0x0089178216もちろん、NOを返すようなものを言っている

strcmp()代わりに使用==


7
文字列リテラルはポインタではなく、配列です。しかし、それらは比較の際の指針に腐敗します。
GManNickG 2011年

@Gman true、本当に明確になっていないため申し訳ありませんが、忘れがちです:)
Antwan van Houdt

9

簡単に言うと、Cには文字列比較演算子が組み込まれていません。この方法で文字列を比較することはできません。

代わりに、文字列はstrcmp()などの標準ライブラリルーチンを使用するか、文字列内の各文字をループするコードを記述することによって比較されます。

Cでは、二重引用符で囲まれたテキストの文字列は、文字列へのポインタを返します。あなたの例はポインタを比較していて、どうやらあなたの2つのバージョンの文字列は異なるアドレスに存在しています。

しかし、あなたが期待しているように、それは文字列自体を比較していません。


3

ポインタ。

最初 "a"は、ヌルで終了するASCII文字列へのポインタです。

二番目 "a"は、ヌルで終わる別のASCII文字列へのポインタです。

あなたは32ビットコンパイラを使用している場合、私は期待したいです"a"=="a"-4。私はちょうどかかわらず、TCC / Win32のでそれを試してみた、と私は得ます"a"=="a"-2。しかたがない...


6
文字列が4バイト境界に揃えられると予想するのはなぜですか?彼らはintではありません。2は私が期待するものです(コンパイラーがそれらをマージしない場合)。各文字列は、ヌルターミネーターを含めて2バイト長であるためです。
セルゲイタシェノフ2011年

たとえば、ある程度のアラインメントにより、一度にstrcmp数バイトを実行できる場合があります。一部のコンパイラはそれを実行し、一部は実行せず、一部は最小値より長い文字列に対してのみ実行します...
zwol

@ザック:実際に比較する前に、文字列の長さをどのように知るのでしょうか?
Joachim Sauer

つまり、一部のコンパイラは、一部の最小値よりも長い文字列を整列します。
zwol 2011年

1

2つのメモリアドレスを比較しているため、結果が常に正しいとは限りません。やってみましたif('a' == 'a'){...}か?


1

この質問は、すべての初心者に非常に良い説明の足跡を残します。
私もそれに貢献してみましょう.....

上記の誰もがについて説明したように、なぜそのような出力を得るのですか?

今あなたがあなたのPROGが欲しいなら。「はい」と印刷するには

どちらかを使用

if(strcmp("a", "a") == 0)
{

}

または
「a」を文字列として使用せずに、文字として使用します...

if('a'=='a')  
{  
printf ("yes Equal");  
}  

Cの文字は1バイトの短整数です。


文字は1バイトしか占有しませんが、などの文字リテラル'a'は実際には整数です。
Spidey

0

一部のコンパイラには、すべての定数文字列に同じアドレスを強制するために使用できる「文字列のマージ」オプションがあります。それを使用する場合は、に"a" == "a"なりますtrue


0

文字間の比較が常に一重引用符で囲まれている場合、たとえば

if('a' == 'a')

Cは次のような文字列比較をサポートできません "abc" == "abc"

それで終わりました strcmp("abc","abc")


-5

この男は変数を使用しません。その代わり、彼は一時的にテキストアレイを使用していますaa。理由

void main() 
{
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

もちろん機能しません。変数を比較しないということです。
次のような変数を作成する場合:

char * text = "a";
char * text2 = "a";

あなたは、比較可能性texttext2、それがあるべき

多分あなたは使用すること{を忘れないでください}=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}

1
" そしてそれは本当でなければならない "-いいえ。文字列リテラルが同じメモリ位置に格納されるかどうかは指定されていません。他の答えを読んでください。
Spikatrix 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.