C++Builder入門:変数1

第一章:基礎知識

3.変数1

3.1.変数の宣言

前々回、計算のやり方を学習しました。しかし、あのままでは計算する値があらかじめ決まった数字でしか計算できませんでした。さらに、計算した結果に対してさらに計算したい場合などにも対応できませんでした。そこで、変数という物を利用します。

    int suuji1;
    int sample1,sample2;
    int suuji2=0;

上記の様に宣言します。 型名 スペース 名前 という形式で記述しなければ使えません。
1行目のint suuji1;は、ただ宣言しただけで、これから使いますという意味です。
2行目はsample1とsample2というint型の変数を利用しますという意味です。カンマで区切ることで複数まとめて宣言できます。
3行目は宣言と同時に変数を初期化します。変数は宣言しただけでは格納されている値が不定なので、初期値を与える必要がある場合はこのようにやるか、後で初期値を渡してやる必要があります。

3.2.変数の種類

変数の型には種類があり、C++Builderでは主に以下の物がよく利用されます。
char -キャラクター型
short -ショート型
int -インテジャー型(integer)
float -フロート型
double -ダブル型
String -ストリング型

unsigned char
unsigned int

char型は単一の半角文字を格納することが出来ます。
short型は-32,768~32,767の範囲の整数を扱うことが出来ます。
int型は-2,147,483,648~2,147,483,647の範囲の整数を扱うことが出来ます。
float型は精度の低い小数を扱うことが出来ます。
double型は精度の高い小数を扱うことが出来ます。
String型は文字列を格納出来ます。

unsigned char型は、0~255の整数を格納します。
unsigned int型は、0~4294967295の整数を格納します。
unsignedを付けることで、マイナスに割り当てられていた物をすべてプラスとして扱うことで、範囲の広い整数を扱うことが出来るようになります。

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char a;
    short b;
    int c;
    float d;
    double f;
    String moji;

    a='A';
    b=100+1;
    c=100-100;
    d=100.01-0.1;
    f=100.01/0.0005;
    moji="文字列";
}

変数の名前は好きなように設定できます。しかし、変数の頭に数字や以下の記号をセットすることは出来ません。
+-*/=%\^~@!<>;:&$#`?,.”‘|()[]{}
唯一_アンダーバーは利用できます。
int _a;

char型は、単一の半角文字を格納することが出来ます。格納したい文字は、”シングルクォーテーションで囲む必要があります。
shortとintは、ともに整数を扱う変数で、その有効範囲が違うだけです。一般的にはintの方がよく使われています。
floatとdoubleは、ともに少数を扱う変数で、有効範囲が違うだけです。どのくらいの精度が必要かは用途によりますが、細かいところまでしっかり計算したい場合はdoubleの方が使われます。
String型は文字列を格納します。格納する文字列を”"ダブルクォテーションで囲む必要があります。

3.3.変数を利用した計算

    int a,b,c;
    a=10;
    b=2;
    c=a*b;
    a=a+c;
Caption=a;

変数a,b,cを宣言し、aに10、bに2を代入します。cにaとbを掛けた物を代入しcが20になります。そして、aにaとcを足した物を代入します。aは30になります。a=a+cという数学上あり得ない計算式が出ましたが、プログラミングではa=というのは、ただ、aに=の右の値を代入するという意味しかありませんので、この式は有効です。

補足説明
文字列型変数 String
Captionは何故、数字も文字も扱えるのだろうかと、気がついた人も居るかもしれません。実はCaptionというForm1のメンバーはString型の変数で本来は文字列を扱う物です。しかし、厳密にはString型という型は存在せず、Stringというのは、後述するクラスの一つです。Stringという名前のクラスには、数字を文字に自動的に変換して文字として格納するという機能が備わっています。なので、Caption=100やCaption=”100″という式が成り立ちます。

String a=100;
String b=200;
String c=a+b;
Caption = c;

この式を実行しても計算は行われず、表示される値は100200という文字列になります。文字列を連結するのに+を利用します。文字列から文字列を削除するという意味で、a-bという使い方は出来ません。Stringでは連結時のみ+を利用できるだけで、そのほかの算術演算記号を用いて文字列を削除したり、同じ文字を*の数だけ増やしたりはできません。

しかし、実は次のような式が成立してしまいます。

String a=100;
String b=200;
String c=a-b;
Caption = c;

結果は-100として表示されます。+は文字の連結なのに、その他の算術記号ではしっかり計算をしています。これは文字列を数字に自動的に変換して計算を試みるという機能が備わっているためで、+以外の演算記号で計算できてしまいます。

