下記のようにC/C++の配列で多次元配列を作れば連続したメモリ領域となるが、動的に大きさを変えられないし、関数に渡したりするのも大変だ。
int a[N][M];
一方、ポインタを使った下記の方法だと確保したメモリ領域が不連続となる。
int **a = new int*[N]; for (int i = 0; i < N; i++) a[i] = new int[M];
動的にメモリ確保して連続したメモリ領域にしたい場合、以下のようにすれば良い。
int **a = new int*[N]; a[0] = new int[N * M]; for (int i = 1; i < N; i++) a[i] = a[0] + i * M;
ここで、a[i][j] と (*a)[i*M+j] は同じ値を示す。
二次元配列、三次元配列を扱った実際のコード(C/C++)を最後に載せておく。
Cバージョン:
#include <stdio.h> #include <stdlib.h> /* NX*NYの二次元配列およびNX*NY*NZの三次元配列. */ #define NX 5 #define NY 6 #define NZ 7 int main() { int **x2; int ***x3; int cnt2 = 0; int cnt3 = 0; int i, j, k; /* 二次元配列の作成 */ x2 = (int**)malloc(NX * sizeof(int*)); x2[0] = (int*)malloc(NX * NY * sizeof(int)); for (i = 1; i < NX; i++) x2[i] = x2[0] + i * NY; /* 三次元配列の作成 */ x3 = (int***)malloc(NX * sizeof(int**)); x3[0] = (int**)malloc(NX * NY * sizeof(int*)); x3[0][0] = (int*)malloc(NX * NY * NZ * sizeof(int)); for (i = 0; i < NX; i++) { x3[i] = x3[0] + i * NY; for (j = 0; j < NY; j++) x3[i][j] = x3[0][0] + i * NY * NZ + j * NZ; } /* 配列に数値を代入 */ for (i = 0; i < NX; i++) { for (j = 0; j < NY; j++) { x2[i][j] = cnt2++; for (k = 0; k < NZ; k++) x3[i][j][k] = cnt3++; } } /* 配列を表示 */ for (i = 0; i < NX; i++) { for (j = 0; j < NY; j++) { printf("x2[%d][%d] = %d\n", i, j, x2[i][j]); printf("(*x2)[%d*NY+%d] = %d\n", i, j, (*x2)[i*NY+j]); for (k = 0; k < NZ; k++) { printf("x3[%d][%d][%d] = %d\n", i, j, k, x3[i][j][k]); printf("(**x3)[%d*NY*NZ+%d*NZ+%d] = %d\n", i, j, k, (**x3)[i*NY*NZ+j*NZ+k]); } } } free(x2[0]); free(x2); free(x3[0][0]); free(x3[0]); free(x3); return 0; }
C++バージョン:
#include <iostream> // NX*NYの二次元配列およびNX*NY*NZの三次元配列. const int NX = 5; const int NY = 6; const int NZ = 7; int main() { // 二次元配列の作成. int **x2; x2 = new int*[NX]; x2[0] = new int[NX * NY]; for (int i = 1; i < NX; i++) x2[i] = x2[0] + i * NY; // 三次元配列の作成. int ***x3; x3 = new int**[NX]; x3[0] = new int*[NX * NY]; x3[0][0] = new int[NX * NY * NZ]; for (int i = 0; i < NX; i++) { x3[i] = x3[0] + i * NY; for (int j = 0; j < NY; j++) x3[i][j] = x3[0][0] + i * NY * NZ + j * NZ; } // 配列に数値を代入. int cnt2 = 0; int cnt3 = 0; for (int i = 0; i < NX; i++) { for (int j = 0; j < NY; j++) { x2[i][j] = cnt2++; for (int k = 0; k < NZ; k++) x3[i][j][k] = cnt3++; } } // 配列を表示. for (int i = 0; i < NX; i++) { for (int j = 0; j < NY; j++) { std::cout << "x2[" << i << "][" << j << "] = " << x2[i][j] << std::endl; std::cout << "(*x2)[" << i << "*NY+" << j << "] = " << (*x2)[i*NY+j] << std::endl; for (int k = 0; k < NZ; k++) { std::cout << "x3[" << i << "][" << j << "][" << k << "] = " << x3[i][j][k] << std::endl; std::cout << "(**x3)[" << i << "*NY*NZ+" << j << "*NZ+" << k << "] = " << (**x3)[i*NY*NZ+j*NZ+k] << std::endl; } } } delete[] x2[0]; delete[] x2; delete[] x3[0][0]; delete[] x3[0]; delete[] x3; return 0; }
int a[N][M];
一方、ポインタを使った下記の方法だと確保したメモリ領域が不連続となる。
int **a = new int*[N]; for (int i = 0; i < N; i++) a[i] = new int[M];
動的にメモリ確保して連続したメモリ領域にしたい場合、以下のようにすれば良い。
int **a = new int*[N]; a[0] = new int[N * M]; for (int i = 1; i < N; i++) a[i] = a[0] + i * M;
ここで、a[i][j] と (*a)[i*M+j] は同じ値を示す。
二次元配列、三次元配列を扱った実際のコード(C/C++)を最後に載せておく。
Cバージョン:
#include <stdio.h> #include <stdlib.h> /* NX*NYの二次元配列およびNX*NY*NZの三次元配列. */ #define NX 5 #define NY 6 #define NZ 7 int main() { int **x2; int ***x3; int cnt2 = 0; int cnt3 = 0; int i, j, k; /* 二次元配列の作成 */ x2 = (int**)malloc(NX * sizeof(int*)); x2[0] = (int*)malloc(NX * NY * sizeof(int)); for (i = 1; i < NX; i++) x2[i] = x2[0] + i * NY; /* 三次元配列の作成 */ x3 = (int***)malloc(NX * sizeof(int**)); x3[0] = (int**)malloc(NX * NY * sizeof(int*)); x3[0][0] = (int*)malloc(NX * NY * NZ * sizeof(int)); for (i = 0; i < NX; i++) { x3[i] = x3[0] + i * NY; for (j = 0; j < NY; j++) x3[i][j] = x3[0][0] + i * NY * NZ + j * NZ; } /* 配列に数値を代入 */ for (i = 0; i < NX; i++) { for (j = 0; j < NY; j++) { x2[i][j] = cnt2++; for (k = 0; k < NZ; k++) x3[i][j][k] = cnt3++; } } /* 配列を表示 */ for (i = 0; i < NX; i++) { for (j = 0; j < NY; j++) { printf("x2[%d][%d] = %d\n", i, j, x2[i][j]); printf("(*x2)[%d*NY+%d] = %d\n", i, j, (*x2)[i*NY+j]); for (k = 0; k < NZ; k++) { printf("x3[%d][%d][%d] = %d\n", i, j, k, x3[i][j][k]); printf("(**x3)[%d*NY*NZ+%d*NZ+%d] = %d\n", i, j, k, (**x3)[i*NY*NZ+j*NZ+k]); } } } free(x2[0]); free(x2); free(x3[0][0]); free(x3[0]); free(x3); return 0; }
C++バージョン:
#include <iostream> // NX*NYの二次元配列およびNX*NY*NZの三次元配列. const int NX = 5; const int NY = 6; const int NZ = 7; int main() { // 二次元配列の作成. int **x2; x2 = new int*[NX]; x2[0] = new int[NX * NY]; for (int i = 1; i < NX; i++) x2[i] = x2[0] + i * NY; // 三次元配列の作成. int ***x3; x3 = new int**[NX]; x3[0] = new int*[NX * NY]; x3[0][0] = new int[NX * NY * NZ]; for (int i = 0; i < NX; i++) { x3[i] = x3[0] + i * NY; for (int j = 0; j < NY; j++) x3[i][j] = x3[0][0] + i * NY * NZ + j * NZ; } // 配列に数値を代入. int cnt2 = 0; int cnt3 = 0; for (int i = 0; i < NX; i++) { for (int j = 0; j < NY; j++) { x2[i][j] = cnt2++; for (int k = 0; k < NZ; k++) x3[i][j][k] = cnt3++; } } // 配列を表示. for (int i = 0; i < NX; i++) { for (int j = 0; j < NY; j++) { std::cout << "x2[" << i << "][" << j << "] = " << x2[i][j] << std::endl; std::cout << "(*x2)[" << i << "*NY+" << j << "] = " << (*x2)[i*NY+j] << std::endl; for (int k = 0; k < NZ; k++) { std::cout << "x3[" << i << "][" << j << "][" << k << "] = " << x3[i][j][k] << std::endl; std::cout << "(**x3)[" << i << "*NY*NZ+" << j << "*NZ+" << k << "] = " << (**x3)[i*NY*NZ+j*NZ+k] << std::endl; } } } delete[] x2[0]; delete[] x2; delete[] x3[0][0]; delete[] x3[0]; delete[] x3; return 0; }
コメント
お蔭でようやく疑問が解決しました。
ありがとうございます。
ちなみに、ちょっとした画像処理と音声処理をしようとしています。包絡線を弄るだけではありますが。