• ベストアンサー

if文の判定条件('||'と'&&'の使い方)

○if文の判定条件への理解が弱いため、下記プログラムを作成し、 疑問があったため、質問をしたいと思っております。 #include<stdio.h> #include<string.h> int main() { char moji[]= "A"; /***********************************************************/ if( 0 != strcmp( moji , "A" ) || strcmp( moji , "B" ) ) ^^(1) /***********************************************************/ { printf( "文字不一致" ); } else { printf( "文字一致" ); } return (0); } ○質問 「/*/」で囲ったif文の判定箇所になりますが、 この判定条件は"配列mojiに格納されている値が"A",または"B"以外の" ときに、画面上に「文字不一致」を出力します。そうでなければ 「文字一致」を出力します。 今回、配列mojiには"A"が格納されており、「文字一致」が画面に 出力されるはずですが、「文字不一致」が出力されてしまいます。 判定条件が誤っていると思い、色々と試したところ、(1)の箇所を 「&&」にしたときに、「文字不一致」が出力されます。 「||」(論理和)と「&&」(論理積)が理解できていないと思われ、 この部分を交えて、何故「&&」にしないと「画面不一致」と出力 されないのかを、ご教授の程お願い致します。

  • KGM
  • お礼率44% (66/148)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

No.3 です。 --------------------------- (1)は配列mojiにAが格納されていない場合 (2)は配列mojiにBが格納されていない場合 《 略 》 (3)では(1)と(2)で出力された値の論理積(偽と真の論理積)を取り、 偽となるので、else側に移り、「文字一致」が出力される。 --------------------------- この理解で、考え方としては合っています。 普段はこれでOKです。 ただ、C言語ではもうひとつ別の問題があります。 No.4 の方の回答でも触れられていますが。 もともと、&& や || の性質として、 && が、「真」になるのは、両方が真の時だけ、つまり、左側が「偽」なら、右側が何であっても、「偽」 || が、「偽」になるのは、両方が偽の時だけ、つまり、左側が「真」なら、右側が何であっても、「真」 という事があります。 C言語ではこれを積極的に取り入れており、 1) && は、左側が「偽」であれば、右側は調べなくても全体として「偽」になるに決まっている。したがって、右側は調べない。 2) || は、左側が「真」であれば、右側は調べなくても全体として「真」になるに決まっている。したがって、右側は調べない。 という動きをします。 ですから、このケースでは、(1)の部分が「偽」となった時点で、全体が偽になるのが明らかです。ですから、(2)の部分は、調べません。 よって、C言語の動きに沿っていえば、 (1)の部分が「偽」となる。だから、((2)を調べるまでもなく)(3)全体として、「偽」となり、else 部分が実行される という流れになります。 もっとも、これは、結果としては真偽表と矛盾はしないので、補足にお書きになったような理解でも普通はかまいません。 ただし、&& や || 以降の部分を調べることが、他の影響を与える時(例えば、strcmp() の中に(たとえ話です)「一致した」とかいう出力を行う部分があったら、この出力が1回しかでなかったり(&& の前で「偽」が決定した時)2回出たり(&& の前が「真」だったので、後ろも調べた時)というように、この影響を考慮しなければならない場合もあります。

KGM
質問者

お礼

このコメントで理解することができました。 確認までしていただき、ありがとうございました^^ また、ご教授お願い致します。

その他の回答 (6)

  • nobe
  • ベストアンサー率66% (59/89)
回答No.7

まず実行結果ですが、 上記プログラムの実行結果は「文字不一致」が表示されるのですよね? ページ上うまく出ていないので良くわかりませんが、 論理和の代りに論理積をを指定すると「文字一致」が表示される ということかと思います。 解説します。 if( 0 != strcmp( moji , "A" ) || strcmp( moji , "B" ) ) これは正確に書けば↓こういう式ですよね。 if (0 != strcmp(moji,"A") || 0 != strcmp(moji,"B")) strcmpをさらに抽象的に書いてみますと if (moji != "A" || moji != "B") となりますね。 C/C++は式の評価が左から行われます。 また、論理和(||)演算子では、 演算子自体の優先度が低いので 左側の式が先に評価されます。 左側と右側に分けて考えて見ましょう。 左側の moji != "A" ですが、mojiは"A"であるので評価は偽です。 論理和(||)演算子は左側式の結果が偽なら右辺の評価を行います。 次に評価されるのは moji != "B" ですが、 mojiは"A"なので "A" != "B" となり評価結果は真となりますよね。 つまり、 if (moji != "A" || moji != "B")      ↓   if (偽 || 真) ですから、論理和(||)演算子の結果が真となるので 「文字不一致」が表示されます。 日本語にすれば「mojiが"A"でなく、または、"B" でない」です。 "B"でないことは確かなので、このプログラム通りの動作をしていると言えます。 代りに論理条件をAND(論理積)とした場合、評価結果は if (moji != "A" && moji != "B")      ↓   if (偽 && 真) となります。論理和と違い、論理積演算子は、演算子の両側が真でなければ論理積演算子の結果が真にならないので、 「文字一致」のほうが表示されます。 if (moji != "A" && moji != "B") を日本語にすれば「mojiが"A"でもなくかつBでもない」、 「かつ」が論理積に相当しますね。 論理和(||)演算子の動作は、コンパイラ内部の動作からみると、 論理和演算子の左側を評価して、真であれば、右側の評価はせずに 結果として真を返します。 左側の結果が偽のときにのみ右側の式も評価して、その結果を 論理和演算子の結果とします。 逆に、論理積(&&)演算子は、 論理積演算子の左側を評価して、偽であれば、右側の評価はせずに、 論理積演算子の結果として返します。 懸案の評価式ですが "A" でも "B" でもないときに「文字不一致」と出したいのであれば、 if( 0 != strcmp( moji , "A" ) && strcmp( moji , "B" ) ) とするのが妥当ではないでしょうか。 補足ですが、strcmp関数について。 一致するときは0を返します。 ↓こういう感じで覚えておくといいと思います。 strcmp(a,b) != 0 → a != b strcmp(a,b) == 0 → a == b strcmp(a,b) > 0 → a > b strcmp(a,b) < 0 → a < b お役にたちましたでしょうか。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.6

★回答者 No.4 です。最初にお詫びします。→回答を一部、間違いました。 ・下のが修正した正しい内容です。  間違い⇒『moji が A なら真』  正しい⇒『moji が A 以外なら真』    if ( (moji が A 以外なら真) || (moji が B 以外なら真) ){   (1)  }  else{   (2)  }  となります。 ★本題、『strcmp』関数について解説します。  この関数は2つの文字列の内容を比較します。そして、次のような値を返します。  引数が strcmp( 文字列A, 文字列B ); の場合、  (1)文字列Aは文字列Bより小さい⇒0以下(文字列A<文字列B)  (2)文字列Aは文字列Bと全く同じ⇒0  (文字列A=文字列B)  (3)文字列Aは文字列Bより大きい⇒0以上(文字列A>文字列B)  という値を返します。3つの状態 0以下、0、0以上です。 ・それで文字列の一致する戻り値は 0 の時です。  このことから次のようになります。  『strcmp(moji,"A")』⇒この式が『真』になるのは、moji が A 以外の場合(つまり不一致)  『!strcmp(moji,"A")』⇒この式が『真』になるのは、moji が A の場合(つまり一致)  となります。また、  『strcmp(moji,"A") != 0』⇒『strcmp(moji,"A")』と同じ意味(不一致)  『strcmp(moji,"A") == 0』⇒『!strcmp(moji,"A")』と同じ意味(一致)  としても同じです。 ・上記のを踏まえると KGM さんの質問にある  『if ( (0 != strcmp(moji,"A")) || strcmp(moji,"B") )』の意味は  『if ( (moji が A 以外のとき真) || (moji が B 以外のとき真) )』と解釈できて  moji に A がセットされている状態では、常に if 直下のブロックである『文字不一致』が  表示されたのです。 ロジック: if ( (moji が A 以外のとき真) || (moji が B 以外のとき真) ){  『文字不一致』を表示 } else{  『文字一致』を表示 } 組み合わせ:論理和タイプ moji が A のとき⇒if ( 偽 || 真 )ですが、論理和であるため if 内は『真』となり『文字不一致』を表示 moji が B のとき⇒if ( 真 || 偽 )ですが、論理和であるため if 内は『真』となり『文字不一致』を表示 moji が C のとき⇒if ( 真 || 真 )ですが、論理和であるため if 内は『真』となり『文字不一致』を表示   : moji が Z のとき⇒if ( 真 || 真 )ですが、論理和であるため if 内は『真』となり『文字不一致』を表示 組み合わせ:論理積タイプ moji が A のとき⇒if ( 偽 && 真 )ですが、論理積であるため if 内は『偽』となり『文字一致』を表示 moji が B のとき⇒if ( 真 && 偽 )ですが、論理積であるため if 内は『偽』となり『文字一致』を表示 moji が C のとき⇒if ( 真 && 真 )ですが、論理積であるため if 内は『真』となり『文字不一致』を表示   : moji が Z のとき⇒if ( 真 && 真 )ですが、論理積であるため if 内は『真』となり『文字不一致』を表示 最後に: ・何かコメント下さいな。1行でもいいです。寂しいです。  分からなかったらば、また別の回答を出します。 ・以上。

KGM
質問者

お礼

返信が遅れてしまい、申し訳ございません。 基本情報技術者試験と業務のため、レスをかくことができませんでした。 内容はほとんど理解することができました。 この式自体があやふや過ぎたとこもあり、自分自身が混乱して しまったものだと思ってしまいます。混乱するとダメですね^^ また、わからないことがありましたら、ご教授お願い致します。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★何故なのかを解説します。 ・KGM さんの if-else を分かりやすくすると次のようになります。  if ( (moji が A なら真) || (moji が B 以外なら真) ){   (1)  }  else{   (2)  }  このプログラムでは、  moji が A のとき⇒(1)を処理(文字不一致)  moji が B のとき⇒(2)を処理(文字一致)  moji が C のとき⇒(1)を処理(文字不一致)      :  moji が Z のとき⇒(1)を処理(文字不一致)  という処理が行われます。 ・このことから moji が A のときは『文字不一致』が表示されて正しいのです。  次に『||』を『&&』に変更すると、  if ( (moji が A なら真) && (moji が B 以外なら真) ){   (1)  }  else{   (2)  }  このプログラムでは、  moji が A のとき⇒(1)を処理(文字不一致)  moji が B のとき⇒(2)を処理(文字一致)  moji が C のとき⇒(2)を処理(文字一致)      :  moji が Z のとき⇒(2)を処理(文字一致)  という処理が行われます。 ・このことから moji が A のときだけ『文字不一致』が表示されです。 ・つまり、プログラムの考えそのものが矛盾したおかしな記述なのです。  上記を参考にしてプログラムし直して下さい。 その他: ・論理和『||』と論理積『&&』の含まれた式は、最初に真または、偽となったらば、  その次の式は評価しないで if ブロック、else ブロックに制御が移ります。  このことから、moji に A がセットされていると常に『真』の状態になるため  if ブロックの(1)である『文字不一致』が表示されてしまったのです。 ・また、『&&』に変更した後は、moji が A 以外では常に『偽』となるためすべて  else ブロックの(2)である『文字一致』が表示されていますのです。 ・C/C++言語では、  論理和(||)のとき、最初に『真』になった式があれば、直ぐに if ブロックに制御を  論理積(&&)のとき、最初に『偽』になった式があれば、直ぐに else ブロックに制御を  移動させてしまいます。この動作に注意! ・以上です。→上記の動作を踏まえてプログラミングし直して下さい。

回答No.3

おそらく正解は、|| (または)を使うのであれば、 if ((strcmp( moji , "A" ) == 0) || (strcmp( moji , "B" ) == 0)) printf( "文字一致" ); else printf( "文字不一致" ); です。 もとの形に近づけようとすれば、 if ((strcmp( moji , "A" ) != 0) && (strcmp( moji , "B" ) != 0)) printf( "文字不一致" ); else printf( "文字一致" ); です。 さて、順次考えてみましょう。 まず、 > 配列mojiに格納されている値が"A",または"B"以外の"ときに、画面上に「文字不一致」を出力します これはどういう意味でしょうか? 別に揚げ足取りではなくて、 a)(moji の値が "A" である)または、(moji の値が "B" 以外) の時に、「文字不一致」 b)moji の値が ("A" または "B") 以外の時に、「文字不一致」 どちらの意味にも取れます。 ここでは、「 > 配列mojiには"A"が格納されており、「文字一致」が画面に出力されるはずですが とのことから、b)の意味だとします。 この場合、C言語のレベルでは、 b)( (moji の値が "A") または (moji の値が "B")) 以外の時に、「文字不一致」 となります。 つまり、strcmp() の結果を、毎回比較する必要があるということです。 これをこのまま書くと、 if (! ((strcmp(moji, "A") == 0) || (strcmp(moji, "B") == 0) ) printf("文字不一致"); となります。 ~ 以外の時 というのを、そのまま表現するために、最初に ! (否定演算子)がついています。 この ! を取り除くには、 1)もともと条件が反対なのだから処理を入れ替える if ((strcmp(moji, "A") == 0) || (strcmp(moji, "B") == 0) printf("文字一致"); 2)論理式を反転させて if ((strcmp(moji, "A") != 0) && (strcmp(moji, "B") != 0) printf("文字不一致"); のいずれかに変形できます。 == と != , || と &&, 文字一致 と 文字一致 の関係に注意してください。 もともと、 moji が ("A" または "B" )でないとき というのは、つまり、"A" でも "B" でもないときですから、 moji が "A" でない、かつ "B" でない となります。 最後に、もともとの式が、エラーにもならずとにかく動いてしまうのは、 if( 0 != strcmp( moji , "A" ) || strcmp( moji , "B" ) ) が、 (0 != strcmp( moji , "A" )) または strcmp( moji , "B" ) という意味だからです。 今回の場合、 (0 != strcmp( moji , "A" )) の部分は、moji が "A" なので、意味としては、 「偽」になります。 ところが、後半の strcmp( moji , "B" ) は、strcmp() の定義から、0 でない 結果となり、こちらは、if() の判定では「真」となります。 ですから、偽 || 真 で、if() 全体の結果は、「真」となり、if() の直後にある、「文字不一致」が表示されます。 一方で、|| を && に置き換えると、偽 && 真 で、if() 全体の結果は、「偽」となり、else の次にある、「文字一致」 ※ここで、「偽」とか「真」とか表現しているのは、C言語の意味では厳密には間違っていますが。

KGM
質問者

補足

下の箇所の説明のお陰で理解できたと思います。 ここで、確認したいことがあるのですが、 if( ( 0 != strcmp( moji , "A" )) || ( 0 != strcmp( moji , "B" )) ) ^^^^^^^^^^^^^^^^^^^^^^^^^^(1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^(2) このようにした場合、 (1)はmojiにAが設定されているので、0以外の値が出力されます。 #この箇所だけで判定すると文字不一致が出力されます。 (2)はmojiにAが出力されていますので if ((strcmp( moji , "A" ) != 0) && (strcmp( moji , "B" ) != 0)) ^^^^^^^^^^^^^^^^^^^^^^^^^^(1) ^^^^^^^^^^^^^^^^^^^^^^^^^(2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^(3) { printf( "文字不一致" ); } else { printf( "文字一致" ); } この部分を確認させて下さい。 (1)は配列mojiにAが格納されていない場合 (2)は配列mojiにBが格納されていない場合 を表します。 プログラム上では、(1)はmojiにAが格納されているので一致し、出力される値は0となり、「 != 0」とは 一致しないので、結果は「偽」となる。 (2)はmojiにAが格納され、Bとマッチしていないので一致せず、出力される値は0以外(1)となり、「 != 0」と 一致するので、結果は「真」となる。 (3)では(1)と(2)で出力された値の論理積(偽と真の論理積)を取り、 偽となるので、else側に移り、「文字一致」が出力される。 という認識であっているでしょうか。 理論は理解できているようなのですが、いまいちしっくりこない状態です。

  • jicchi2
  • ベストアンサー率27% (5/18)
回答No.2

プログラムと質問文が一致しないないようです。 strcmpは一致したときに0を戻し、不一致のときは0以外を戻しますので、 「値が"A",または"B"以外」という条件ならば、 if( 0 == strcmp( moji , "A" ) || 0 != strcmp( moji , "B" ) ) となります。 プログラムのほうが正しいのであれば、 「値が"A"以外、または???」 となります。 また"||"を"&&"に変えた場合、 「値が"A"以外、かつ???」 となります。 もう一度内容を整理されたほうがよろしいかと思います。

KGM
質問者

お礼

整理した結果、内容を理解することができました。 お手数おかけしました。

  • cojirou
  • ベストアンサー率50% (59/117)
回答No.1

>判定条件は"配列mojiに格納されている値が"A",または"B"以外の" ときに、画面上に「文字不一致」を出力 日本語の文章ですと「または」とあるので、「||」(論理和)を用いてしまったようですが、 プログラムとして解釈する場合には、 配列mojiに格納されている値が"A"以外かつ"B"以外 と記述しなくてはなりません。 ということで、「&&」(論理積)を用いるのが正しいのではないでしょうか。 Cに詳しくはないので参考までに。

KGM
質問者

お礼

自分が意図しているようにならないと、大混乱してしまいました。 ご迷惑おかけしました。

関連するQ&A

  • while文とif文

    #include <stdio.h> void main() { char str[2][6] = {"hello","lop"}; int i = 0; while(i < 2){ printf("%s\n", str[i++]); } } 上のプログラムの条件判定の部分にif文を つかうとhelloという文字列しか出力されず while文を使うとhelloとlop 二つ出力され ます。上の条件判定のif文にした時ととwhile 文にした時の違いはどこなのでしょうか?? どなたかご教授よろしくお願いしますm(_ _)m

  • perlのif文(条件の指定方法)につきまして

    おそらく単純な事だと思われますが、 不慣れなものでお付き合いいただけますとありがたいです。 if( $hoge == $testdata){ # 条件が一致した場合の処理 } $hoge には、2 が入っています。(文字列) $testdata には、2,6,10 が入っています。(文字列) 1対1であれば、上記の記述でいけるのですが、 カンマ区切りの復数の値と一致判定する方法がわかりません。 まず、配列にして my @testdata_hairetu = split(/,/, $testdata); などやってみましたが、 その後の条件文との絡みなどで詰まっています。 復数値がある場合に一つ一つ照合(判定)していく方法をご教授いただけないでしょうか。 foreachの内部でifとかかなと調べ中です。 perlは記述方法がいろいろあるようなのですが、できれば短さよりもわかり易い方が有難いです。 どうぞよろしくお願いします。

  • if文の判定条件に配列

    2次元配列(ここではa[M][N]とします)の値が全て0の時にだけある文章を実行したいのですが、 if(for(i=0; i<M; i++){ for(j=0; j<N; j++) map[i][j] == 0; }){ (実行したい文) } という文をコンパイルしたところエラーが出てしまいました。 if文の判定条件中にfor文は使えないのでしょうか? 使えないのであれば、別の書き方を教えて戴けると嬉しいです。よろしくお願いします。

  • if( strcmp( 引数, 引数 )=== 0

    サンプルで、 if( strcmp( 第1引数, 第2引数 ) === 0 ){ て書いてあるコードを見たのですが、 この === 0 には、どういう意味があるのでしょうか? (==0とはどう違うのでしょうか? という意味です) 試しに、型の一致を確認できるのかな? と思いやってみたのですが、 うまくいきませんでした。 $a = "10"; $b = 10; if( strcmp( $a, $b ) === 0 ){ print "2つの文字列は同じです!"; } else { print "2つの文字列は違います"; } strrposの返り値判定に「===」を使うのだったら、 意味は分かるのですが、 それとは意味合いが違うような (strcmpに===を使う意味はないような)気もするのですが…

    • ベストアンサー
    • PHP
  • while文の判定について(C言語)

    while文の判定についてです たぶんすごいつまらないミスなので時間の余っている方 ご指導ください<_ _> (自分ではいろいろ調べましたが原因がわかりません><、) returnやbreakを使わないで二分探索を終了させよとの問題で low-highで2ならばデータが見つかったとき 1ならば見つからなかったときという判定で whileで抜けさせたいのですがどうしても抜けません><、 論理演算子の使い方が間違っているのでしょうか? #include<stdio.h> #define N 10 int main(void) { static int a[]={2,3,4,11,31,50,55,70,77,80}; int key,low,high,mid; high=N-1; low=0; int i=0; printf("検索するdata ? :");scanf("%d",&key); ここです while((2!=(low-high)) || (1!=(low-high))){ mid=(low+high)/2; if(a[mid]==key){ low=mid+1; high=mid-1; } else if(a[mid]<key){ low=mid+1; } else{ high=mid-1; } } if(2==(low-high)){ printf("%2dは%2d番目にありました",key,mid); } else{ printf( "見つかりませんでした" ); } return 0; } while内でlow-highをprintfで出力しましたが2と1が出力されました

  • エクセル if文で偽判定のとき、何も起こらないようにしたいのですが・・・

    宜しくお願いします。 エクセル2003のif文で、偽の判定の時に何も起こらない状態にしたいのですがどうすればいいのでしょうか? 例えば =if(A1=A2,"○","") とすると偽の判定のときに空欄になってしまいますよね? 既に文字が入力されているところにコピペしても、偽の判定ならば打ち込まれた文字が残るようにしたいのですが・・・・ 教えて頂ければと思います。 宜しくお願いいたします。

  • if文ができません・・・。

    文字を入力してその入力された文字が 「 A 」 だったら 「 当たり 」 と表示させるプログラムを作りたいのですができません。「 A 」 以外を入力しても 「 当たり 」 と表示されてしまいます。下記のプログラムで正しいと思うのですがどこが間違っているのでしょうか? #include <stdio.h> void main (void) { int mozi ; scanf ("%c",&mozi); if (mozi=='A'); printf("当たり"); }

  • 一致する要素が格納されている添え字番号を返す

    例えばある配列内に @moji = (ak, df, gc); などという値でも文字でもが格納されていたとして、 $x = "ak"; といったある変数に格納されている値・文字(この場合はak)と一致する要素が配列@mojiに格納されていた場合に、その格納されている要素の添え字番号(配列の添え字番号)を返すような関数はないでしょうか? イメージとして $res = mch($x); とすると、0が返されて$resに格納されるというものです。 ちなみにRという言語では > a <- c("ljj", "B0", "op199") # 変数aに3つの文字列要素を代入する > res <- which(a == "op199") # which()は引数に指定された論理に一致する要素番号を返す > res # aについて,a == "op199"がTRUEとなるのは要素番号3であるから,3を返す [1] 3 というものがあるのですが、これと同じような関数が欲しいのです(泣)

    • ベストアンサー
    • Perl
  • while文の条件

    参考書でC言語を勉強しておりますが、タイトルの件で分からないことがあります。 #include <stdio.h> #include <string.h> void main(void) { char *p = "stop"; char str[80]; do { printf("文字列を入力してください:"); gets(str); }while(strcmp(p , str)); } while文は条件が真(0でない)の場合に繰り返し、偽(0)の場合に抜けるという認識なんですが、上記のwhile文だと、strcmp()の戻り値が0の場合(偽)に繰り返しを抜けます。 なぜなのか分かりません。 どなたか教えてください。

  • while文の条件

    参考書でC言語を勉強しておりますが、タイトルの件で分からないことがあります。 #include <stdio.h> #include <string.h> void main(void) { char *p = "stop"; char str[80]; do { printf("文字列を入力してください:"); gets(str); }while(strcmp(p , str)); } while文は条件が真(0でない)の場合に繰り返し、偽(0)の場合に抜けるという認識なんですが、上記のwhile文だと、strcmp()の戻り値が0の場合(偽)に繰り返しを抜けます。 なぜなのか分かりません。 どなたか教えてください。

専門家に質問してみよう