String a=100;
int x=2;
Caption=a+x;

この場合、結果は1002となります。+ なので、文字の連結としてxの値が文字列に変換されてCaptionに格納されます。a*xにした場合は、結果は200となります。
ここで、次の式を見てください。

String a=100;
int x=2;
Caption=x+a;

この式はエラーになります。何故かというと、Stringクラスは他の値と計算や連結をしようとするとき、他の値が左にある場合と右にある場合とで動作が異なる場合があるからです。

String a="値:";
int x=2;
Caption=a+(x*10);

この式では、値:20 と表示されます。

紛らわしいので、String型で+は文字の連結ができる。とだけ覚えておくと、バグに悩まずに済むと思います。

3.4.配列変数

同じ変数名で番号をセットする事で複数の変数を用意することが出来ます。
下の例ではaという変数でint型の連続する領域を5つ確保するという意味になります。

int a[5];
a[0]=1;
a[1]=2;
a[2]=3;
a[3]=4;
a[4]=5:

この配列にアクセスする時は2行目に書いてあるようにa[0]から始まります。5つ確保しているので、0~4までの数字でアクセスします。
配列を使うときは型名 スペース 変数名[確保する数]という宣言をして、変数名[配列の番号]という指定で配列にアクセスします。
また、配列を初期化するときは以下のような方法も利用できます。

int a[]={1,2,3,4,5};

{ }とカンマで変数が必要な数だけ初期値を配置します。配置した数だけ変数が確保されます。

補足説明
変数のサイズ
変数にはサイズが設定されています。

char 1byte □
short 2byte □□
int 4byte □□□□
float 4byte □□□□
double 8byte □□□□□□□□
String 不定 可変長変数

上の例では4バイトのint型をメモリ上に5つ確保するという意味なので、たとえば以下のようになります。
メモリーのイメージ(見やすいように8バイトずつで区切りを入れてます)
■■■■■■■ ■■■■■■■■ ■■■■■■■■ ■■■□□□□□ □□□□□□□□ ■■■■□□□ ■■■■□□□□ □□□□□□□□

■int a[5];で確保
使用中
使用中
使用中
□空き領域

黒塗りの部分が確保されたint a[5];の領域です。int型は4バイトなので4*5=20個確保してます。
メモリの領域はプログラムの中で確保したり解放しているので、空いている部分が連続しているとは限りません。配列を宣言することにより、連続した空き領域を確保する事が出来ます。この話は後述するポインタの話に繋がります。

3.5.ポインタ変数

ポインタ変数の説明の前に、どのように宣言するのかを見てみましょう。

int *a;
int b;

1行目の*aがポインタ変数です。2行目の普通の変数と違うところは*(アスタリスク)が付いている事です。この*は、四則演算の掛け算という意味とは全く関係ないので、掛け算のことは忘れて、ただの記号として覚えましょう。
ポインタが格納出来る値は、メモリのアドレスです。
メモリのイメージを示します。
■■■■■■■■ ■■■■■■■■ ■■■■■■■■ □□□□□□□□ □□□□□□□□ □□□□□□□□
たとえばこのようになります。四角の一つ一つに1~48の番号が付いていると考えてください。
メモリは1バイトごとにアドレス(番号)が割り振られています。この番号を覚えるのがポインタ変数の役目です。
では、どうやってアドレスを記録させ、どのように利用するのか以下に示します。

int *a;
int b=100;
a=&b;
Caption=*a;

変数bは普通の変数なのに、頭に&が付いています。これが普通の変数からアドレスを読み込む為の書き方になります。
ポインタ変数aに保存したアドレスのメモリの内容にアクセスする時は*をaの前に付けます。
アドレスを格納するときはaにアスタリスクは付けません。
これで、変数bに格納された値をポインタ変数*aからアクセスできるようになりました。
*aから値をセットするには*a=200;のようにします。これで、bの値が200になります。

補足説明

ポインタ変数が他の変数と違うところは、どの型のポインタ変数もサイズはOSが32bit環境なら4バイト、OSが64bitなら8バイトという事です。
1バイトは8bitで出来ており、32bit環境では最大のメモリアドレスが32bitで表せる必要があるので、32bit/8bit=4バイト必要になると言うことです。
ビットというのは、0か1かで表す2進数の事であり、この集合によって、大きな数字を表現できるようになっています。
32bitの最大値はこのように表現されます。
11111111 11111111 11111111 11111111
10進数にすると4294967295です。大体4GBになります。32bit環境では4GBまでしかメモリが認識できないということです。

