1. ホーム
  2. C++

C++ ダイナミックオープンスペース

2022-02-14 03:03:48

<スパン C++のダイナミックオープンスペースです。

<スパン 1. 可変長一次元配列 


ここでいう可変長配列とは、コンパイル時に配列の長さを決定できず、プログラムが実行時に動的にメモリ空間を確保する必要がある配列のことです。可変長配列の最も単純な実装は可変長一次元配列で、次のようにします。 
//ファイル名:array01.cpp 
#include<iostream> 
名前空間std.を使用する 
int main() 

int lenです。 
cin>>len; 
// ポインタ p を使って、長さ len*sizeof(int) の新しい動的割り当てメモリ空間を指定します。 
int *p=new int[len]; 
<スパン ........... 
delete[] p; 
は 0 を返します。 

int *p=new int[len]; という行に注意してください、このようなことはできません。 
int p[len]; 
C++コンパイラは、この形式で配列を宣言する場合、コンパイル時に配列のサイズを決定する必要があるため、lenのサイズが決定できないというエラーを報告します。そして、このように動作しないのです。 
int p[]=new int[len]; 
コンパイラは、int* 型を int[] 型に変換することはできない、なぜならメモリのセクションを new で開くとそのメモリのセクションの最初のアドレスが返されるので、そのアドレスをポインタに代入しなければならない、だから int *p=new int[len] としなければならない、と言うでしょう。 
array01.cppは可変長の一次元配列を実装していますが、ポインタpを書き落とすことに注意して、newで開放されたメモリ空間をプログラムが解放するように習慣付けるとよいでしょう。 
もちろん可変長配列は、C++標準テンプレートライブラリ(STL)のベクトルを使って実装することも可能です。 
//ファイル名:array02.cpp 
#include<iostream> 
#include<vector> 
名前空間std.を使用する 
int main() 

int lenです。 
cin>>len; 
vector<int> array(len);// 長さ可変の配列を宣言する。 
for(int i=0;i<len;i++) 

array[i]=i; 
cout<<array[i]<<"\t"; 

は 0 を返します。 

ここでいう可変長配列は、javaのjava.utilパッケージのvectorやC#のArrayListを連想させますが、これらの言語でも可変長配列を実装することが可能です。ただし、C++のベクターには、C#のように占有したメモリ空間を回収するマネージドガベージコレクション機構はありませんが、ベクターを使い終わったら、~vector() デストラクタを呼び出してメモリを解放することが可能です。 

<スパン 2. 可変長n次元配列 
可変長n次元配列は実装が少し難しいですが、工学やソフトウェア設計の用途でよく使われるので、ここでは可変長2次元配列を中心に説明しますが、可変長n次元配列も同様の方法で実装することが可能です。まず、C言語で可変長2次元配列を実装する古典的な例から見ていきましょう。 
//ファイル名:array03.c 
#include <stdio.h> 
#include <malloc.h> 
void main() 

int x,y,i,j; 
float **a,*b; 
printf("解こうとしている連立一次方程式の行数xを入力してください。x=")です。 
scanf("%d",&x); 
printf("Please enter column number y of the system of linear equations you are solving: y=")。 
scanf("%d",&y); 
a=(float **)malloc(sizeof(float *) *x); 
b=(float *)malloc(sizeof(float) *x); 
for(i=0;i<x;i++) 

*(a+i)=(float *)malloc(sizeof(float) *y)。 

/*データ読込*/ 
printf("係数の値を行の順番に入力してください(%d項目): ",x*y)。 
for(i=0;i<=x-1;i++) 
for(j=0;j<=y-1;j++) 
scanf("%f",&a[i][j]); 
printf("定数の値を列順に入力してください(全部で%d項目): ",x)。 
for(j=0;j<=x-1;j++) 
scanf("%f",&b[j]); 
printf("The augmented matrix of your input system of equations is: \n"); 
for(i=0;i<=x-1;i++) 

for(j=0;j<=y-1;j++) 
printf("%.5f ",a[i][j])を実行します。 
printf("%.5f ",b[i])を実行します。 
printf("\n"); 

free(b)です。 
for(i=0;i<x;i++) 
free (*(a+i)); 

<スパン では、C++で実装するにはどうすればよいのでしょうか。C++では、newとdeleteという演算子で動的に領域を開放・解放することができます。newはC言語のmalloc関数、deleteはC言語のfree関数に似ています。C++で可変長の2次元配列を実装するには、ダブルポインタ方式とSTLのベクタ(ベクトル)方式の2つの方法があります。 
まず、ダブルポインタ方式を紹介します。ダブルポインタとは、ポインタのように見えるポインタのことで、例えば、次のような配列を宣言します。 
int **p = new int*[num1]; 
そして、各 *p (合計 num1 *p) に対して、1組のメモリ空間が要求されます。 
for(int i=0; i<num1; ++i) 
p[i] = new int[num2]; 
ここで、num1 は配列の行数、num2 は配列の列数です。このテストのソースプログラムは次のとおりです。 
//ファイル名:array04.cpp 
#include <iostream> 
#include <iomanip> 
名前空間std.を使用する 
int main() 

