本連載も今回で折り返し地点の第6回となりました。前回は,エラトステネスのふるいを使って素数を求めるプログラムを作成し,ロジックを考えてプログラムを作ることの面白さをお伝えしました。今回は文字列の扱い方とポインタの基礎を解説して,暗号化プログラムを作成してみます。

 インターネットの普及とともに暗号化技術の研究も盛んになっていますね。とはいってもここでは最近用いられるような難解な暗号ではなく,古代ローマのジュリアス・シーザーが使ったといわれるシーザー暗号をプログラミングしてみましょう。*1

なぜ文字列とポインタの知識が必要なのか

 暗号化の話に入る前に,いま一度,C言語とはどんなコンピュータ言語なのかを振り返っておきたいと思います。1970年代に米AT&T社のベル研究所でD. M. Ritchie氏とB. W. Kernighan氏によって開発されたC言語は,C#やJavaを始めとする多くの言語に影響を与えただけでなく,オブジェクト指向化されたC++言語とともに,現在でも広く使われています。しかし普及したからといって,C言語を甘く見てはいけません。Cをプログラムするとき,プログラマは常にCの危険性を肝に銘じておく必要があります。

 一つ目は「ポインタ演算などの機能を持ち,アセンブラのようなハードウエアに密着した操作ができる」ことです。これはOSを書くためには必須のもので,もともとC言語はUNIXを書くために作られたのですから,当然といえば当然ですね。

 もう一つは「文字列はNULL文字でターミネートする配列であり,配列操作の実体はポインタ演算である。標準ライブラリに用意されている文字列を操作する関数はバッファ・オーバーフロー*2を考慮していない」という点です。

 文字列操作やポインタは,便利な半面,操作を誤ると思わぬバグを引き起こします。実際,ポインタ演算の機能は,バグの原因やコンピュータを暴走させる危険性があるという理由で,Javaなどでは省かれています。

 C言語にはそういった危険な要素があるんだぞということを理解しつつ,バグを作らないためにも,文字列とポインタの基礎をしっかり身に付ける必要があるのです。

文字列は文字 (char型)の配列で扱う

 Javaなどの言語では,複数の文字を並べた“文字列”を扱うためにString型という型が用意されています。しかし,C言語には文字列を扱う型がありません。そのためC言語では,文字(char型)の“配列”として文字列を扱います。

 例えば,「Jonny」という文字列を扱うときは,リスト1のように配列に代入する必要があります。(1)で1バイト文字が0から9の10文字ぶん格納できる配列を宣言し,(2)以降で一文字ずつ代入しています。(3)で代入している「\0」はNULL*3文字を表すエスケープ文字です。C言語の場合,文字列はNULLでターミネート(終了)します。難しく聞こえるかもしれませんが,NULLを文字列の終わりとして判断する記号に使っているわけです。土の中に,Jonnyという名前を一文字ずつ記入したカプセルを埋めたとイメージしてください(図1)。掘り出していくと,J,o,n…と順番に文字が出てきます。yまで掘っても,これで終わりだよというマークがなければ,「まだ,何かあるんじゃないか」と掘るのを止めることができません。この「これで終わりだよマーク」がC言語ではNULLなのです。ですから,文字列を格納する場合は文字数プラス(NULLのための)1バイトが必要なのです(図2)。

リスト1●Jonnyという文字列を配列に格納するプログラム
リスト1●Jonnyという文字列を配列に格納するプログラム

図1●埋まっている文字列の最後にあるのが「\0」
図1●埋まっている文字列の最後にあるのが「\0」

図2●文字列を格納する場合は文字数プラス1バイトが必要
図2●文字列を格納する場合は文字数プラス1バイトが必要

 文字(char)型で,「a」を記憶するには1バイトしか必要ありません。しかし,文字列として(char型の配列として),「a」1文字を記憶するには,2バイト必要になるわけですね*4

 しかし,文字列を扱うのにいちいちリスト1のように書いていたら大変です。文字列の配列の初期化は,リスト2の(1)のようにまとめて書くこともできますし,(2)のようにダブルクォートでくくって記述することもできます。この場合は末尾に自動的にNULLが付加されます。どう考えても(2)の方が簡単ですよね…。ただし,このとき文字列はダブルクォートでくくり,文字はシングルクォートでくくる点に注意してください。なお,コードの途中で

char str2[10]="Lucy";

str2[10]="Linda";

のようにして文字列を代入することはできません。コンパイル・エラーになります。文字列配列に他の配列を代入することはできないからです。

リスト2●文字列の配列の初期化は,ダブルクォートでくくって記述できる
リスト2●文字列の配列の初期化は,ダブルクォートでくくって記述できる