配列の次元が不明な場合、多次元配列を単一の引数として関数C
に渡すことはできますか?
また、多次元配列には文字列以外の型が含まれている場合があります。
配列の次元が不明な場合、多次元配列を単一の引数として関数C
に渡すことはできますか?
また、多次元配列には文字列以外の型が含まれている場合があります。
配列の次元を個別のパラメーターとして使用して、最初の要素への明示的なポインターを渡します。たとえば、任意のサイズの int の 2 次元配列を処理するには、次のようにします。
void func_2d(int *p, size_t M, size_t N)
{
size_t i, j;
...
p[i*N+j] = ...;
}
これは次のように呼ばれます
...
int arr1[10][20];
int arr2[5][80];
...
func_2d(&arr1[0][0], 10, 20);
func_2d(&arr2[0][0], 5, 80);
高次元の配列にも同じ原則が適用されます。
func_3d(int *p, size_t X, size_t Y, size_t Z)
{
size_t i, j, k;
...
p[i*Y*Z+j*Z+k] = ...;
...
}
...
arr2[10][20][30];
...
func_3d(&arr[0][0][0], 10, 20, 30);
これは、任意のデータ型で実行できます。単純にポインターツーポインターにします。
typedef struct {
int myint;
char* mystring;
} data;
data** array;
ただし、変数を malloc する必要があり、少し複雑になることを忘れないでください。
//initialize
int x,y,w,h;
w = 10; //width of array
h = 20; //height of array
//malloc the 'y' dimension
array = malloc(sizeof(data*) * h);
//iterate over 'y' dimension
for(y=0;y<h;y++){
//malloc the 'x' dimension
array[y] = malloc(sizeof(data) * w);
//iterate over the 'x' dimension
for(x=0;x<w;x++){
//malloc the string in the data structure
array[y][x].mystring = malloc(50); //50 chars
//initialize
array[y][x].myint = 6;
strcpy(array[y][x].mystring, "w00t");
}
}
構造体の割り当てを解除するコードは似ています。malloc したすべてのものに対して free() を呼び出すことを忘れないでください。(また、堅牢なアプリケーションでは、 malloc() の戻りを確認する必要があります。)
これを関数に渡したいとしましょう。おそらくデータ構造のポインターへのポインターではなく、データ構造に対して操作を行いたいため、ダブルポインターを引き続き使用できます。
int whatsMyInt(data** arrayPtr, int x, int y){
return arrayPtr[y][x].myint;
}
この関数を次のように呼び出します。
printf("My int is %d.\n", whatsMyInt(array, 2, 4));
出力:
My int is 6.
C では、配列の次元が不明な場合に、多次元配列を単一の引数として関数に渡すことはできますか?
いいえ
「単一の引数」によって、配列の次元を渡さずに配列だけを渡すことを意味する場合は、できません。少なくとも真の多次元配列ではありません。
次元を配列とともに構造体に入れ、「単一の引数」を渡していると主張できますが、それは実際には複数の値を単一のコンテナーにパックし、そのコンテナーを「1 つの引数」と呼んでいるだけです。
次のように、次元自体と配列を渡すことで、既知の型と次元数の配列を渡すことができますが、サイズは不明です。
void print2dIntArray( size_t x, size_t y, int array[ x ][ y ] )
{
for ( size_t ii = 0, ii < x; ii++ )
{
char *sep = "";
for ( size_t jj = 0; jj < y; jj++ )
{
printf( "%s%d", sep, array[ ii ][ jj ] );
sep = ", ";
}
printf( "\n" );
}
}
その関数を次のように呼び出します。
int a[ 4 ][ 5 ];
int b[ 255 ][ 16 ];
...
print2dIntArray( 4, 5, a );
....
printt2dIntArray( 255, 16, b );
同様に、たとえば a の 3 次元配列struct pixel
:
void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
...
}
または 1 次元double
配列:
void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
...
}
しかし...
ただし、基本型にセンチネル値があるX
限り、「多次元配列」として誤ってラベル付けされることが多い「型の配列のポインターの配列へのポインターの配列」を渡すことは可能です。X
type の最終的な最下位レベルの 1 次元配列の終わりを示すために使用できますX
。
たとえば、 にchar **argv
渡される値main()
は、 へのポインターの配列へのポインターchar
です。char *
ポインターの初期配列はNULL
センチネル値で終わりますが、ポインターchar
の配列によって参照される各配列はの文字値でchar *
終わります。NUL
'\0'
たとえば、NAN
実際のデータNAN
がdouble **
.
void printDoubles( double **notAnArray )
{
while ( *notAnArray )
{
char *sep = "";
for ( size_t ii = 0; ( *notAnArray )[ ii ] != NAN; ii++ )
{
printf( "%s%f", sep, ( *notAnArray )[ ii ] );
sep = ", ";
}
notAnArray++;
}
}
int matmax(int **p, int dim) // p- matrix , dim- dimension of the matrix
{
return p[0][0];
}
int main()
{
int *u[5]; // will be a 5x5 matrix
for(int i = 0; i < 5; i++)
u[i] = new int[5];
u[0][0] = 1; // initialize u[0][0] - not mandatory
// put data in u[][]
printf("%d", matmax(u, 0)); //call to function
getche(); // just to see the result
}