

C言語の真偽と文字列の比較について解らないので教えてください。

1：真偽について  
真偽について入門書には「偽が0、真が0以外」と有るのですが、if(strcmp(str1, str2) ==
0)で真と偽が逆になってるような気がするのですがこの0は真偽の0とは別の意味ですか？

2：文字列の比較について  
文字列を比較する場合はstrcmp関数を使うとあるのですが、文字列の変数同士は確かに比較で誤った結果になるのですがポインター変数や文字列そのものを比較する時は誤ってないようにも見えます。  
if(str3 == "ABC")はうまく動作してるようですが、実はそう見えてるだけでこれは間違った比較方法なのでしょうか？

[code]

    int main(void) {
        char str1[10] = "ABC";
        char str2[10] = "ABC";
        char *str3 = "ABC";
    
        if (strcmp(str1, str2) == 0) {
            puts("真");
        } else {
            puts("偽");
        }
    
        if (str3 == "ABC") {
            puts("str3 = 真");
        } else {
            puts("str3 = 偽");
        }
        return 0;
    }
    
[/code]


CC BY-SA 3.0
2018-03-22T05:18:25.963
42565
2018-03-22T13:18:28.607
2018-03-22T05:44:36.253
2238
question
c
真偽と文字列の違いについて


> この0は真偽の0とは別の意味ですか？

別です。この0は`strcmp`の戻り値との比較に使っています。

> `if(str3 == "ABC")`はうまく動作してるようですが、実はそう見えてるだけでこれは間違った比較方法なのでしょうか？

`String literal compared with variable 'str3'. Did you intend to use strcmp()
instead?`とか`comparison with string literal results in unspecified
behavior`という警告が出るので、`strcmp`を使うほうが好ましいと私は考えます。


CC BY-SA 3.0
2018-03-22T05:31:13.487
42566
2018-03-22T05:31:13.487
25936
42565
answer


> この0は真偽の0とは別の意味ですか？

「意味」という言葉の受け取り方によりそうですが、基本的には別だと考えて良いです。

まず、C 言語の「真偽値」は、Java など他の言語にある Boolean 型の値とは異なり、実体は単なる数値です。C
言語自体のバージョンによって事情が多少異なるものの、いずれも `0` に「偽」の意味を割り当てているだけです。

したがって、`0` に他の意味を割り当てることもできます。`strcmp` 関数では比較結果が「小さい」「等しい」「大きい」の 3
種類であり、これを整数の返り値で表すため、`0` に「等しい」の意味を割り当てています。

これらの歴史的経緯から、`strcmp(str1, str2) == 0` というプログラムは「`strcmp`
の返り値が『等しい』を意味しているか調べている」と解釈するのがよく、「`strcmp`
の返り値が『偽』なのか調べている」とは解釈しにくいです。この意味で、この `0` は真偽値の `0` とは別の意味です。

> `if(str3 == "ABC")`はうまく動作してるようですが、実はそう見えてるだけでこれは間違った比較方法なのでしょうか？

はい。C 言語で `char *` 型の文字列を比較する際に直接 `==` を使うべきではありません。`str3 == "ABC"`
が実際に行っているのはポインタとの比較であり、文字列との比較ではありません。更に、ポインタとの比較は[思わぬ動作を引き起こす場合があります](https://stackoverflow.com/q/9994202/5989200)。

`strcmp` を使った方が良いことを説明するための例として、`==` と `strcmp` の挙動が異なることを確認できたプログラムを書いてみました。

[code]

    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char *s = "ABCDEF";
        char *t = s + 3;
    
        if (t == "DEF") {
            printf("==: 等しい\n");
        } else {
            printf("==: 等しくない\n");
        }
    
        if (strcmp(t, "DEF") == 0) {
            printf("strcmp: 等しい\n");
        } else {
            printf("strcmp: 等しくない\n");
        }
    
        return 0;
    }
    
[/code]

ポインタ `t` が指し示すのはヌル終端された文字列 `DEF` ですが、[Wandbox
上で実行してみる](https://wandbox.org/permlink/Aw9GD0Iw4jtaLCMP)と以下のように出力されます。

[code]

    ==: 等しくない
    strcmp: 等しい
    
[/code]


CC BY-SA 3.0
2018-03-22T13:18:28.607
42582
2018-03-22T13:18:28.607
19110
42565
answer