Передача многомерных массивов в качестве аргументов функции в C

В C я могу передать многомерный массив в функцию в качестве единственного аргумента , когда я не знаю , что размеры массива будут?

Кроме того, мой многомерный массив может содержать типы, отличные от строк.

Ответов (5)

Решение

Вы можете сделать это с любым типом данных. Просто сделайте это указателем на указатель:

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");
  }
}

Код для освобождения структуры выглядит примерно так же - не забудьте вызвать 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.
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
}

Вы можете объявить свою функцию как:

f(int size, int data[][size]) {...}

Затем компилятор выполнит за вас всю арифметику с указателями.

Обратите внимание, что размеры размеров должны появляться перед самим массивом.

GNU C допускает пересылку объявления аргументов (в случае, если вам действительно нужно передать размеры после массива):

f(int size; int data[][size], int size) {...}

Первое измерение, хотя вы также можете передать его в качестве аргумента, бесполезно для компилятора C (даже для оператора sizeof, когда он применяется к массиву, переданному как аргумент, всегда будет рассматриваться как указатель на первый элемент).

Могу ли я передать многомерный массив в функцию в качестве одного аргумента, если я не знаю, какими будут размеры массива?

Нет

Если под «одним аргументом» вы подразумеваете передачу только массива без передачи размеров массива, нет, вы не можете. По крайней мере, для настоящих многомерных массивов.

Вы можете поместить измерение [s] в структуру вместе с массивом и заявить, что вы передаете «единственный аргумент», но на самом деле это просто упаковка нескольких значений в один контейнер и вызов этого контейнера «одним аргументом».

Вы можете передать массив известного типа и количества измерений, но неизвестного размера, передав сами размеры и массив следующим образом:

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 );

Точно так же 3-мерный массив, например struct pixel :

void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
    ...
}

или одномерный double массив:

void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
    ...
}

НО...

Однако можно передавать «массивы указателей на массивы указателей на ... массив типа X » конструкции, которые часто ошибочно маркируются как «многомерный массив» в качестве единственного аргумента, если базовый тип X имеет контрольное значение. который может использоваться для обозначения конца окончательного одномерного массива нижнего уровня типа X .

Например, char **argv переданное значение main() является указателем на массив указателей на char . Начальный массив char * указателей заканчивается NULL контрольным значением, в то время как каждый char массив, на который ссылается массив char * указателей, заканчивается NUL символьным значением '\0' .

Например, если вы можете использовать NAN в качестве контрольного значения, потому что фактические данные никогда не будут a 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:

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);