わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

sleepから始まるシーザー暗号

いきなりですが問題です.以下のソースコードをご覧ください.なお文字コードは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言語において,文字を表す型は整数型となる(他言語もそうとは限らない)点は,注意したいところです.

(リリース:翌日未明)