3章 変数と型

 

【学習内容とねらい】

 

 本章では、「変数」について学習します。変数といっても数学の方程式に出てくる変数とはちょっと意味が違います。プログラミングの世界では、変数とは、データの記憶(格納)場所のことを指します。 ・・・ と言っても、まだピンと来ないかもしれませんね。しかし、実はすでに皆は「変数」に“遭遇”しているのです。

 

例えば、「エディット」コンポーネントの「Text」プロパティにはエディット欄に入っている“文字”が記憶されていますし、「Width」プロパティには“欄の横幅の値”が記憶されています。この意味でコンポーネントのプロパティは変数だったのです。

 

ただし、この「Textプロパティの変数」と「Widthプロパティの変数」には大きな違いがあります。というのは、Widthプロパティは「その値を2倍する」、あるいは「5を加える」などの計算(算術演算)ができるのに対し、Textプロパティには算術演算はできないからです。ですからコンピュータの中で一律に扱うことはできません。どうやら、変数はその性質に応じて“タイプ分け”しておくことが必要なようです。そこで、「変数の型」という概念が現れます。

 

以上を念頭において、本章の各節を一つ一つ確かめながら読み進んで行けば、「変数」および「変数の型」の概念を理解することができるはずです。また、自分独自の変数をプログラム中で定義して使用することもできるようになります(これを「変数の宣言」と言います)。

 

変数はプログラミングの基礎中の基礎であり、また同時に初心者がつまずきやすいところでもあります。どうか、ていねいに流れを追いながら学習して行って下さい。本章を理解すればプログラミング学習の最初の“関門”を突破したことになります。

 

 

<第3章の構成>

 


3−1  「+」演算子 (1) −「エディット」による足し算−

3−2  「+」演算子 (2) −「スピンエディット」による足し算−

3−3  データの型

3−4  型変換 (1) −整数型と文字列型の相互変換−

3−5  型変換 (2) −「エディット」による足し算の完成−

3−6  改行・空白・コメント・大文字小文字

3−7  変数 (1) −変数としての Text プロパティ−

3−8  変数 (2) −宣言して使う変数−

3−9  実数型変数

3−10 定数 (1) −整数型定数−

3−11 定数 (2) −文字列型定数−

3−12 変数と定数 (1) −「スピンエディット」を作ろう−

3−13 変数と定数 (2) −「メモ」を使ってみよう

3−14 配列変数

 


3-1 「+」演算子 (1) ―「エディット」による足し算―

【練習問題】

という状態で「足す」ボタンを押すと足し算して

と表示するプログラムを作ってみましょう。

まずはフォーム上にコンポーネントを配置して、次の画面を作ってください。

コンポーネント

Name

上のエディット

Edit1

中のエディット

Edit2

下のエディット

EditResult

ボタン

ButtonAdd

次に、ボタンを押したときの動作をプログラミングします。「ButtonAdd」の「OnClick」イベントに対するプログラム(イベントハンドラ)を書きましょう。下線部はどのように書くとよいでしょうか?

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

                   =                  +                 ;

}

実行結果を確かめましょう。 

【練習問題】

このプログラムで、左上のエディットに「佐藤」、左中のエディットに「さん」と入れて「足す」ボタンを押すと、左下のエディットには何と表示されますか?

                

実は現段階では、14+31=45 のような数の足し算を実現できません。どうしたらいいでしょう?  ・・・  考えながら次節へ進んで下さい。

3-2 「+」演算子 (2) ―「スピンエディット」による足し算―

【基礎課題 3-1

今度は、スピンエディットに替えて足し算をさせてみましょう。フォーム上に3つのスピンエディットを次のように配置してください。

コンポーネント

Name

左上のスピンエディット

CSpinEdit1

左中のスピンエディット

CSpinEdit2

左下のスピンエディット

CSpinEditResult

右のボタン

ButtonAdd

ボタンを押したときの動作はどのようにプログラミングするとよいでしょうか。

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

                   =                  +                 ;

}

出来上がったら、適当な数値を入れて「足す」ボタンを押し、プログラムの動作を確かめましょう。

 

今度はうまく足し算ができたはずです。

どうやら「エディット」コンポーネントと「スピンエディット」コンポーネントには何らかの“違い”があるようです。その種明かしは次節で行いましょう。


3-3 データの型

エディットを使った足し算とスピンエディットを使った足し算が違うのは、Edit1->TextSpinEdit1->Value の「型」というものが違うためです。型には名前がつけられています。

プロパティ

型の名前

日本語名

データ形式

足し算の結果

Edit1->Text

AnsiString

文字列型

文字 (231文字まで)

14 + 31 = 1431

CSpinEdit1->Value

int

整数型

整数(-231〜231-1まで)

14 + 31 = 45

 

【練習問題】

