第14講 フリーストア配列とCLI配列
第1話 配列の種類

C言語は長い歴史を持ちます。Cから始まり、C++そしてVisual C++と変貌し拡張してきました。
したがって、配列と同様の働きをもつものも拡張を続けてきて、かなり複雑な様相を呈しています。

ここで配列の種類を、私が理解している範囲で整理してみましょう。
T ネイティブ配列
 @ 自動メモリに配置される配列
 A フリーストアに配置される配列
U ポインタ
V ベクタ
W CLI配列

このうち、T@自動メモリに配置される配列とUポインタとVベクタについては既習済みです。
残っているのは、TのAフリーストア配列とWCLI配列です。
本講では、この2つについて学んでいきます。

T@自動メモリに配置される配列とは、
int a[5];
で宣言される配列です。したがって、第7講で学習した配列です。
ネイティブ配列はC言語時からあるもので、C++やVisual C++でももちろん使えるわけです。
C++言語が扱うメモリにはいくつの種類があり、そのうちの2つが自動メモリとフリーストアであると理解してください。
自動メモリの方は、関数の処理が終わったときなど、変数が使っていたメモリを自動的に開放してくれます。
開放するということは、今まで使っていたメモリ領域を他の変数の領域として割り振ることができるということです。
例えば、ある関数f1()が3つの変数をメモリに割り当てていたとすれば、

a b c

f1()の終了と同時にそのメモリーは解放され、例えば、g1()の変数x、yとh1()の変数pに割り当てることができるということです。

x y p

同じメモリが他の変数の領域として再利用されるのです。
つまり、自動メモリの場合変数の生成と消滅が自動的に行われるわけです。

それに対して、フリーストアの場合は、プログラマが意図して消さないと、メモリ領域は開放されず、
割り当てられているメモリがどんどん増えていってしまいます。

a b c x y p

そうすると使用できるメモリ容量がどんどん減っていってしまいます。
使用できるメモリ容量が減少して行く現象をメモリリークといいます。
フリーストアの場合、プログラマーが消すのを忘れるとメモリリークを起こすことになります。
では、自動メモリの方が優れているかというとそうではなく、一長一短があります。
プログラマに手を煩わさない自動メモリは容量が小さいのです。
だから、自動メモリに配置されるネイティブ配列の場合、大きな配列を扱うことができません。
それに、対してフリーストアの場合メモリ容量が大きいので、大きな配列を扱うことができます。
さらに、フリーストアの方が優れている点は、実行時に要素数を決められるという利点があります。
この点については、後ほど具体例で説明いたします。

フリーストアに配置されるネイティブ配列を宣言するには、次の構文を使います。
要素の型* 配列名=new 要素の型[要素数]
フリーストア配列を使った最後には、必ずその配列を削除しなければなりません。
メモリリークを起こすからです。
配列を削除するには
delete[] 配列名;
とします。

具体例を挙げましょう。
int* a=new int[5];
これで要素数5の1次元配列が宣言されています。
この配列の使い方は、T@自動メモリに配置されるネイティブ配列と同じで、
a[0]=5;等と使います。

先に実行時に要素数を決められると説明したのは、次のような例を指しています。
int s=5;
int* a=new int[s];
T@自動メモリに配置されるネイティブ配列の場合は、
int s=5;
int a[s];
としたのでは、エラーします。
T@自動メモリに配置されるネイティブ配列はサイズを最初に決めておかないといけないのに対して、
UA フリーストアに配置される配列の場合は、実行時に要素数を決められるのです。

では実際に、フリーストアに配置される配列(以後フリーストア配列と記述します)をコーティングしてみましょう。
新規にプロジェクトを作成して、フォームとコーティングを下のようにしましょう。

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         int* a=new int[5];
         int i;
         for(i=0;i<5;i++)a[i]=i+1;
         String^ w="";
         for(i=0;i<5;i++)w+=a[i].ToString()+L" ";
         label1->Text=w;
         delete[] a;
      }
(コピーペースト用

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
int* a=new int[5];
int i;
for(i=0;i<5;i++)a[i]=i+1;
String^ w="";
for(i=0;i<5;i++)w+=a[i].ToString()+L" ";
label1->Text=w;
delete[] a;
}




フリーストア配列の場合、必ず関数終了直前にdelete[] a;等で削除しなければなりませんので注意しましょう。

実行結果

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         int* a=new int[5];
         int i;
         for(i=0;i<5;i++)a[i]=i+1;
         String^ w="";
         for(i=0;i<5;i++)w+=a[i].ToString()+L" ";
         label1->Text=w;
         delete[] a;
      }

では皆さん問題です。
今回は、System::Void button1_Clickの中ですべての処理を済ませましたが、
データを作成する部分データを表示させる部分
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         int* a=new int[5];
         
int i;
         for(i=0;i<5;i++)a[i]=i+1;

         
String^ w="";
         for(i=0;i<5;i++)w+=a[i].ToString()+L" ";
         label1->Text=w;

      }
を関数として独立させ、
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         int* a=new int[5];
         
f(a);
        
g(a);
         delete[] a;
      }
として、同じ実行結果になるようにコーティングしてください。
f(a)g(a)はvoid型です。

第11講第6話へ
 第12講第1話へ 第13講第10話へ 第14講第2話へ 

vc++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