いきなりですが問題です.以下のプログラムの出力が「1 -1 1 -1 1 -1 1 -1 1 -1」となるようにするには,/* ??? */と書いた箇所にどのようなコードを書けばいいでしょうか.
#include <stdio.h> int main(void) { int i, x = 1; for (i = 0; i <= 10; i++) { printf("%d ", x); /* ??? */ } printf("\n"); return 0; }
さっそくですが解答です.「x = -x;」と書けばいいでしょう.
この文を実行するごとに,
- (実行前の)xの値が1なら,xには-1が代入される
- (実行前の)xの値が-1なら,xには1が代入される
ので,出力は「1 -1 1 -1 1 -1 1 -1 1 -1」となります.
続いてですが問題です.上のプログラムを修正して,プログラムの出力が「0 1 0 1 0 1 0 1 0 1」となるようにします.まず,「x = 1」を「x = 0」に変更します.そして,/* ??? */と書いた箇所にどのようなコードを書けばいいでしょうか.
これについても解答です.「x = 1 - x;」と書きます.上と同様に,次のことが言えます.
- (実行前の)xの値が0なら,xには1 - 0の計算結果である,1が代入される
- (実行前の)xの値が1なら,xには1 - 1の計算結果である,0が代入される
なお,「x = x - 1;」ではありません.これだと,出力は「0 -1 -2 -3 -4 -5 -6 -7 -8 -9」となります.
「x = 1 - x;」の形の代入は,毎年,プログラミング科目でC言語を扱うときの最終回に使用しています.AliceとBobによる,おはじき取りのゲームです.一度に取るのは1個か2個か3個のいずれかとし,最後に取ったほうが負けというルールで,はじめに個数の値をscanfで獲得し,1回分のゲームを実施する(printfで経過を出力していく)というプログラムです.
プログラムではint p = 0;と宣言して初期化し,この変数の値が0のときはAlice,1のときはBobに対応付けます(playerのpです).単一のwhileループの中で,残り個数をもとに取る数を決め,「Alice took 3」といった文を出力*1し,それから「p = 1 - p;」を実行します.おはじきの残り個数は別の変数で管理していて,その値が0になると,whileループ*2を抜けまして,そのときのpの値は,最後におはじきを取った人の反対,ということで勝者を意味し,「Winner is Alice」または「Winner is Bob」を出力します.おはじきを取る個数を返すのと,上記のpの値に応じて「Alice」または「Bob」を出力するのは,それぞれ関数を定義してmain関数から呼び出します.
最初の問題のように,「1 -1 1 -1 1 -1 1 -1 1 -1」と変数の値が変化するプログラムは,授業では使用していませんが,例えば数学の偶置換・奇置換における置換の符号*3を,自前で計算するのに,有用となるかもしれません.
ここまでを踏まえて最後に,問題です.先ほどの「x = 1 - x;」を変更して,プログラムの出力が「0 -1 0 -1 0 -1 0 -1 0 -1」となるようにします.どのようなコードを書けばいいでしょうか.
これについても解答です.負の数に関して,2の補数表現が採用されていることを前提とするなら,「x = ~x;」と,ビット反転の単項演算子~*4を使用するのが最も簡潔です.2の補数表現でない場合でも大丈夫なようにしようとすると,「x = -1 - x;」と書けばいいでしょう*5.以下が成り立ちます.
- (実行前の)xの値が0なら,xには-1が代入される
- (実行前の)xの値が-1なら,xには0が代入される
*1:昨年度までに授業を受けてこの記事を見た人へ.Linux使用の際には日本語メッセージを出力させていましたが,今年度のコマンドラインインタフェースだと,日本語メッセージは文字化けしまして,今回,メッセージはすべてASCII文字で出力するよう,プログラムを変更したのでした.
*2:このループの中に,「Aliceの番」と「Bobの番」の処理を順番に書いているわけではありません.ループ内は「AliceまたはBobの番」の処理にしていまして,pの値が0ならAliceの番,1ならBobの番を意味します.
*3:https://mathtrain.jp/permutation
*4:この演算子は,論理否定の単項演算子!と別物です.ところで,論理演算の評価結果は0または1になることに注意すると,「0 1 0 1 0 1 0 1 0 1」を出力させる問題について「x = !x;」も正解と言えます.
*5:空白はあってもなくても問題ありませんが,「2項演算子は前後に空白を入れる」「単項演算子とそのオペランドの間には空白を入れない」という慣例にもとづくと,「x = -1 - x;」と書くことになります.