CSpinEdit1->Value に次の値を入れて、CSpinEdit1->Value整数しか受け付けないことを確かめましょう。

 

「ヘルプ」キーを使ってプロパティの型を調べられる場合もあります。ここでは、エディットの Text プロパティの型を調べてみましょう。フォーム上にエディット (Edit1) を置き、オブジェクトインスペクタで Edit1 の 「Text」 をクリックし、[F1]キーを押してみましょう。

 

すると、次のようなTextプロパティに対するヘルプメニューが開きます。

 

枠内の記述から、TextプロパティがAnsiString(文字列)型であることが分かります。

一般に[F1]キーを使うと、該当事項に関するヘルプメニューを開くことができます。この意味で、[F1]キーは「ヘルプ」キーと呼ばれています。

 

【練習問題】

Edit1Width プロパティの型を調べてください。

                

ButtonAddCaption プロパティの型を調べてください。

                


3-4 型変換 (1) ―整数型と文字列型の相互変換―

【練習問題】

「エディット」では普通の足し算はできませんでしたが、「スピンエディット」ではできました。そこで、まずは「エディット」から「スピンエディット」へのコピープログラムを作ってみましょう。次のようなフォームを作ってください。

コンポーネント

Name

左のエディット

Edit1

真中のスピンエディット

CSpinEdit1

右のボタン

ButtonAdd

下のようにプログラムを入力してください。

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

  CSpinEdit1->Value = Edit1->Text;

}

実行してみましょう。  

すると ・・・       次ページへ進んで下さい。


'AnsiString' 型は 'long' 型に変換できない 」というエラーが出てしまいます。これは、左辺と右辺の「型が合っていません」という意味のエラーです。

テキスト ボックス: CSpinEdit1->Value

 

 


では、エディットからスピンエディットへのコピーはできないのでしょうか?

実は、Delphi には、文字列型の数字を整数型の数値に変換する StrToInt() という命令があります。Edit1->TextStrToInt() で包むと、データは整数型となり、SpinEdit1->Value に代入できるようになります。

 


テキスト ボックス: CSpinEdit1->Value

 

 

 


【練習問題】

プログラムを次のように変更して実行してみてください。

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

   CSpinEdit1->Value = StrToInt(Edit1->Text);

}

 

【基礎課題 3-4-1

上のプログラムを改変して、逆に、スピンエディットからエディットに値を移すプログラムを作りましょう。この場合、StrToInt() ではなく IntToStr() という命令を使います。

StrToIntStringTo Integer 型 の略です。

IntToStr IntegerTo String 型 の略です。

 


3-5 型変換 (2) ―「エディット」による足し算の完成―

【基礎課題3-5-1】

当初の目的どおり、エディットを用いて

という状態で「足す」ボタンを押すと足し算を行い

と表示するプログラムを作りましょう。

 

 

と言いたいところですが・・・

3-1の【練習問題】の足し算プログラムの時のように

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

   EditResult->Text = Edit1->Text + Edit2->Text ;

}

というプログラムを作っても、数値としての足し算はしてくれないのでした。

そこで、ここではまず、エディットのかわりにスピンエディットに計算させるプログラムを作ります。まずは次のようにフォームを作ってください。コンポーネントの Name プロパティは自由に付けても構いません。


今まで学んできたこと(整数型 ←→ 文字列型の変換)を用いればできます。次の順に「型変換」あるいは「足し算」処理をプログラムすれば良いでしょう。

これで当初の足し算プログラムが完成しました。

 

【基礎課題 3-5-2】

上のプログラムのフォームから右下の「スピンエディット」を削除しましょう。

そのまま実行するとエラーが出ます。エラーを出さずに今までどおりに足し算ができるよう、プログラムを変更してください。

 ヒント : (3) の処理と (4) の処理を一緒におこなってしまえば…。

 

【基礎課題 3-5-3】

さらに、残りの右の「スピンエディット」も削除しましょう。

そのまま実行するとエラーが出ます。エラーを出さずに今までどおりに足し算ができるよう、プログラムを変更してください。


3-6 改行・空白・コメント・大文字小文字

C++Builder でのルール

(1)    どこで改行しても、しなくてもよい。

(2)    空白がいくつ並んでいても1つの空白とみなす。

(3)    /*」と「*/」で囲まれた部分、および「//」から行末までは無視される。

(4)    大文字と小文字を区別する。

 

(1) 次の2つのプログラムは同じものです。

 


void __fastcall TForm1::Button1Click(TObject *Sender);

