まず第一に、anint**
は。と同じではありませんint[][]
。を動的割り当ての2D配列として使用している場合int**
、内部構造は実際には実際の2D配列とは大きく異なります。このコードを見てください:
int** dynamic2DArray;
int static2DArray[10][10];
dynamic2DArray = new int*[10];
for( int i=0; i<10; i++ )
dynamic2DArray[i] = new int[10];
ここで、dynamic2DArray
10個のポインターのリストの最初の要素を指します。各ポインターは10int
秒のリストをstatic2DArray
指し、10 * 10=100int
秒のリストの最初の要素を指します。したがって、メモリ内の構造は完全に異なります。
さらに、以下も、int**
明らかに配列とは関係ありませんが、です。
int someInt;
int* pointerToSomeInt = &someInt;
int** doublePointerToSomeInt = &pointerToSomeInt;
私が見つけた構文エラーは、配列のタイプを宣言していないことです。
array_can_choose[9][2]={0};
board[3][3]={{' ',' ','x'},{' ','o',' '},{'x',' ',' '}};
する必要があります:
int array_can_choose[9][2]={0};
char board[3][3]={{' ',' ','x'},{' ','o',' '},{'x',' ',' '}};
これは、配列が必要であることをコンパイラに通知する必要があるだけでなく、配列が何であるかを指定する必要があるためです。この場合、int
およびchar
。
コードのもう1つの問題は、ローカル配列を返そうとしていることです。あなたはこれを行うことはできません。ローカル変数は、「その名前がわかっている」場合にのみ存在します(これは「スコープ内にある」と呼ばれます)。この場合、array_can_choose
関数を終了するとすぐに変数は存在しなくなりますint ** Master::what_can_choose()
。
なぜ関数から変数を返すことができるのか不思議に思うかもしれません。これは、ほとんどの変数をコピーできるためです。これは、(たとえば)int
関数からを返すとき、または関数にを渡すときに起こることですint
。ただし、アレイはコピーできません。これは、非常に大きなアレイをコピーするときに予期しない大幅な速度低下を防ぐために行われました。代わりに、配列を関数に渡すときは、配列の内容を指す変数のみを渡します。これは、関数を終了するとこの配列の内容が存在しなくなるため、ローカル配列を返すことができないことを意味します。そのため、戻り変数は「存在しない」メモリを指します。
これを回避するには、動的割り当てを使用する必要があります。
int ** Master::what_can_choose()
{
//dynamically allocate the array we want to return
int** array_can_choose = new int*[9];
for( int i=0; i<9; i++ )
{
array_can_choose[i] = new int[2];
for( int j=0; j<2; j++ )
array_can_choose[i][j] = 0; //initialize all values to 0
}
//a type (such as char) is required for arrays
char board[3][3]={{' ',' ','x'},{' ','o',' '},{'x',' ',' '}};
int x=0;
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
if (board[i][j]==' ')
{
array_can_choose[x][0]=i;
array_can_choose[x][1]=i;
x+=1;
}
}
}
return array_can_choose;
}
ここで、動的割り当てを使用することの1つの欠点は、割り当てたメモリも解放する必要があることです。動的割り当てにより、現在のスコープを離れてもメモリが存在することが保証されます(そのため、配列を返すことができます)が、これは、メモリが「存在を停止」できる時期が明確ではなくなったことを意味します。このため、メモリの使用が終了したときにコンパイラに明示的に通知して、このメモリを解放できるようにする必要があります。を使用してこれを行うことができますdelete[]
。-part[]
は、1つの項目だけでなく、配列全体を削除するようにコンパイラーに指示します。配列の配列を割り当てたため、この削除を一度に行うことはできません。すべてのサブ配列を削除してから、2D配列自体を削除する必要があります(前に説明したように、これは実際には配列へのポインターの1D配列です)。
Master master; //we need an object to call our function
int** our_array = master.what_can_choose(); //this allocates an array and stores it in our_array
//do stuff with our_array
for( int i=0; i<9; i++ )
delete[] our_array[i]; //delete a sub-array
delete[] our_array; //delete the array itself.
//we can now no longer do stuff with our_array
このようにメモリを削除しないということは、割り当てたメモリが不要になっても永久に占有されることを意味します。これは「メモリリーク」と呼ばれます。これを頻繁に行うと、コンピュータのメモリが最終的に不足し、プログラムがクラッシュします。