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

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

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

6.08.2008 22:01:25
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.
23
29.04.2015 23:38:48
здесь нужна помощь: stackoverflow.com/questions/16943909/…
Dchris 5.06.2013 16:01:25
Указатель на сегментированную таблицу поиска с указателем не является двумерным массивом. Просто потому, что он допускает [][]синтаксис, он волшебным образом не превращается в массив. Вы не можете использовать memcpy () и т. Д., Поскольку память не выделяется в соседних ячейках памяти, что требуется для массивов. Ваша таблица поиска довольно разбросана по всей куче, что делает поиск медленным, а куча фрагментированной.
Lundin 23.06.2015 10:42:37

Передайте явный указатель на первый элемент с размерами массива в качестве отдельных параметров. Например, для обработки двухмерных массивов типа 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);
33
26.05.2016 18:42:17
p[i*Y+j*Z+k]должно быть p[i*Y*Z+j*Z+k]вместо.
David H 18.08.2012 09:01:38
Dchris 5.06.2013 16:02:08
каковы значения i и j?
AlphaGoku 6.04.2016 09:17:46
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
}
-2
7.02.2016 17:37:07
Dchris 5.06.2013 16:02:32
Это не двумерный массив, это справочная таблица. Кроме того, это помечено C.
Lundin 23.06.2015 10:45:55

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

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

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

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

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

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

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

21
12.01.2015 18:51:34
ИМО это должен быть принятый ответ. Не требуется никакого дополнительного кода и ненужных выделений кучи. просто и чисто
imkendal 27.04.2015 17:03:00
Спасибо @kjh, я также думаю, что это самое чистое решение. Принимается ответ тот, который работал на него. Посмотрите: ОП с 2008 года, почти за 6 лет до моего ответа. Кроме того, я не знаю, допускали ли тогда стандарты C для синтаксиса, который я здесь использовал.
rslemos 30.04.2015 03:23:47
Это решение, которое я, наконец, принял для передачи целочисленной матрицы (двумерного массива) размером M x N в качестве аргумента функции. Может быть, немного больше информации будет полезно: Прототип функции выглядит так: void f (int N, int data [] [N], int M); В теле функции элемент [m] [n] может быть записан как data [m] [n] - очень удобно, вычисление индекса не требуется.
jonathanzh 19.05.2015 09:08:35
Я объявляю функцию, как вы сказали, я вызываю ее из main (), и это нормально, но как мне объявить переменную dataв main (), если я не знаю размер (ы)? Я пытался с, int* dataно не сработает.
glc78 27.08.2017 11:30:27
@ glc78 Или как VLA в стеке int data[height][width];или в куче с int (*data)[width] = malloc(height*sizeof(*data));. В обоих случаях вы можете впоследствии получить доступ data[y][x]обычным способом и передать его f(width, data).
cmaster - reinstate monica 13.12.2019 09:13:21

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

нет

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

Вы можете поместить измерение [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++;
    }
}
0
13.12.2019 11:22:39