{

  EditResult->Text = IntToStr(StrToInt(Edit1->Text) + StrTo

}

 


void __fastcall TForm1::Button1Click(TObject *Sender);

{

  EditResult->Text =

IntToStr(StrToInt(Edit1->Text) +

StrToInt(Edit2->Text));

}

 

 

ただし、

void __fastcall TForm1::Button1Click(TObject *Sender);

{

  EditResult->Text = IntT

oStr(StrToInt(Edit1->Text) + StrToInt(Edit2->Text));

}

 

というように字句の途中で改行してはいけません。

 

(2) 次のプログラムは文法的には正しいプログラムです。

 

void __fastcall TForm1::Button1Click(TObject *Sender);

    {

       SpinEdit1->Value = StrToInt(Edit1->Text   );

SpinEdit2->Value     = StrToInt(   Edit2->Text);

SpinEditResult->Value =  SpinEdit1->Value + SpinEdit2->Value;

    }

 

しかし、このプログラムは、「{} によって囲まれた部分がプログラムである」という構造が非常にわかりにくくなっています。また、余計な空白を入れると文の意味が分かりにくくなり、誤解が生じかねません。そこで、下のように記述したらどうでしょうか?

 

void __fastcall TForm1::Button1Click(TObject *Sender);

{

SpinEdit1->Value = StrToInt(Edit1->Text);

SpinEdit2->Value = StrToInt(Edit2->Text);

SpinEditResult->Value = SpinEdit1->Value + SpinEdit2->Value;

}

 

かなりすっきりするでしょう?ここで特に注意して欲しいことは、{} の間の行は先頭に空白を入れて先頭を揃えプログラムをみやすくする、という点です。これを「字下げ」といいます。字下げは、プログラムの体裁上のことなのでどうでもいいことの様に思うかもしれません。しかし、論理構造を視覚的に分かりやすく記述することは、ミスを減らす、あるいは作業効率を上げるという観点からも重要なことです。

 

(3) C++Builder はプログラムの中に半角の「 /* 」があると、そこから半角の「 */ 」までを無視します。このことを利用して、プログラムに自由にコメントをつけることができます。また、「//」を利用することもできます。コメントには全角文字を使っても構いません。プログラムをわかりやすくするため、コメントを有効に使うようにしましょう。

 


void __fastcall TForm1::Button1Click(TObject *Sender);

{

// 2数の和を求めるプログラム

SpinEdit1->Value = StrToInt(Edit1->Text); /*上のEditの値*/

SpinEdit2->Value = StrToInt(Edit2->Text); /*中央のEditの値*/

SpinEditResult->Value = SpinEdit1->Value + SpinEdit2->Value;

}

 

 

(4)  C++Builder は大文字と小文字を区別します。ですから、「Edit1->Text」と「EDIT1->Text」や「edit1->text」などは、全て異なるものとして認識されます。このため、最初の内は、「Edit1->Text」のつもりで、「edit1->Text」などと記述してエラーになることがよくあります。注意してください。C++Builderはコンポーネントやプロパティの名前は通常「Edit1->Text」や「SpinEdit1->Value」のように、単語の先頭を大文字にするようになっています。


3-7 変数 (1) ―変数としての Text プロパティ―

 

【練習問題】

という画面で「入れ替え」ボタンを押すと

上のエディットの Text プロパティ (攻撃) と下のエディットの Text プロパティ (守備) が入れ替わる、というプログラムを作りましょう。

 まず、次のようにフォームを作ってください。

コンポーネント

Name

左上のエディット

Edit1

左下のエディット

Edit2

右のボタン

ButtonSwap

そして[入れ替え]ボタンをクリックした時のプログラムを下のように記述してください。

 

void __fastcall TForm1::ButtonSwapClick(TObject *Sender);

{

Edit2->Text = Edit1->Text;

Edit1->Text = Edit2->Text;

}

 

上下のエディットに適当な言葉を入れて実行してみましょう。うまく動きましたか?

実はこのままではうまく入れ替えができませんね。それは何がまずいのでしょうか?また、どうしたらいいでしょうか。

 

 

                                                


【基礎課題 3-7-1】

うまく入れ替えを行うためには、Edit2.Textを取り敢えず保存しておく「エディット」が必要です。次のように、データの中継用のエディットを加えてください。(Temp temporary=一時的 の略です。)

コンポーネント

Name

上のエディット

Edit1

中のエディット

Edit2

下のエディット

EditTemp

ボタン

ButtonSwap

EditTemp

 

以下の空欄を埋めてプログラムを完成させ、動作を確かめてください。

void __fastcall TForm1::ButtonSwapClick(TObject *Sender);

{

                                           

                                            

                                           

}

このままでもプログラムは正しく動きますが、中継用エディットが画面に表示されるのは格好悪いですね。次の問に対して予想を立ててから、実行して確かめてみましょう。

【練習問題】

予想 EditTempWidth8 にしても正しく動くでしょうか?

1.      エラーが出て実行できない

2.      エラーは出ないが、目的通りの動作はしない

3.      エラーは出ず、目的通りの動作をする

あなたの予想は               

 

【練習問題】

予想 EditTempVisible プロパティを False にしても正しく動くでしょうか?

1.      エラーが出て実行できない

2.      エラーは出ないが、目的通りの動作はしない

3.      エラーは出ず、目的通りの動作をする

あなたの予想は               


3-8 変数 (2) ―宣言して使う変数―

Visible Falseにすると、EditTempは画面から消えてしまうので、Height Width, Colorなどのプロパティにはどんな値を入れても意味がないですね。入れ替えに必要なのは、Textプロパティだけなのです。中継用エディットを使わない、もっとよい方法はないのでしょうか。

 

ここで、新しい方法を試してみます。まずは、EditTempを削除してください。EditTempを削除したので、EditTempを中継欄に使うことはできなくなりました。そこで、今消した EditTempのかわりにもっと単純な中継欄を作ります。次のように下線部を付け加えてください。

 

void __fastcall TForm1::ButtonSwapClick(TObject *Sender);

{

AnsiString Temp;

EditTemp->Text = Edit1->Text;

Edit1->Text = Edit2->Text;

Edit2->Text = EditTemp->Text;

}

 

EditTempはなくなりましたが、これで Tempという入れ物ができ、Temp EditTemp.Textのかわりをします。EditTemp.Text AnsiString型だったので、そのかわりとなる Temp AnsiString型でなくてはなりません。そのため「AnsiString  Temp;」と書きます。(もし int型が必要なら「int  Temp;」と書きます。) このように、プログラム中で用いる変数の変数名およびその型を指定することを、「変数の宣言」と呼びます。

これで第一段階の準備はできましたが、まだ完成ではありません。次の基礎課題に進みましょう。

 

【基礎課題 3-8-1】

Tempを使って(EditTemp->Textを使わないで)プログラムを完成させるには、どのように変更するといいでしょうか。下の空欄を埋めてプログラムを完成させて下さい。

void __fastcall TForm1::ButtonSwapClick(TObject *Sender);

{

AnsiString Temp;

              = Edit1->Text;

Edit1->Text = Edit2->Text;

Edit2->Text =               ;

}

 

Tempのように値を保存しておく入れ物を「変数」といいます。(入れ物への)代入によって、その値が様々に変わるからです。今の場合 Temp は画面に現れない「エディットコンポーネントのTextプロパティ」と考えて結構です。変数の名前は Tempでなくとも自由につけても構いませんが、なるべく一目見て内容がわかる名前をつけましょう。

 

 

コラム

 

変数の名前は原則として自由につけて構わないのですが、いくつか例外があります。

  • 英数字 (および「_) だけで作られる名前でなくてはいけない。漢字や記号・空白を含む名前はいけない。
  • 数字で始まる名前はいけない。
  • if」や「begin」など、特別な意味を持つ名前 (予約語と呼ばれます) を使ってはいけない。

Temp」という変数を用いることは、プログラムにとって必要充分な機能を提供することになります。余計なものを使わずにこうして必要充分なものを用いるようにすると、プログラムが速くなり、プログラムサイズが小さくなります。

テキスト ボックス: コラム
C++Builderでは、次のように「変数の宣言」と、「変数の初期化(初期値の代入)」を同時に行うことができます。
void __fastcall TForm1::ButtonSwapClick(TObject *Sender);
{
AnsiString Temp = Edit1->Text;
Edit1->Text = Edit2->Text;
Edit2->Text = Temp;
}
一般に、プログラムの書き方としては、変数の宣言と、初期値の代入は別々に行うほうが良いとされています。しかし、C++言語のプログラミングでは、効率を重視して上のように同時に行うことの方が多いようです。
 

 

 

 



【基礎課題 3-8-2】

今度はスピンエディットの入れ替えプログラムを作ってみましょう。

左のようなフォームを作ってください。

フォームができたらプログラムを書いてください。

出来上がったら、適当な数値を入れて実行してみましょう。

基礎課題 3-8-3

【基礎課題 3-5-1】で作ったプログラム

からスピンエディットおよび、ラベルも削除して下さい。

そして、変数を用いるプログラムに修正します。下線部を埋めてプログラムを完成させて下さい。

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

          a;  //変数の宣言

          b;

          c;

        = StrToInt(Edit1->Text);

        = StrToInt(Edit2->Text);

        =        +       ;

  EditResult->Text = IntToStr(    );

}

 

