いきなりですが問題です.以下のソースコードをご覧ください.なお文字コードはASCIIを仮定します.
/* caesar.c */ #include <stdio.h> int main(void) { char text[] = "sleep"; int i, j; printf("%2d: %s\n", 0, text); for (i = 1; i <= 26; i++) { for (j = 0; j < sizeof(text) - 1; j++) { char c = text[j]; if ('a' <= c && c <= 'z') { text[j] = (c - 'a' + 1) % 26 + 'a'; /* ココ */ } } printf("%2d: %s\n", i, text); } return 0; }
(1) コンパイルして実行すると,何を出力しますか.またその出力には,どのような特徴がありますか.
(2) /* ココ */ と書いた行の処理を,日本語で説明してください.
さっそくですが解答です.まずは(1)から.出力は以下のとおり.
0: sleep 1: tmffq 2: unggr 3: vohhs 4: wpiit 5: xqjju 6: yrkkv 7: zsllw 8: atmmx 9: bunny 10: cvooz 11: dwppa 12: exqqb 13: fyrrc 14: gzssd 15: hatte 16: ibuuf 17: jcvvg 18: kdwwh 19: lexxi 20: mfyyj 21: ngzzk 22: ohaal 23: pibbm 24: qjccn 25: rkddo 26: sleep
この出力の特徴ですが,連続する2つの行の英字について,出現位置ごとに「その次の文字」になっています.
すべての出力で考えたとき,英字の最初の文字はs→t→u→...→r→sとアルファベット小文字で1ずつ「次」に行き(ただしzの次はa),最終行で最初のsに戻っています.2番目の文字はl→m→n→...→k→l,となっており,lから始まって1文字ずつ「次」の文字になり,lに還ります.残りの文字も同様です.
行ごとに,5文字の英字の並びを見ていったとき,「9: bunny」というのがあります.これは次のことを意味します.すなわち,シーザー暗号で暗号化されたという「atmmx」を解読したとき,sleepのほかbunnyも,「意味のある英単語」として平文の候補になり得るのです.
(2)の答えは…逐次的には「英小文字の文字コードが格納された変数cに対し,'a'の値を引いて1を加え,26で割った余りに'a'を加えた値を計算する.右辺は,変数cの値が'z'のときは'a',それ以外のときは,次の文字となる.この値を,文字配列textの先頭よりj要素分だけ後ろの場所に代入する.」で,字数を減そうとするなら,「cに格納された文字の次の文字を,配列textのj番目に代入する」と書き,'z'の次は'a'だとか,配列の先頭は0番目になるだとかを,必要に応じて補足すればいいでしょうか.
といったところで元ネタです.昨年12月の授業で取り上げたサンプルプログラムです.ただし,(1)の出題はこちらで解説し,(2)を授業終了時の「まとめテスト」で問いました.
(2)の式の処理について,解説用のスライドも作りました.該当箇所を切り出しておきます.
このプログラムについては,以前にも解説していました.
なぜ今どきこのプログラム? といいますと,学科内で毎年1回,1年間の担当科目の状況を報告しておりまして,ちょうど見直す機会があったのです.
自分の昨年度後期のプログラミング科目では,優良可などの数や学生満足度,新たに取り組んだ内容に加えて,どんな出題をしたかを報告することにし,その一部が,上記プログラムだったという次第です.
C言語において,文字を表す型は整数型となる(他言語もそうとは限らない)点は,注意したいところです.
(リリース:翌日未明)