3.6.文字列配列変数

次にchar型の配列について説明します。次を見てください。

char c[]="123456789";
Caption=c;

宣言に長さが定義されていませんがエラーはありません。この表記法では初期値の文字列によってcの配列の長さが決定されます。この文字列の長さは10文字です。c[]はc[10]と宣言されたことになります。9文字しかないのに何故10文字かですが、ダブルクォーテーションで囲った文字列には見えない文字NULL文字(\0)があるのです。このNULL文字によって文字列の終わりをコンパイラが検出します。
char型の配列に後から文字列を入れるには、専用の関数(strcpy関数)を用いて書き込みます。char型配列にc=”abc”;という文法は使えません。Stringがいかに便利なクラスに仕上がっているかがよくわかります。
c[0]=’a';
c[1]=’b';
c[2]=’c';
という書き方もあるにはありますが、効率悪すぎですね。

char c[]="1234";
char *p;
p=c;
Caption=p;

char型のポインタも*を付けて宣言できます。c[]=”1234″;はc[5]で宣言されたchar型配列と同じです。p=c;という式によってポインタpに対してc[0]のアドレスが格納されます。配列変数は連続したメモリ領域に確保されると上の補足説明に書きましたが、配列はポインタと同じで、cと書くことによってアドレスが取得されます。
*cを使った方法で値を1文字だけ読み取るときは*(c+1)などとして記入します。cは連続領域の先頭のアドレス(c[0]のアドレス)が格納されています。cの内容(アドレス)は数字なので、+1する事により、アドレスが次の領域を示すことになります。*cとすることで、アドレスから1文字だけ値を読み出す事が出来ます。括弧は計算と同じで優先順位を示す演算子でしかありません。
Caption=c;のようにアドレスを渡してあげることで、StringクラスがNULL文字を認識するまで文字列をすべて読み込んでくれます。

補足説明
char型の配列ではStringクラスのように文字列を + 記号を用いて連結することは出来ません。仮に、”abc”+”ccc”という式を入力したら先頭アドレスに後続の先頭アドレスを足した値という意味になり、メモリ上の全然関係のない場所を指すことになり、エラーになります。
では、エラーにならない範囲で試してみましょう。

String str = "abc"+1;
Caption = str;

表示される文字は、bcになったはずです。イメージとしては、String str=”abc”;とした段階で、abcをメモリ上に展開し、アドレスを割り当てることによって、後続の+1によって先頭アドレスに1を足した次のアドレスを指すことになります。読み込むのはbからNULLを認識するまでという意味なので、bcになります。
ただし、注意する必要があります。

char *c="abc";
Caption = c;

このサンプルは正常に動きますが、きちんと意味をわかっていないと大きな間違いをしてしまいます。
char *c=”abc”;やString str=”abc”+1;の”abc”はメモリ上に新たに展開するのでは無く、コンパイル済みのプログラムをロードする時に展開されるリテラル文字列というもので、このリテラル文字列はメモリ上の書き込み禁止位置(後から書き換えることが許されない位置)にロードされます。このロードされたメモリはプログラムを終了するまで解放されません。
char *c=”abc”;というダブルクォーテーションの表記があった場合は、コンパイル時に定数として実行ファイルに保存されます。
“abc”という文字列をchar *cに渡すとき、*cは1バイト分のアドレスを受けるだけなのに文字列が渡せるというということは、”abc”はabcという文字列のアドレスということです。アドレスとして格納されるのはaの位置のアドレスで、Stringクラスで読み込むときはNULL文字まで読み込まれます。
char *c=”abc”;
char a[]=”abc”;
の決定的な違いは、*cの方はリテラル文字”abc”のaのアドレスを取得するだけですが、a[]の方はメモリ上の書き込み可能な位置に”abc”を展開するということです。
char a[]=”abc”は
char a[]={‘a’,'b’,'c’,'\0′}としたことと同じ意味です。
配列に個別に値を格納し、アドレスを割り当てているので、a[]=c;としただけでは、アドレスが一つしか読み込まれない上、アドレスのどこまでを読み込んだらいいのかアドレスからは認識できないのでエラーになります。エラーメッセージとしては char*型はchar[]型に変換できないと表示されます。

※書き込み禁止位置に書かれているはずなのに私の環境では、*c=’Z';などと記入することで書き換えることが出来てしまいました。本来は書き換えようとすると強制終了されたりするらしいので、このリテラル文字列の値は絶対に書き換えないでください。

カテゴリー: C++Builder, C++Builder入門   パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>