今までどおり「足し算プログラム」として動くことを確認しましょう。

 

 

 

なお、変数の宣言では、

int  a;

int  b;

int  c;

 

をまとめて

int a, b, c;

AnsiString a;

AnsiString b;

AnsiString c;

 

をまとめて

AnsiString  a, b, c:

と、複数の変数をひとまとめにして宣言することができます。

 

コラム

 

「でも、【基礎課題3-5-3】で作ったプログラムとここで作ったプログラムと、どちらも同じく動作するけど、どちらがいいの?」という疑問を持った人がいるかもしれませんね。どちらも同じく動作するから、どちらでもいいのです。

「だけど、実行したときの速さは違うんじゃない? 【基礎課題3-5-3】で作ったプログラムの方が、命令が1行ですっきりしているから速いと思います。」なかなか鋭い質問ですね。ですが、実行する速さも同じなのです。

実は Delphi は、【基礎課題3-5-3】で作ったプログラムもここで作ったプログラムも本質的に同じものであることを理解しています。その意味で、両者は同等なプログラムなのです。

しかし、後からプログラムを見たときには、一つの式に一度にまとめて記述するよりも、こちらの様に変数を用いた方が分かりやすいということは言えます。一般に、インプットデータや、計算の答など、何らかの意味を持つ値については、いったん、変数を定義してそこに代入しておいた方が分かりやすく、また後に拡張等を行う際にもより容易になる傾向があります。

 


