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

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

  • автор:

Передача двумерного массива в функцию

Author24 — интернет-сервис помощи студентам

Начал изучать с++ в vs .
Дошел до темы функции.
Понял как передавать одномерный массив в функции.
Решил попробовать передать двумерный массив в функции. столкнулся с проблемой.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include ; using namespace std; void(FillArrey(int arr[][], const int row, const int col)) { for (int i = 0; i  row;i++) { for (int j = 0; j  col;j++) { arr[i][j] = rand() % 10; } } } void PrintArrey(int arr[][], const int row, const int col) { for (int i = 0; i  row;i++) { for (int j = 0; j  col;j++) { cout  [i][j]<" "; } cout  ; } } void main() { setlocale(LC_ALL, "ru"); const int ROW = 5; const int COL = 4; int arr[ROW][COL]; FillArrey(arr, ROW,COL); PrintArrey(arr, ROW,COL); system("pause"); }

Вот фрагмент где визуал кажет ошибку:
void(FillArrey(int arr[] [ ], const int row, const int col))
void PrintArrey(int arr[] [ ], const int row, const int col)
не могу понять в чем проблема, тыкался по форумам — ответов не нашел. Кто может объяснить в чем причина. Я так понял — неправильно объявляю массив в функции?

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

Это массив указателей на float, указатель на массив — это float (* M)[N]. В С++ и С до С99 на месте N обязательно должна быть константа.

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Программист

Остальные Вам правильно написали. Надо указывать размер строки.

Если для Вас это неприемлемо, то есть другие варианты. Например, принимать
float det(float**m, int rows, int cols)

Но тогда передавать надо сложнее.
например:

