Как передать двумерный массив в функцию c
Перейти к содержимому

Как передать двумерный массив в функцию c

  • автор:

Передать двумерный статический массив в функцию

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

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

void f( int a[], size_t m, size_t n ); //. int A[3][4]; f( reinterpret_cast( A ), 3, 4 ); 

Вот демонстрационная программа

#include #include void f( int a[], size_t m, size_t n ) < for ( size_t i = 0; i < m; i++ ) < for ( size_t j = 0; j < n; j++ ) a[i * n + j ] = i * n + j; >> int main() < const size_t M = 3; const size_t N = 4; int a[M][N]; f( reinterpret_cast( a ), M, N ); for ( size_t i = 0; i < M; i++ ) < for ( size_t j = 0; j < N; j++ ) std::cout return 0; > 

Ее вывод на консоль

 0 1 2 3 4 5 6 7 8 9 10 11 

Если же писать программу на C, а не на C++, то там есть массивы переменной длины, и поэтому вам было бы проще.

В C++ для этих целей лучше использовать стандартный класс std::vector

std::vector> v( 3, std::vector( 4 ) ); 

Что касается вашего вопроса

2)Статические 2D массивы хранятся в памяти линейно. Динамические хранятся тоже линейно или нет?

то если вы будете распределять его в памяти как двумерный массив, то естественно его элементы будут храниться линейно по строкам. Например

int ( *a )[4] = new int[3][4]; 

А что касается этого вопроса

3)Какую связь имеет статический 2D массив с указателями?

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

Отслеживать
ответ дан 6 ноя 2015 в 19:03
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 39 39 серебряных знаков 90 90 бронзовых знаков
А как сделать эту функцию универсальнее, чтобы она принимала любые A[x][y] ?
6 ноя 2015 в 19:08

@neko69 Что значит «любые»? Если любые двумерные массивы с любыми значениями размерностей, то сделайте ее шаблонной.

6 ноя 2015 в 19:10
Шаблонная, в смысле template ? Без этого нельзя?
6 ноя 2015 в 19:12
@neko69 Если вы хотите иметь дело именно с двумерными массивами, то без этого не обойтись.
6 ноя 2015 в 19:13
@neko69 Смотрите мой обновленный ответ.
6 ноя 2015 в 19:17

В gcc сделать это совсем просто.

Вы можете передавать в функцию размерности матрицы (достаточно только «низших») и обращаться к элементам по индексам естестственным образом. Например:

void func (int n_lines, int n_columns, int array[][n_columns])

К сожалению g++ (и c++) не поддерживает такую передачу матриц в функцию. Поэтому проще всего (обладая знанием, что все элементы матрицы располагаются в памяти последовательно, сначала первая строка, за ней вторая и т.д.) передать в функцию адрес первого элемента матрицы, а в функции рассматривать ее как одномерный массив.
Естественно, пересчитывать индексы придется самому.

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

avp@avp-ubu1:hashcode$ cat c1.c #include #ifdef __cplusplus #include #endif static int aa[4][3] = < , , , >; #ifdef __cplusplus void func_matrix (int n, int m, int *x) < x[0] = x[(n - 1) * m + m - 1]; for (int i = 0; i < n; i++) for (int j = 0; j < m || !puts(""); j++) std::cout #else void func_matrix (int n, int m, int x[n][m]) < int i, j; x[0][0] = x[n - 1][m - 1]; for (i = 0; i < n; i++) for (j = 0; j < m || !puts(""); j++) printf("%d ", x[i][j]); >#endif int main (int ac, char *av[]) < #ifdef __cplusplus func_matrix(4, 3, &aa[0][0]); #else func_matrix(4, 3, aa); #endif >avp@avp-ubu1:hashcode$ gcc c1.c && ./a.out 43 12 13 21 22 23 31 32 33 41 42 43 avp@avp-ubu1:hashcode$ g++ c1.c && ./a.out 43 12 13 21 22 23 31 32 33 41 42 43 avp@avp-ubu1:hashcode$ 

Если вопросы еще остались, задавайте.

UPD

Вот вариант с указателями на строки «плотной» матрицы.

Берем статическую матрицу, делаем для нее массив указателей, передаем его в функцию транспонирования, которая делает в динамической памяти «плотную» транспонированную матрицу и возвращает новый массив указателей на ее строки.