3-9 実数型変数

【練習問題】

【基礎課題 3-8-3】を再利用して、

というように2つの数を入れて「平均」ボタンを押すと

平均値が求まる、というプログラムを作ります。ボタンの表示は「平均」に変更しておいてください。

次に、イベントハンドラを変更します。2つの数の平均は、合計を2で割って求めるのですね。プログラムを次のように書き換えてください。(書き換える部分は下線部です。)

 

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

   int a,b,c;  //変数宣言を一度に行っています。

   a  = StrToInt(Edit1->Text);

   b  = StrToInt(Edit2->Text);

   c  =  (a + b)/2;

   EditResult->Text = IntToStr(c);

}

実行してみましょう。結果は次のようになるはずです。

答えの小数点以下が切り捨てられていますね。これは、平均を代入する変数cint型(整数型)であることが原因です。整数には、少数点以下が代入されず、切り捨てられてしまうのです。そこで、「実数型」の変数が必要になります。次の基礎課題に進みましょう。

【基礎課題 3-9-1

c を整数型の変数ではなく小数を受け付ける型の変数にしてしまいましょう。小数を受け付ける型は実数型と呼ばれ、「double」と表します。プログラムを以下のように修正してください。

void __fastcall TForm1::ButtonAddClick(TObject *Sender);

{

   int a,b;  //変数宣言を一度に行っています。

   double c;

   a  = StrToInt(Edit1->Text);

   b  = StrToInt(Edit2->Text);

   c  =  (a + b)/2.0;

   EditResult->Text = FloatToStr(c);

}

なお、FloatToStr() とは、実数型から文字列型への変換を行う命令です。

実行してみましょう。今度はきちんと少数点以下も表示されるはずです。

テキスト ボックス: コラム 分母を2.0にしたのはなぜ?

平均cを求めるところでなぜ分母を「2」ではなく、「2.0」に変更したのか、不思議に思うかもしれません。実は、「c  =  (a + b)/2」のままでは、たとえ、変数cを実数型にしても小数点以下は表示されないのです(各自試してみてください)。
というのは、C++Builderでは「整数/整数」の演算結果は整数にする、という規則があるからです。今の場合、a、bおよび2が全て整数であるため、このような問題が起こります。これを避けるためには、分母か分子の(少なくとも)どちらか一方を実数にする必要があります。そこで、分母の整数「2」を実数「2.0」に変更した訳です。
 

 

 

 

 

 

 

 

 


型変換の命令は、次のものがあります。必要になったらこのページを参照してください。

整数型から文字列型へ

IntToStr()

文字列型から整数型へ

StrToInt()

実数型から文字列型へ

FloatToStr() 又は
FloatToStrF() (小数点以下の表示桁数を調整する場合)

文字列型から実数型へ

StrToFloat()

整数型から実数型へ

命令がなくても自動的に変換される

実数型から整数型へ

Ceil(), Floor(),  Trunc()
(状況に応じて使い分ける。詳しくはヘルプを見ること。)

※実数を整数型変数に代入すると少数点以下切り捨て

 以上の「変換命令」使用法の詳細については、Delphiの「ヘルプ」メニュを参照して下さい。

<様々な演算子>

以下にC++で通常よく用いられる演算子をまとめておきます。

T.算術演算子

演算

加算

減算

乗算

除算

剰余

表記

※除算の場合、分母、分子が共に整数であれば答は整数(少数点以下切り捨て)、それ以外は実数。

※剰余(余り)計算の演算結果(の例)は次の通り。

11 % 3 2    11 % 4 3

U.代入演算子

 プログラムを記述する場合は、「a = a + b」のようなタイプの式がよく出てきます。この入力の手間を省くため、以下の代入演算子が用意されています。

 

演算子

使用例

式の意味