int rows = . ; int cols = . ; float **m; m = calloc(rows, sizeof(float*)); for (int i=0; i /* как-то заполняете значения */ float res = det(m, rows, cols);

Однако, такой код нормален для C, но не для С++. В C++ коде я бы поостерегся передавать двумерный массив. Впрочем, как и одномерный массив. Вместо это лучше сделать класс матрица. И все особенности хранения данных решать уже в этом классе. Равно как и метод нахождения определителя.

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

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

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

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

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

Решения вопроса 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; >

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

Если функция принимает в качестве параметра массив, то фактически в эту функцию передается указатель на первый элемент массива. То есть как и в случае с указателями нам доступен адрес, по которому мы можем менять значения. Поэтому следующие объявления функции будут по сути равноценны:

void print(int numbers[]); void print(int *numbers);

Передадим в функцию массив:

#include void print(int[]); int main() < int nums[] ; print(nums); > void print(int numbers[]) < std::cout 

В данном случае функция print выводит на консоль первый элемент массива.

Теперь определим параметр как указатель:

#include void print(int*); int main() < int nums[] ; print(nums); > void print(int *numbers)

Здесь также в функцию передается массив, однако параметр представляет указатель на первый элемент массива.

Ограничения

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

void print(int numbers[]) < int size = sizeof(numbers) / sizeof(numbers[0]); // или так // size_t size = std::size(nums); std::cout

И также мы не сможем использовать цикл for для перебора этого массива:

void print(int numbers[])

Передача маркера конца массива

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

Первый подход заключается в том, чтобы один из элементов массива сам сигнализировал о его окончании. В частности, массив символов может представлять строку - набор символов, который завершается нулевым символом '\0'. Фактически нулевой символ служит признком окончания символьного массива:

#include void print(char[]); int main() < char chars[] ; print(chars); > void print(char chars[]) < for (unsigned i<>; chars[i] != '\0'; i++) < std::cout >

Однако при таком подходе мы должны быть уверены, что массив содержит такой подобный признак завершения. И если бы в данном случае нулевого байта не оказалось бы в строке, то это привело бы к неприятным последствиям. Поэтому обычно применяется другой подход, который заключается в передаче в функцию размера массива:

#include void print(int[], size_t); int main() < int nums[]; size_t n ; print(nums, n); > void print(int numbers[], size_t n) < for(size_t i <>; i < n; i++) < std::cout >

Третий подход заключается в передаче указателя на конец массива. Можно вручную вычислять указатель на конец массива. А можно использовать встроенные библиотечные функции std::begin() и std::end() :

int nums[] < 1, 2, 3, 4, 5 >; int *begin ; // указатель на начало массива int *end ; // указатель на конец массива

Причем end возвращает указатель не на последний элемент, а адрес за последним элементом в массиве.

Применим данные функции:

#include void print(int*, int*); int main() < int nums[] < 1, 2, 3, 4, 5 >; int *begin ; int *end ; print(begin, end); > void print(int *begin, int *end) < for (int *ptr ; ptr != end; ptr++) < std::cout >

Константные массивы

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

#include void print(const int*, const size_t); void twice(int*, const size_t); int main() < int numbers[]; size_t n = std::size(numbers); print(numbers, n); twice(numbers, n); // увеличиваем элементы массива в два раза print(numbers, n); > void print(const int numbers[], const size_t n) < for(size_t i <>; i < n; i++) < std::cout std::cout void twice(int *numbers, const size_t n) < for(size_t i <>; i < n; i++) < numbers[i] = numbers[i] * 2; >>

В данном случае функция print просто выводит значения из массива, поэтому параметры этой функции помечаются как константные.

Функция twice изменяет элементы массива - увеличивает их в два раза, поэтому в этой функции параметр-массив является неконстантным. Причем поле выполнения функции twice массив numbers будет изменен.

Консольный вывод программы:

1 2 3 4 5 2 4 6 8 10

Передача массив по ссылке

Еще один сценарий передачи массива в функцию представляет передача массива по ссылке. Прототип функции, которая принимает массив по ссылке, выглядит следующим образом:

void print(int (&)[]);

Обратите внимание на скобки в записи (&) . Они указывают именно на то, что массив передается по ссылке. Пример использования:

#include void print(int (&)[], size_t); int main() < int nums[] ; size_t count = std::size(nums); print(nums, count); > void print(int (&numbers)[], size_t count) < for(size_t i<>; i < count; i++) < std::cout >

Подобным образом можпо передавать константные ссылки на массивы.

void print(const int (&)[]);

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

#include void print(const int (&)[5]); // массив строго с 5 элементами int main() < int nums1[] ; print(nums1); > void print(const int (&numbers)[5]) < for(unsigned i<>; i < 5; i++) < std::cout >

Здесь функция print принимает ссылку строго на массив с 5 элементами. И поскольку мы знаем точный размер массива, то нам нет необходимости передавать в функцию дополнительно размер массива.

Если же мы попробуем передать в функцию массив с другим количеством элементов, то на этапе компиляции мы столкнемся с ошибкой, как, например, в следующем случае:

int nums2[] ; print(nums2); // ! Ошибка - в массиве nums2 6 элементов

Передача многомерного массива

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

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

void print(int (*numbers)[3]);

Здесь предполагается, что передаваемый массив будет двухмерным, и все его подмассивы будут иметь по 3 элемента. Стоит обратить внимание на скобки вокруг имени параметра, которые и позволяют определить параметр как указатель на массив. И от этой ситуации стоит отличать следующую:

void print(int *numbers[3])

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

Рассмотрим применение указателя на массив в качестве параметра:

#include void print(const int(*)[3], const size_t); int main() < int table[][3] < , , >; // количество строк или подмассивов size_t rowsCount ; print(table, rowsCount); > void print(const int (*rows)[3], const size_t rowsCount) < // количество столбцов или элементов в каждом подмассиве size_t columnsCount ; for(size_t i<>; i < rowsCount; i++) < for (size_t j<>; j < columnsCount; j++) < std::cout std::cout >

В функции main определяется двухмерный массив - он состоит из трех подмассивов. Каждый подмассив имеет по три элемента.

В функцию print вместе с массивом передается и число строк - по сути число подмассивов. В самой функции print получаем количество элементов в каждом подмассиве и с помощью двух циклов перебираем все элементы. С помощью выражения rows[0] можно обратиться к первому подмассиву в двухмерном массиве, а с помощью выражения rows[0][0] - к первому элементу первого подмассива. И таким образом, манипулируя индексами можно перебрать весь двухмерный массив.

В итоге мы получим следующий консольный вывод:

1 2 3 4 5 6 7 8 9

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

#include void print(const int[][3], const size_t); int main() < int table[][3] < , , >; // количество строк или подмассивов size_t rowsCount ; print(table, rowsCount); > void print(const int rows[][3], const size_t rowsCount) < // количество столбцов или элементов в каждом подмассиве size_t columnsCount ; for( size_t i<>; i < rowsCount; i++) < for (size_t j<>; j < columnsCount; j++) < std::cout std::cout >

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

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