int num1,//行数 
num2;//列の数 
cout<<"Please enter number for row and column: "<<endl.を入力してください。 
cin >> num1 >> num2; 
// 2次元配列のためのオープンスペース 
int **p = new int*[num1]; 
for(int i=0; i<num1; ++i) 
p[i] = new int[num2]; 
for(int j=0;j<num1;j++) 

for(int k=0;k<num2;k++) 

p[j][k]=(j+1)*(k+1) となります。 
cout<<setw(6)<<p[j][k]<<':'<<setw(8)<<&p[j][k]; 

cout<<endl; 

//2次元配列が占有する空間を解放する。 
for(int m=0;m<num1;m++) 
delete[] p[m]; 
delete[] p; 
は 0 を返します。 

<スパン 以下は、その実行結果である。 
<スパン 行と列の番号を入力してください。 
<スパン 4 5 
1:004915f0 2:004915f4 3:004915f8 4:004915fc 5:00491600 
2:00491180 4:00491184 6:00491188 8:0049118C 10:00491190 
3:00491140 6:00491144 9:00491148 12:0049114C 15:00491150 
4:00491100 8:00491104 12:00491108 16:0049110C 20:00491110 
<スパン 任意のキーを押して続行 
プログラムリストarray04.cppには、割り当てられたメモリ空間ユニットのアドレスが表示されています。このように,配列は動的に確保されるため,異なる行の配列要素のアドレスは異なるnewで確保されるため,配列行間のアドレス空間は不連続となります.また、各行の列間のアドレス空間は連続しています。 
では、ベクトルを使った2次元配列はどのように実装するのでしょうか。以下にそのソースプログラムを示します。 
//ファイル名:array05.cpp 
#include <iostream> 
#include <vector> 
#include <iomanip> 
名前空間std.を使って 
int main() 

int i, 
j, 
m, //行数 
n; //列の数 
cout << "m,nの入力値:"。 
cin>>m>>n; 
//次の行に注意してください: vector<int の後に、2つの ">" の間にスペースがあること! さもないと、">"のオーバーロードとみなされます。 
vector<vector<int> > vecInt(m, vector<int>(n)); 
for (i = 0; i < m; i++) 
for (j = 0; j < n; j++) 
vecInt[i][j] = i*j; 
for (i = 0; i < m; i++) 

for (j = 0; j < n; j++) 
cout<<setw(5)<<vecInt[i][j]<<":"<<setw(9)<<&vecInt[i][j]; 
cout<<endl; 

は 0 を返します。 

<スパン 以下は、その実行結果である。 
m,n の入力値:3 4 
0: 00491180 0: 00491184 0: 00491188 0: 0049118C 
0: 00491140 1: 00491144 2: 00491148 3: 0049114C 
0: 00491100 2: 00491104 4: 00491108 6: 0049110C 
<スパン 任意のキーを押して続行 
このように、vectorの要素に対するメモリの割り当ては、ダブルポインタで実装された2次元配列と同じ性質を持っていることがわかります。しかし、ダブルポインタを使うよりもベクトルの方がはるかに単純で、メモリ領域を確保する際の安全性が高く、配列の初期化コードも単純なので、STLベクトルを使って可変長多次元配列を実装することをお勧めします。(以下は可変長の3次元配列です) 
//ファイル名:array06.cpp 
#include <iostream> 
#include <vector> 
#include <iomanip> 
名前空間std.を使用する 
int main() 

int i, 
j, 
k, 
m, //一次元の座標 
n, //2次元座標 
l; //三次元座標 
cout << "入力値 for m,n,l:"; 
CIN>>M>>N>>L. 
vector<vector<int> > vecInt(m, vector<vector<int> >(n, vector<int>(l))) を使用します。 
for (i = 0; i < m; i++) 
for (j = 0; j < n; j++) 
for (k = 0; k < l; k++) 
vecInt[i][j][k] = i+j+k; 

for (i = 0; i < m; i++) 

for (j = 0; j < n; j++) 

for(k = 0; k<l; k++) 
cout<<setw(5)<<vecInt[i][j][k]<":"<<setw(9)<&vecInt[i][j][k] です。 
cout<<endl; 

cout<<endl; 

は 0 を返します。 

<スパン 走った結果 
m,n,l の入力値:2 3 4 
0: 00492fe0 1: 00492fe4 2: 00492fe8 3: 00492fec 
1: 00492fa0 2: 00492fa4 3: 00492fa8 4: 00492fac 
2: 00492f60 3: 00492f64 4: 00492f68 5: 00492f6c 
1: 00492ec0 2: 00492ec4 3: 00492ec8 4: 00492ecc 
2: 00492e80 3: 00492e84 4: 00492e88 5: 00492e8c 

3: 00492e40 4: 00492e44 5: 00492e48 6: 00492e4c 

から取得した。 http://hi.baidu.com/ouyangyuanling/item/dbf618eab47ef7c4baf37d4f