この質問は、次のコードの出力を通知する必要があるテストで見ました。
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
出力は-1
です。なぜこれが答えなのかはわかりません。
+(+k--)
Cでの表現の意味は?
この質問は、次のコードの出力を通知する必要があるテストで見ました。
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
出力は-1
です。なぜこれが答えなのかはわかりません。
+(+k--)
Cでの表現の意味は?
回答:
[念のため、この回答は承認されて投票されたため、かなり大幅に編集しました。ただし、基本的には同じことを言っています。]
このコードは深く、おそらく故意に、混乱しています。これには、恐怖の未定義の動作の狭く平均化されたインスタンスが含まれています。この質問を作成した人物が非常に賢いか、非常に愚かかを判断することは基本的に不可能です。そして、このコードがあなたに教えるかクイズすることを意図しているかもしれない-つまり、単項プラス演算子はあまり機能しない-確かに、この種の破壊的な誤解に値するほど重要なものではない。
奇妙な条件であるコードには、2つの混乱する側面があります。
while(+(+k--)!=0)
そしてそれが制御する認知症の声明:
k=k++;
最初に2番目の部分をカバーします。
このような変数をk
1つずつ増やしたい場合、Cは1つではなく、2つではなく、3つではなく、4つの異なる方法でそれを行います。
k = k + 1
k += 1
++k
k++
この報奨金にもかかわらず(またはおそらくそのため)、一部のプログラマーは混乱し、次のようなゆがみを吐き出します
k = k++;
これが何をするべきか理解できなくても心配しないでください。誰もできません。この式にはk
、の値を変更する2つの異なる試み(k =
部分とk++
部分)が含まれています。Cには、試行された変更のどれが「勝つ」かを示す規則がないため、このような式は正式には未定義であり、それだけでなく、それは明確な意味はありませんが、それを含むプログラム全体が疑わしいということです。
あなたが見れば今、非常に慎重に、あなたは、この特定のプログラムでは、ラインがいることがわかりますk = k++
制御条件が最初に偽であるので、ループは0回を実行します(私たちが見るしようとしているとして)ので、実際に、実行されません。 。したがって、この特定のプログラムは実際には未定義ではない可能性がありますが、それでも病理学的に混乱します。
この種の未定義の動作に関するすべての質問に対するこれらの正規のSOの回答も参照してください。
しかし、そのk=k++
部分については尋ねませんでした。最初の紛らわしい部分、+(+k--)!=0
状態について尋ねました。それはので、これは、奇妙に見えている奇妙な。誰もそのようなコードを実際のプログラムで書くことは決してありません。それを理解する方法を学ぶ理由はありません。(はい、そのとおりです。システムの境界を探索することは、その細かい点について学ぶのに役立ちますが、私の本には、想像力に富む示唆に富む探索と、ぶつかり合った虐待的な探索との間にかなり明確な境界があり、この表現は非常に明確ですその行の反対側。)
とにかく調べてみましょう+(+k--)!=0
。(そして、そうした後は、そのすべてを忘れましょう。)このような表現は、内側から理解する必要があります。あなたは何を知っていると思います
k--
します。それはk
の現在の値を取り、それを式の残りの部分に「戻し」、多かれ少なかれ同時に減少しますk
。つまり、量をにk-1
戻しk
ます。
しかし、それでは何をし+
ますか?これは単項プラスであり、バイナリプラスではありません。単項マイナスのようなものです。あなたは、バイナリマイナスが減算を行うことを知っています:式
a - b
aからbを減算します。そして、あなたは単項マイナスが物事を否定することを知っています:式
-a
aのネガを与える。単項関数+
が行うことは...基本的には何もしません。 正の値を正の値に、負の値を負の値に変更した後のの値+a
を示しますa
。だから式
+k--
与えられたものk--
、つまりk
の古い値を与えます。
しかし、私たちは完了していません。
+(+k--)
これ+k--
はあなたに与えられたものを取り、単項+
を再び適用します。だから、それはあなたに+k--
与えたものk--
、あなたに与えたもの、それはk
古い価値でした。
結局、状態
while(+(+k--)!=0)
ずっと普通の状態とまったく同じことをする
while(k-- != 0)
行っているだろう。(これは、さらに複雑な外観の条件while(+(+(+(+k--)))!=0)
と同じことを行います。また、これらの括弧は実際には必要ありません。同じことを行いwhile(+ + + +k--!=0)
ます。)
「通常の」状態を把握する
while(k-- != 0)
ちょっとトリッキーです。このループでは、次の2つの処理が行われます。ループが複数回実行される可能性があるため、次のようにします。
k--
にするために、k
ますます小さくするだけでなく、ただしk--
、ループをもう一度実行するかどうかを決定する前(または処理中)に、この部分をすぐに実行します。また、デクリメントする前にk--
、の古い値を「返す」ことを覚えておいてk
ください。このプログラムでは、の初期値k
は0です。したがってk--
、古い値0を「返し」、次にk
-1に更新します。しかし、残りの条件は!= 0
-ですが、今見たように、最初に条件をテストしたときに、0が得られました。ループを実行しないため、実行を試みません。問題のあるステートメントk=k++
です。
つまり、この特定のループでは、「2種類のことが起こっている」と言いましたが、1が1回発生し、2が0回発生していることがわかります。
とにかく、プログラムのこのような言い訳が不十分で、最終的に-1と表示される理由が十分に明らかになったと思いますk
。通常、私はこのようなクイズの質問に答えるのは好きではありません-不正行為のように感じます-この場合、私は練習のポイント全体に激しく同意しないので、私は気にしません。
一見すると、このコードは未定義の動作を呼び出すように見えますが、そうではありません。
まず、コードを正しくフォーマットします。
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
これで、ステートメントk=k++;
がループ内にあることがわかります。
次に、プログラムをトレースしてみましょう。
ループ条件が最初に評価されたときのk
値は0です。式k--
の現在値k
は0でありk
、副作用として減少します。したがって、このステートメントの後の値k
は-1です。
+
この式の先頭は値に影響しないため+k--
、0と+(+k--)
評価され、同様に0と評価されます。
次に、!=
演算子が評価されます。以来0!=0
falseで、ループの本体が入力されていません。本文が入力されている場合、シーケンスポイントなしでk=k++
読み取りと書き込みの両方がk
行われるため、未定義の動作が発生します。しかし、ループに入っていないため、UBはありません。
最後にk
-1 の値が出力されます。
if (x != NULL) *x = 42;
これは未定義x == NULL
ですか?もちろん違います。未定義の動作は、実行されないコードの部分では発生しません。行動という言葉はヒントです。実行されないコードには、未定義などの動作はありません。
k=k++
は定性的にとは異なることに注意してください*x=42
。x
が有効なポインターである場合、後者は明確に定義されていますが、前者は何があっても未定義です。(私はあなたが正しいかもしれないと認めますが、私はそれについて断言するつもりはありません、そして私たちが巧妙にトロールされてきたことをますます心配しています。)