#include #include int ** make_lines_ptrs (int *mx, int a, int b) < int **p = (int **)malloc(a * sizeof(int *)); for (int i = 0; i < a; i++) p[i] = mx + i * b; return p; >int ** transp (const int * const * m, int a, int b) < int *mx = (int *)malloc(a * b * sizeof(int)); for (int i = 0; i < a; i++) for (int j = 0; j < b; j++) mx[j * a + i] = m[i][j]; return make_lines_ptrs(mx, b, a); >void pri_mx (const int * const * m, int a, int b) < for (int i = 0; i < a; i++) for (int j = 0; j < b || !puts(""); j++) printf("%d ", m[i][j]); >static int aa[4][3] = < , , , >; int main (int ac, char *av[])

Ну, память перед выходом Вы уж сами освободите?

Как передать в функцию двумерный массив.

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

Ответ напрашивается сам собой, использовать для этого указатель. Но просто передать адрес первого элемента двумерного массива недостаточно(по сути указатель), давайте разберемся почему.

Несмотря на то, что двумерный массив, по сути представляет собой таблицу(массив элементами которого являются массивы), в памяти все его элементы хранятся последовательно и для того, чтобы в этой последовательности как-то ориентироваться необходимо знать размер его второй мерности. То есть если у нас есть массив arr[5][20], для работы с ним достаточно знать с какого адреса он начинается и что размер его второй мерности равен 20.

Тогда формула для вычисления адреса любого элемента массива будет иметь следующий вид
arr + 20*i + j
arr — адрес начала массива;
i — первый индекс элемента;
j — второй индекс элемента;

Двумерный массив можно использовать для хранения строк, описывающих какую-то сущность. В таком случае функция, модифицирующая его, будет выглядеть следующим образом.

