参考資料もこれが最後です。今回は、暗号プログラムを作りながら
について学びます。それなりに実用的なプログラムです。
まず、次のとおりにフォーム上にコンポーネント(部品)を配置してください。

ボタンの表示(caption)は「暗号化」にし、入力欄は両方とも空欄にしてください (text)。
次に、プログラム本体を書きます。オブジェクトインスペクタでButtonEncodeのOnClickをダブルクリックし、次のように書いてください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
strcpy(buff, EditFrom->Text.c_str());
EditTo->Text = buff;
}
できたら実行してみましょう。左の欄に何か言葉を(英数字、つまり俗にいう半角のみで)書き、「暗号化」ボタンを押すと、右の欄に同じ言葉がでてきます。
このプログラムは、次のコンソールプログラム(黒い画面で実行するプログラム)とほぼ同じ物です。
main()
{
char *buff[1024];
gets(buff);
printf("%s\n", buff);
}
「gets(buff)」でキーボードから直接入力させる代わりに「strcpy(buff, EditFrom->Text.c_str());」で入力欄を使って入力させ、「printf("%s\n", buff)」で画面に直接表示させる代わりに「EditTo->Text = buff」で入力欄に表示しています。
さて、この「c_str()」は一体何者なのでしょうか。興味がない人はここを読み飛ばして「先頭の1文字を暗号化しよう」まで進んでもかまいません。
とりあえず「c_str()」は放っておいて、EditFromをクリックし、オブジェクトインスペクタのWidthの欄に「abc」と入力し、Enterキーを押してみてください。すると、
'abc'は整数ではありません.
というエラーが表示されますね。このエラーから察するに、Widthは整数でなくてはならないようです。このことを確かめてみましょう。オブジェクトインスペクタの中でWidthが選択された状態で、ファンクションキーの「F1」を押してください。
TControl::Width
TControl 参照 例
Width プロパティはコントロールまたはフォームの水平サイズをピクセル単位で決めます。
__property int Width;
というように書いてありますね。ここに「int」とあるので、Widthは整数しか受け付けないのです。実は、プロパティとは構造体のメンバ変数のようなものであり、この場合は、TEditという構造体 (入力欄を生み出す型) にint型でWidthというメンバ変数がある、というように考えてかまいません。
では、Edit (入力欄) のプロパティであるTextが何型であるか調べてみましょう。入力欄をクリックした後に「F1」を押すと、TEditの、つまり入力欄の説明になります。今度はウィンドウ上部にある「プロパティ」を押してください。すると、画面の左側にプロパティの一覧が表示されます。ここで「Text」を押せば、次のようにTextの説明が表示されるはずです。
TControl::Text
TControl 参照 例
Text プロパティは,コントロールに関連付けられているテキスト文字列を保持します。
__property System::AnsiString Text;
どうやらAnsiString型という型であるようです。
では、このAnsiString型がどういうものなのか、見ていきましょう。
「AnsiString」の部分が緑色になっているので、そこをクリックしてください。AnsiStringについての説明が出てきます。
AnsiString型は文字列型です。(char型は文字列型ではなく文字型と呼ばれ、1つの変数に1文字しか入れることができません。) char型を配列で宣言して、つまり
char buff[80];
というように宣言して文字列を扱うこともできますが、AnsiString型の方が便利です。(AnsiString型の変数を定義するときは「AnsiString buff;」というように書きます。今まで使ってきた「int a;」という宣言と同じ形です。)
画面上部にある「メソッド」を押してください。(メソッドとは何か、は後で説明します。) すると、画面左側にメソッドと呼ばれるものの一覧が表示されます。その中に「c_str」があるので、そこをクリックしてください。
AnsiString::c_str
AnsiString
説明
ヌル終了の文字配列に変換した AnsiString を返します。
char* __fastcall c_str() const;
c_strの後に()とついていることからわかるように、c_strは関数なのです。どういう関数かというと、AnsiString型の文字列をchar*型にして返してくれる関数です。しかし、今まで学んできた関数とは少々違います。今までなら
char* c_str(AnsiString xyz);
というように宣言され
strcpy(buff, c_str(EditFrom->Text));
というように使われてきましたが、メソッドと呼ばれる関数は
strcpy(buff, EditFrom->Text.c_str());
というように「.」の後に(又は「->」の後に)関数名を書きます。とりあえずここでは、「メソッドとは書き方が少々変わっている関数である」と覚えておけばいいでしょう。(いずれC++を学ぶ機会があれば、「メンバ関数」という名前で解説されることがあるでしょう。)
最初は、先頭の1文字だけを暗号化してみましょう。暗号化規則は、「英大文字をみつけたら次の文字にする」とします。つまり、AはBに、IはJになり、aやiや?はそのまま、ということです。ButtonEncodeのOnClickに次の部分を加えてください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
strcpy(buff, EditFrom->Text.c_str());
if ((buff[0] >= 'A') && (buff[0] <= 'Z')) {
buff[0] = buff[0] + 1;
}
EditTo->Text = buff;
}
if文は、「1文字目 (つまりbuff[0]) がAからZまでの文字(つまり英大文字)であるかどうか」を判定しています。そして、英大文字であれば1を足して次の文字にしているのです。試しに実行してみましょう。(警告が出ますが無視してください。) 左の入力欄に「ABC」と入力し、「暗号化」ボタンを押してください。どうですか?「BBC」になりましたか?なお、左の入力欄に日本語を入れると動作がおかしくなる可能性があるので、注意してください。
プログラムをわかりやすく (そしてエラーを出しにくく) するため、暗号化処理の部分を関数にしましょう。
まずは、プログラムの初めの方に次の1行を書き加えてください。
#pragma resource "*.dfm"
char encode(char origin);
TForm1 *Form1;
そして、暗号化処理部分を関数にします。次のように書き換えてください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
strcpy(buff, EditFrom->Text.c_str());
buff[0] = encode(buff[0]);
EditTo->Text = buff;
}
char encode(char origin)
{
if ((origin >= 'A') && (origin <= 'Z')) {
origin = origin + 1;
}
return origin;
}
これで、暗号化する面倒な処理はすべてencode()がやってくれるようになりました。
気づいた人もいるかもいると思います。実は、これまでのプログラムではZは「[」に変換されてしまうのです。これではまずいので、ZはAに変換されるようにしましょう。関数encode()に下線部を付け加えてください。
char encode(char origin)
{
if ((origin >= 'A') && (origin <= 'Z')) {
origin = origin + 1;
if (origin > 'Z') {
origin = origin - 26;
}
}
return origin;
}
これは、「Zを超えた文字になってしまったら26 (アルファベットの数) 引いて英大文字に戻す」という処理です。できたら実行してみましょう。ちゃんとZがAになりましたか?
今度はすべての文字を暗号化してみましょう。すべての文字を暗号化するということは、先頭から1文字ずつ暗号化していきヌル文字が現れた時点でやめる、ということです。プログラムを次のように変更してください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
strcpy(buff, EditFrom->Text.c_str());
int index = 0;
while (buff[index] != 0) {
buff[index] = encode(buff[index]);
index = index + 1;
}
EditTo->Text = buff;
}
indexは「今何文字目を処理しているか」を表す変数です。つまり、indexが4ならば今5文字目を処理している、ということです。while文で「ヌル文字であるかどうか、つまり文字列の終わりであるかどうか」を判定しています。では実行してみましょう。左の入力欄に「ABC」と入力してボタンを押し「BCD」と出てきたらOKです。
プログラムをもっと実用的にするため、2行以上の文書、つまり普通の文書を暗号化できるようにしましょう。
まずは、次のようにフォームに2つのメモ欄
(Memoコンポーネント)を置きます。

メモ欄に最初から文字が入っていると都合が悪いので、左のメモ欄をクリックし、オブジェクトインスペクタの中のLinesをクリック、そしてLines欄の右端に出てくる「…」をクリックし、そこの「MemoFrom」を消して最初は何も表示されないようにします。右のメモ欄も同様に処理します。
とりあえず左のメモ欄は放置しておいて、処理結果を右のメモ欄に書き込むようにしましょう。プログラムを次のように変更してください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
MemoTo->Clear();
strcpy(buff, EditFrom->Text.c_str());
int index = 0;
while (buff[index] != 0) {
buff[index] = encode(buff[index]);
index = index + 1;
}
EditTo->Text = buff;
MemoTo->Lines->Add(EditTo->Text);
}
「MemoTo->Clear();」は「メモ欄の内容を消せ」というメソッドです。このメソッドについて詳しく知りたいなら、メモ欄をクリックして「F1」を押し、「メソッド」を押して出てくる一覧の中から「Clear」を選ぶと説明が出てきます。
「MemoTo->Lines->Add(EditTo->Text);」は「メモ欄に情報を書き加えろ」というメソッドです。このメソッドについて詳しく知りたいなら、まずメモ欄をクリックして「F1」を押し、「プロパティ」を押して出てくる一覧の中から「Lines」を選びます。するとLinesはTStrings型であることがわかるので、「TStrings」を押して「メソッド」を選ぶと出てくる一覧の中から「Add」を選んでやると説明が出てきます。
今度は、左のメモ欄の1行目を処理できるようにしましょう。プログラムを次のように書き換えてください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
MemoTo->Clear();
EditFrom->Text = MemoFrom->Lines->Strings[0];
strcpy(buff, EditFrom->Text.c_str());
int index = 0;
while (buff[index] != 0) {
buff[index] = encode(buff[index]);
index = index + 1;
}
EditTo->Text = buff;
MemoTo->Lines->Add(EditTo->Text);
}
「MemoFrom->Lines->Strings[0];」はメモ欄の最初の行を表しています。(同様に、Strings[1]であれば2行目、Strings[2]であれば3行目を表します。) つまりここでは、左のメモ欄の最初の行を左の入力欄に写しているのです。
なお、「Strings[]」について詳しく知りたければ、メモ欄をクリックして「F1」を押し、「プロパティ」→「Lines」→「TStrings」→「プロパティ」→「Strings」と選んでいくと説明が出ます。
では、すべての行を暗号化できるようにしましょう。プログラムを次のように変更してください。
void __fastcall TForm1::ButtonEncodeClick(TObject *Sender)
{
char buff[1024];
int LineNO;
MemoTo->Clear();
for (LineNO = 0; LineNO < MemoFrom->Lines->Count;
LineNO = LineNO + 1) {
EditFrom->Text = MemoFrom->Lines->Strings[LineNO];
strcpy(buff, EditFrom->Text.c_str());
int index = 0;
while (buff[index] != 0) {
buff[index] = encode(buff[index]);
index = index + 1;
}
EditTo->Text = buff;
MemoTo->Lines->Add(EditTo->Text);
}
}
左のメモ欄の行数は、「MemoFrom->Lines->Count」によって表されます。(詳しい説明は、メモ欄をクリックして「F1」を押し、「プロパティ」→「Lines」→「TStrings」→「プロパティ」→「Count」で表示されます。)
LineNOが「現在何行目を処理しているか」を表しています。これをfor文でCount回繰り返しているので、メモ欄の最後の行まで処理されることになります。プログラムを実行してみてください。
今まで作ってきたプログラムは、英大文字を暗号化するだけでした。暗号文を手作業で解読することもできますが、やはりこれもコンピュータにやらせたいですね。フォームに次のようにボタンを配置してください。