+=

a += b

a = a + b

-=

a -= b

a = a – b

*=

a *= b

a = a * b

/=

a /= b

a = a / b

%=

a %/ b

a = a % b

※ 「a += b」などの場合、「a +  = b」のように、二つの演算子の間に空白を空けてはいけません。

V.変数の値を一つ増やす、あるいは一つ減らす演算子

演算子

使用例

式の意味

++

a++ あるいは ++a

a = a + 1

--

a-- あるいは --a

a = a - 1

     C++言語は、C言語にオブジェクト指向プログラミングの要素が加わった言語ですが、「++」の意味は、C言語から一つ加わった、つまり一歩進んだ言語という意味合いで名付けられたようです。

 

★ UやVは入力の手間を省くために用意された演算子であり、これを知らなくてもプログラミングはできます。しかし、C++言語では、本来の書式よりも、UやVのような省略した演算子が好んで用いられる傾向があります。

【基礎課題 3-9-2

3つの数の平均を求めるプログラムを作ってください。

 

 

【基礎課題 3-9-3

下のようなフォームをもつ、分数を小数にするプログラムを作ってください。

注意


3-10 定数 (1) ―整数型定数―

 

【基礎課題 3-10-1】

今は午後3時だとします。

「換算」ボタンを押したら

午後の時刻の12時間表記から24時間表記を求める、というプログラムを作ってみましょう。

下の下線部には何と書いたらいいでしょうか。

void __fastcall TForm1::ButtonKansanClick(TObject *Sender);

{

   CSpinEditResult->Value = CSpinEdit1->Value +         ;

}

 

※ コンポーネントのNameプロパティを次のようにしています。

上のスピンディット

CSpinEdit1

下のスピンエディット

CSpinEditResult

ボタン

ButtonKansan

 

【基礎課題 3-10-2】

上のプログラムに手を加え、下2桁の西暦略記から4桁の西暦表記を求めるプログラムを作ってください。ただし、西暦2000年以降とします。

 

 

12や2000のように、いつも決まった値であるものを「定数」といいます。この定数とは対照的に、変数は、代入によってその内容(値)が変わります。


3-11 定数 (2) ―文字列型定数―

左上の欄に女性の名前を入れてボタンを押すと

頭に「Miss」とつけるプログラムを作ります。

     実はMissやMr.などの呼称は名字(姓)につけるもので、名前にこれをつけるのは英語としては不自然なのですが、ここでは気にしないでください。

 

まずはフォームにコンポーネントを配置してください。

コンポーネント

Name

左上のエディット

Edit1

左下のエディット

Edit2

右のボタン

ButtonMiss

 

【練習問題】

あとは「敬称付け」ボタンのイベントハンドラを書くだけです。下線部には何が入ると思いますか?

void __fastcall TForm1::ButtonMissClick(TObject *Sender);

{

   Edit2->Text =                  + Edit1->Text;

}

 

実行してみましょう。

次ページへ


下線部に単に「Miss」と入れて実行すると、「未定義のシンボル Miss」というエラーが出て止まってしまったと思います。これは、「Miss っていうのは変数 (か何か) のつもりだろうけど、どこにも用意されていないよ」という意味のエラーです。

Miss は変数じゃない、単なる文字列 (定数) なんだ」ということを C++Builder に伝えるには、「”Miss”」と書きます。つまり」で囲みます

【練習問題】

プログラムを次のように修正して実行してみましょう。

void __fastcall TForm1::ButtonMissClick(TObject *Sender);

{

   Edit2->Text =  "Miss" + Edit1->Text;

}

 

 

【基礎課題 3-11-1】

次のように「さん」づけするプログラムを作りましょう。

 

 

【基礎課題 3-11-2

ボタンを押すと「Hello, C++Builder.」と表示するプログラムを作ってください。

 

【応用課題 3-11-A】

次のように来年が何年か教えてくれるプログラムを作りましょう。

今年の年を入力した画面

来年の年が表示された画面

 


3-12 変数と定数 (1) ―「スピンエディット」を作ろう―

【基礎課題 3-12-1】

「▲」ボタンを押すと

「エディット」の中身が1つ増える、という「スピンエディット」のようなプログラムを「エディット」と「ボタン」だけで作ってみましょう。

コンポーネント

Name

左のエディット

Edit1

右のボタン

ButtonInc

まずはフォームにコンポーネントを配置しましょう。

Edit1 はそのままでは数値の計算ができないので、整数型変数 a を用意し、

(1)      Edit1 から a に値を代入

(2)      a の値を1増やす

(3)      a から Edit1 に値を代入

の順に処理するようにしましょう。下線部を埋めてプログラムを完成させて下さい。

void __fastcall TForm1::ButtonIncClick(TObject *Sender);

{

        a;  // 変数aの宣言

  a = StrToInt(Edit1->Text);

  a =               ;

  Edit1->Text =  IntToStr(a);

}

実行してみましょう。

※ このプログラムがすんなりできたら大したもの!あなたは「代入」の意味をよく理解していることになります。

 

【基礎課題 3-12-2】

上のプログラムを、値が1ずつ増えるのではなく、2ずつ増えるように変更しましょう。


3-13 変数と定数 (2) ―「メモ」を使ってみよう―

メモと呼ばれるコンポーネントを使ってみましょう。メモはを使ってフォームに配置することが出来ます。

下のようなフォームのプログラムを作ってください。

【練習問題】

オブジェクトインスペクタで Memo1 を選んで ScrollBarsssNone から ssBoth に変えると、プログラムはどのように変わりますか?

                                                        

WordWrap プロパティを False にすると、何が変わりますか? (ヒント:実行中にメモに大量の文章を入力すると違いが分かります。)

                                                         

 

【基礎課題 3-13-1】

Lines プロパティの値を変えて、プログラムを実行したとき、メモに

虹と雪のバラード
晴れたらいいね
白い恋人達

と表示されるようにしましょう。


【練習問題】

下のように、左のメモに情報が入っている状態で、「何行目」を指定して「取り出す」ボタンを押すと

 

その内容が右下のエディットに取り出される、というプログラムを作ってみましょう。

まずは、フォームの上に次のようにコンポーネントを配置します。

コンポーネント

Name

左のメモ

MemoMain

右上のスピンエディット

CSpinEditGet

右のボタン

ButtonGet

右下のエディット

EditEachLine

 

次に、プログラムを書きます。MemoMain の各行は、

MemoMain->Lines->Strings[行番号]

という形でアクセスすることができます。次のプログラムを作成して下さい。

 

void __fastcall TForm1::ButtonGetClick(TObject *Sender);

{

  EditEachLine->Text =

    MemoMain->Lines->Strings[CSpinEditGet->Value];

}


注意 メモの各行は、最初が0行目、次が1行目、その次が2行目、というように順序がつけられています(0行目から始まっています)。

 

【基礎課題 3-13-2

 

上の【練習問題】を改良しましょう。下の状態で「送り込む」ボタン(NameプロパティをButtonPutとします)を押すと

 

指定された場所に情報を送り込む(内容が更新される)、というプログラムを作って下さい。

 

ここに、新たに付加したスピンエディットとボタンのNameプロパティは次に様にしてください。

 

 [送り込む]ボタン     : ButtonPut

 2行目のスピンエディット : CSpinEditPut

 

3行目に「北の国から」、4行目に「ロマンスの神様」を送り込んでみてください。プログラムはどのように動作しましたか?

 

・・・

 

4行目以降には情報が入らないですね。 → コラム参照

 


 

 

 

 


コラム

 

このプログラムで、7行目や10行目など、4行目以降に情報を送り込もうとしても、うまく行きません。これは、現在存在していない行へのアクセスをメモが許してないからなのです。

「では、100行の情報を書き込むためには、各行にアクセスできるよう、メモにあらかじめ100行の無駄なデータを書き込んでおかなくてはならないのか?」 という疑問ももっともです。

実は、Memo には Add() という、行を付け足す命令があります。プログラムを次のように変更すると、ボタンを押すたびに行が増えていきます。

void __fastcall TForm1::ButtonPutClick(TObject *Sender)
{
    MemoMain->Lines->Add(EditEachLine->Text);
}

 


3-14 配列変数

フォームにメモを置くだけで MemoMain->Lines->Strings[0], MemoMain->Lines->Strings[1], MemoMain->Lines->Strings[2], …が利用できるようになったように、普通の変数も1行の宣言だけでいくつもの入れ物を用意することができます。

 

【基礎課題 3-14-1】

【基礎課題 3-13-2】からメモを削除し、その代わりとなる変数を使って同じプログラムを作りましょう。

MemoMain->Lines->Strings[0]MemoMain->Lines->Strings[1]・・・の代わりに、Data[0]Data[1]、・・・という新しい変数を導入することにします。変数名Dataは適当に付けた変数名です。

まずは、【基礎課題 3-13-2】のプログラムから MemoMainを削除し、代わりにヘッダファイル (どこでもいいからプログラムコードの上で右クリックし、「ソース/ヘッダー ファイルを開く」を選ぶと出現する)に次の下線部を挿入してください。

 


#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "CSPIN.h"
#include <vector>
using namespace std;
//------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE 管理のコンポーネント
       TCSpinEdit *SpinEditGet;
       TLabel *Label1;
       TButton *ButtonGet;
       TEdit *EditEachLine;
       TCSpinEdit *SpinEditPut;
       TLabel *Label2;
       TButton *ButtonPut;
       void __fastcall ButtonGetClick(TObject *Sender);
       void __fastcall ButtonPutClick(TObject *Sender);