void Update_List_Name(char *arr, uint8_t j) { char a; uint32_t adr; //первая буква первой строки имеет адрес начала массива adr = (arr+0*j+0); //вторая буква первой строки располагается по адресу adr = (arr+0*j+1) ; //вторая буква первой строки располагается по адресу adr = (arr+1*j+0) ; //вторая буква первой строки располагается по адресу adr = (arr+1*j+1) // для получения данных хранящихся в ячейке, // необходимо использовать операцию разыменования a = *adr; >

Аналогично можно передать указатель, указав размер второй мерности массива

void Update_List_Name(char *arr[20]) { char a; //в таком случае обращаться к элементам массива можно как обычно a = arr[1][2]; >

Или передать массив, указав размер его второй мерности.

void Update_List_Name(char arr[][20]) { char a; //в таком случае обращаться к элементам массива можно как обычно a = arr[1][2]; >

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

Как передать двумерный статический массив в функцию на Си?

Есть массив char mass[1024][1024] и функция int fun(char*) . При вставке функции fun(mass) , компилятор выдаёт предупреждение о несоответствии типов, приходиться приводить тип fun((char*)mass)<> или fun((char*)&mass)<> . Есть ли возможность для указания статического массива как аргумента? И почему типы разные?

  • Вопрос задан более трёх лет назад
  • 3237 просмотров

Комментировать
Решения вопроса 1
Не ИТ-специалист

Целиком массив в функцию не передаётся (если только не обернуть его в структуру), а передаётся указатель на его 0-й элемент и формальный аргумент функции должен быть указателем на тип элементов массива, передаваемого фактическим аргументом.
n-мерный массив — это 1-мерный массив (n-1)-мерных массивов и, соответственно, формальным аргументом функции должен быть указатель на (n-1)-мерный массив.
В данном случае

int fun(char (*)[1024]); int fun(char (*m)[1024]) 

Ответ написан более трёх лет назад
Нравится 1 1 комментарий
Данил Тунев @lada-guy Автор вопроса
Спасибо, очень логично,в выходные заценю
Ответы на вопрос 1
«I’m here to consult you» © Dogbert

Есть массив char mass[1024][1024] и функция int fun(char*)

в такую функцию можно передать fun(&mass[0][0]) .

Есть ли возможность для указания статического массива как аргумента?

В смысле массива статической размерности? Легко: int fun(char a[][1000]); . fun(mass);
Ответ написан более трёх лет назад
Данил Тунев @lada-guy Автор вопроса

Компилятор gcc не разрешает такого рода аргументы: int fun(char mass[][1000]); Только с помощью указателей передаются массивы. В общем разобрался, спасибо за ответ!

Компилятор gcc не разрешает такого рода аргументы: int fun(char mass[][1000])

О, как интересно. Данил Тунев расскажи мне, почему, а то я даже отдалённо не вижу никаких проблем?
Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++
  • +1 ещё

Почему неправильно считает Коэффициенты регрессии?

  • 2 подписчика
  • 01 мая
  • 91 просмотр

Как правильно передать двумерный массив в функцию?

но если указать вместо size, конкретную цифру то все сработает.

void foo(int arr[][5]) < . >int arr[5][5] = <>;

Как в первом случае отправить массив в функцию ? Подскажите самый оптимальный вариант.

  • Вопрос задан более трёх лет назад
  • 10584 просмотра

Решения вопроса 3

myjcom

Roman @myjcom Куратор тега C++
const int size
Массив не передается. Передается указатель. Даже если вы пишете a[][size]
Ответ написан более трёх лет назад
Нравится 1 2 комментария

myjcom

Roman @myjcom Куратор тега C++
Размер массива должен быть известен на этапе компиляции.

myjcom

Roman @myjcom Куратор тега C++
int sum; неинициализированная переменная

#include template int foo(int (&matrix)[ColumnCount][RowCount]) < int r = 0; for(auto& row: matrix)< for(auto& x: row) r += x; >return r; > int bar()< int matrix [][2] = , , >; return foo(matrix); >

С-массивы в функции можно передавать только по ссылке. Или преобразовать в массив указателей.

Вообще, для передачи С-массивов придуман std::array , но двумерный C-массив нельзя напрямую привести к std::array, N> . Но можно изначально работать с std::array :

template int foo(std::array, ColumnCount>& matrix) < int r = 0; for(auto& row: matrix)< for(auto& x: row) r += x; >return r; > int bar()< std::array, 3> matrix = , , >>; return foo(matrix); >

Ответ написан более трёх лет назад
Нравится 1
Developer, ex-admin

Если вы изучаете С++, то лучше использовать классы стандартной библиотеки для массивов. В функцию передаете ссылку на класс.
В чистом Си передается просто указатель и размер в отдельном параметре (или 2 размера для двумерного массива).
Сам двумерный массив может быть представлен в двух вариантах:
1.Как массив указателей, где каждый указатель представляет собой одномерный массив. Нужно отдельно выделять память для массива указателей и для каждого одномерного подмассива и аналогично освобождать. В этом случае возможна операция индексации обоих измерений массива, при этом массив указателей и каждый подмассив могут находится в разных участках памяти.

void foo(int ** arr, int N, int M) < . >int main() < int N = 10; // первое измерение массива int M = 20; // второе измерение массива int ** arr = new int * [N]; for(int i = 0; i < M; ++i) < arr[i] = new int[M]; >. foo(arr, N, M); . // Тут освобождение массива аналогично выделению в обратном порядке >

2.Как одномерный массив размерностью N * M. В этом случае память под массив выделяется и освобождается вся оптом одним куском, но операция индексации первых размерностей не возможна. Но можно легко переходить от двумерного массива к одномерному, сразу вычислять нужный индекс или просто перемещаться по элементам массива с помощью временного указателя.

void foo(int * arr, size_t N, size_t M) < . >int main() < int N = 10; // первое измерение массива int M = 20; // второе измерение массива int * arr = new int * [N*M]; int * arrcur = arr; // временный указатель для обхода массива int * arrone = arr; // вариант с переходом к одномерному массиву for(int i = 0; i < N; ++i) < for(int j = 0; j < M; ++j) < // Вариант с вычислением адреса текущего элемента по индексам *(arr + i * M + j) = rand() % 10; // вычисление нужного индекса на месте // Вариант с обходом массива с помощью временного указателя *arrcur = rand() % 10; ++arrcur; // переход к следующему элементу // Вариант с переходом к одномерному массиву arrone[j] = rand() % 10; >arrone += M; > . foo(arr, N, M); . delete[] arr; >

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *