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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
54
0
79 867
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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.

здесь нужна помощь: stackoverflow.com/questions/16943909/…

Dchris 05.06.2013 20:01

Указатель на сегментированную таблицу поиска указателя не является двумерным массивом. Просто потому, что он поддерживает синтаксис [][], он не превращается волшебным образом в массив. Вы не можете использовать memcpy () и т. д., Потому что память не выделяется в соседних ячейках памяти, что требуется для массивов. Ваша таблица поиска довольно разбросана по всей куче, что замедляет поиск и фрагментирует кучу.

Lundin 23.06.2015 13:42

Передайте явный указатель на первый элемент с размерами массива в качестве отдельных параметров. Например, для обработки двумерных массивов произвольного размера 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);

Вместо p[i*Y+j*Z+k] должен быть p[i*Y*Z+j*Z+k].

David H 18.08.2012 13:01
stackoverflow.com/questions/16943909/…
Dchris 05.06.2013 20:02

каковы значения i и j?

AlphaGoku 06.04.2016 12:17

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
}
stackoverflow.com/questions/16943909/…
Dchris 05.06.2013 20:02

Это не 2D-массив, это таблица поиска. Кроме того, это помечено C.

Lundin 23.06.2015 13:45

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

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

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

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

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

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

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

ИМО, это должен быть принятый ответ. Никакого дополнительного кода и ненужного выделения кучи. простой и чистый

kjh 27.04.2015 20:03

Спасибо @kjh, я тоже считаю, что это самое чистое решение. Принятый ответ - тот, который у него сработал. Смотрите: ОП от 2008 года, почти за 6 лет до моего ответа. Кроме того, я не знаю, допускали ли тогда стандарты C синтаксис, который я использовал здесь.

rslemos 30.04.2015 06:23

Это решение, которое я наконец принял для передачи целочисленной матрицы (двумерного массива) размера M x N в качестве аргумента функции. Возможно, будет полезно немного больше информации: Прототип функции похож на: void f (int N, int data [] [N], int M); В теле функции элемент [m] [n] может быть записан как data [m] [n] - очень удобно, вычисление индекса не требуется.

jonathanzh 19.05.2015 12:08

Я объявляю функцию, как вы сказали, я вызываю ее из main (), и все в порядке, но как мне объявить переменную data в моем main (), если я не знаю размер (а)? Я пробовал с int* data, но не работает.

glc78 27.08.2017 14:30

@ 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 12:13

In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?

Нет

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

Вы можете поместить измерение [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 имеет значение sentinel, которое может использоваться для обозначения конца последнего одномерного массива нижнего уровня типа 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++;
    }
}

Другие вопросы по теме

«Метафункция» в R для создания функций с оцененным/явным параметром? (не знаю, как точно это сформулировать)
Ошибка при передаче переменной в ggplot в пользовательской функции r
Как векторизовать функцию, которая присваивает значение элементу на основе поиска в справочной таблице?
Можно ли заменить эти две функции Python одной универсальной, принимающей либо список, либо аргумент кортежа?
Как называется событие, которое передает только аргументы типа в общую функцию в машинописном тексте?
Шифр Цезаря неправильно сдвигает буквы в алфавитном списке
Ошибка компиляции C «вызываемый объект не является функцией или указателем на функцию»
Рекурсивное преобразование фрейма данных во вложенный список, где уровень вложенности списка равен количеству столбцов в фрейме данных
PHP: обновить глобальную ссылочную переменную внутри области функции
Использование рекурсивной функции для создания списка, вложенного n раз