private: // ユーザー宣言
public: // ユーザー宣言
       __fastcall TForm1(TComponent* Owner);
       vector<AnsiString> Data;
};
 
 

これで、Data[0], Data[1], Data[2], …というように、いくつもの文字列型変数を使う準備 (の第1段階) が出来ました。このときの 0, 1, 2, … を添え字といいます。そして、このように添え字がつく変数を配列変数と呼びます。

 

     ここで、「vector」という初めて耳にする用語が出てきましたが、ここでは、配列を宣言する際に使うものだ、という様に理解しておいてください。

     using namespace std;」を記述することによって、本来

std::vector<AnsiString> Data;

と書くべきところを、

vector<AnsiString> Data;

と、略することができます。これは、「vector」がstd名前空間(namespace)に属しているからなのですが、もう少し詳しく説明するためにはいくつかの前提知識が必要になります。とりあえずここでは、現在のC++言語では、通常using namespace std;」を用いる、と理解しておいてください。

 

テキスト ボックス: コラム ヘッダーとは?

「ヘッダー」とはプログラムを動作させるために必要な命令(機能)群のことです。例えば、C++Builderのプログラム開始時にはコードエディタの先頭部分が次のようになっています。

 
 
ここにある「vcl.h」や「Unit.h」がヘッダーファイルと呼ばれるものです。「vcl.h」にはボタンやエディットなどのビジュアルコンポーネントに関する命令群が登録されており、それを「include(「取り込む」という意味)」することによって、コンポーネントの使用が可能になります。一方、「Unit.h」には、このプログラムでフォーム上に貼り付けられたコンポーネントおよび、それらのイベントハンドラ名のリストが登録されています(5-6節参照)。
このようにC++では、プログラムに必要な命令群をヘッダファイルとして用意しておき、それらをプログラミングの際に活用する(includeで取り込む)という形でプログラミングを行います。
 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


さて、ところで、…, Data[100], Data[101], Data[102], と続いていって、添え字はどこまで使えるようになっているのでしょうか (メモリをどれだけ準備しているでしょうか)?

実は、「配列 (の要素) が実際に何個必要か」は、プログラムの中で指示してやる必要があります。フォームに次のようにボタン (NameプロパティをButtonSetSizeとします) を配置し、そのイベントハンドラに次のように書いて下さい。

 
void__fastcall TForm1::ButtonSetSizeClick(TObject *Sender)
{
    Data.resize(100); 
}

 

これで、100個の変数 Data[0], Data[1], Data[2], , Data[99]が用意されました。もし変数の数が100個で足りなくなった場合も、同じ命令で変数の数を増減させることが出来ます。

では、プログラム本体部分を変更して、メモがないこのプログラムが正しく動くようにしましょう。空欄部分は自分で埋めて下さい。

 

void__fastcall TForm1::ButtonGetClick(TObject *Sender)
{
    EditEachLine->Text = Data[CSpinEditGet->Value];
}
//------------------------------------------------------------
void__fastcall TForm1::ButtonPutClick(TObject *Sender)
{
                             = EditEachLine->Text;
}

 

 

では、実行して動作を確認してみましょう。

最初に「100個用意」ボタンを押して下さい。これで100個の変数が使えるようになります。(押し忘れると、1個の変数も使えるようにならないため、エラーが発生します。)

 

1.        「睦月」という文字列を「0」行目へ「送り込む」。

2.        「如月」という文字列を「1」行目へ「送り込む」。

3.        0」行目から文字列を「取り出す」と「睦月」と表示される。

4.        「むつき」という文字列を「0」行目へ「送り込む」。

5.        1」行目から文字列を「取り出す」と「如月」と表示される。

6.        0」行目から文字列を「取り出す」と「むつき」と表示される。

 

正しく動きましたか? 


テキスト ボックス: コラム 動的配列変数と静的配列変数
配列変数を宣言する際に、

vector<AnsiString> Data;

ではなく

AnsiString Data[100];

と書くことがあります。これは静的配列変数と呼ばれ、この1行だけで Data[0]〜Data[99] が利用可能になりますが、一度用意した変数の個数を後から変更することは出来ません。一方、先ほどの配列変数は、プログラム実行中でも変数の個数を変更することが出来るため、動的配列変数と呼ばれます。

静的配列変数では、「最大で100個の変数が必要になりそうだ」と思ったら最初から100個用意 (宣言) しなくてはいけないため非効率なプログラムになりやすく、万一プログラム実行中に101個以上の変数が必要になっても打つ手がありません。動的配列変数であれば、その時に必要な個数分だけ変数を用意することが出来、効率的です(ただし、動的配列変数は動作が遅くなることがあります。)。