ボタンの表示は「解読」とし、このボタンのOnClickに必要なプログラムを書いてください。暗号化プログラムとほとんど同じ処理になるはずです。(ただし、関数encodeの代わりにdecodeという関数を作る必要があります。) 簡単なので、ここにはプログラムを載せません。自力で作ってください。
解読プログラムを作るのが面倒なら、後から作ることにしてとりあえず先を読み進んでもかまいません。
今のプログラムのままでも、メモ帳やMS-WORDなどのほかのプログラムを起動して、コピー (CTRL+C) や貼り付け (CTRL+V) によって充分に活用することができます。でも、せっかくですから、ほかのプログラムの助けを借りずにこのプログラムでファイルを開いたり保存したりしましょう。
まずは、暗号文 (または解読文)
をファイルに保存できるようにします。コンポーネント一覧の中からDialogs
のページを開き、OpenDialogとSaveDialogを1つずつフォームに置きましょう。また、次のように2つのボタンも置きましょう。

左のボタンの表示は「開く」、右のボタンの表示は「保存」にしてください。
ButtonSaveをクリックしてからオブジェクトインスペクタのOnClickをダブルクリックして、保存ボタンが押されたときの動作を次のように書き込みましょう。
void __fastcall TForm1::ButtonSaveClick(TObject *Sender)
{
MemoTo->Lines->SaveToFile("変換後.txt");
}
SaveToFileは、メモ欄などの内容をファイルに保存するメソッドです。SaveToFileについては、メモ欄をクリックして「F1」を押し、「プロパティ」→「Lines」→「TStrings」→「メソッド」→「SaveToFile」で詳しく知ることができます。
出来上がったら実行してみましょう。まず、左のメモ欄に適当に英大文字を入力し暗号化ボタンを押すと右のメモ欄に暗号文が表示されますね。その後保存ボタンを押すと「変換後.txt」というファイルができているはずです。確認してください。
しかし、このままでは保存するファイル名がいつも「変換後.txt」であり、不便です。そこで、保存する際にファイル名も選べるようにします。プログラムを次のように変更してください。
void __fastcall TForm1::ButtonSaveClick(TObject *Sender)
{
SaveDialog1->Execute();
MemoTo->Lines->SaveToFile(SaveDialog1->FileName);
}
SaveDialog1->Execute()は、「ファイル名をつけて保存」ウィンドウを表示してファイル名を入力させろ、という命令です。入力されたファイル名はSaveDialog1->FileNameに格納されます。詳しい説明は、SaveDialogをクリックして「F1」を押し、「メソッド」→「Execute」で表示されます。
上のプログラムには、まだ欠点があります。それは、「キャンセルボタンを押しても保存しようとすること」です。これを避けるには、プログラムを次のように変更します。
void __fastcall TForm1::ButtonSaveClick(TObject *Sender)
{
if (SaveDialog1->Execute() == true) {
MemoTo->Lines->SaveToFile(SaveDialog1->FileName);
}
}
実はSaveDialog1->Execute()は、「保存」が押されるとtrueになり、キャンセルが押されるとfalseになるのです。これで、キャンセルが押されたときは保存せずにすみます。
ここまでの方法と同様に、開くボタンについてもプログラムを書いてみましょう。やり方は保存ボタンとほとんど同じです。SaveDialog1の代わりにOpenDialog1を使い、メソッドSaveToFileの代わりにLoadFromFileというメソッドを使います。
これまでは英大文字だけを暗号化してきましたが、少し工夫すると英小文字も暗号化できます。やり方は載せませんので、興味があれば自分でやってみてください。おそらく非常に簡単です。
せっかく作ったプログラムは、いろいろな人に使ってほしいと思いませんか? この暗号プログラムを使いたいという人は今はいないかも知れませんが、どんどん改良を重ねていけば、そのうち使ってみたいプログラムになるはずです。
「自由に使ってください」と書かれた無料のプログラムは、フリーソフトと呼ばれ、インターネット上にたくさん公開されています。(似たようなものでシェアウェアと呼ばれるものもあります。) 特に、VECTORと呼ばれる
では3万本以上のフリーソフトやシェアウェアが公開されており、1度は見てみる価値があります。1ヶ月間に数万人にダウンロードされるプログラムもあるのです。
未来の人気プログラムの作者はあなたかも知れません。プログラム実習で扱ったプログラムは堅苦しく感じることもあったでしょうが、ある程度プログラミングができるようになると、このように創造的で楽しい世界が広がっています。
CやC++についてもっと学習したい、と考える人も多いと思います。そこで、石川 (実習指導員) の独断ではありますが、お勧めの書籍とコンパイラを紹介します。
まずは書籍について。C言語についてもっと詳しく学びたいなら、カーニハン, B. W. / リッチー, D. M. 著『プログラミング言語C〔第2版〕』(共立出版, 1989年, 2718円) がいいでしょう。著者はC言語の権威であり、この本に合わせてC言語が作られたといっても過言ではありません。ただし、C言語の初心者にとっては内容が少々難しいです。
C++について学んでみたいなら、柴田望洋著『CプログラマのためのC++入門』(ソフトバンク, 1992年, 2816円) がお勧めです。柴田望洋氏の本には定評があるので、C言語をやりなおすなら『明解C言語入門』(ソフトバンク, 1995年, 2330円) もいいかもしれません。
Borland C++Builderについて学びたいなら、ライスドルフ, K. (ケント) 他著『C++Builder入門 1』(プレンティスホール, 1997年, 3200円) がいいでしょう。入門書は他にもいくつもありますが、たいていは、入門期しか役に立たないないような体系的でない内容です。しかし、『C++Builder入門 1』でも難しいと感じるなら、先に他の本を買ってもいいかも知れません。
コンパイラについては、有名なものは2つあります。MicrosoftのVisual C++とBorland (INPRISE)のC++Builderです。学生証を提示すれば、前者は9800円くらいで、後者は15000円くらいで買えます。Visual C++の方が利用者も多く標準的ですが、C++Builderの方が使いやすいと思います。
お金がもったいなければ、無料のコンパイラを使うこともできます。
http://www.vector.co.jp/vpack/browse/software/maker/lsi/sn001169.html
には無料のCコンパイラがあります。WINDOWS上だけではなく、MS-DOSでも使えます。ただし、C++ではありません。また、昔のコンパイラなので、操作にちょっと戸惑うかも知れません。C言語を学ぶだけならこれで充分です。また、
http://www.vector.co.jp/vpack/browse/software/win95/prog/sn055015.html
には「LSI C-86 超簡単セットアップ」というものもあります。