Как передаются массивы разных размеров в функцию?
Вопрос довольно тривиальный, и есть множество ответов на данный вопрос. И поверьте я прочитал очень много по этому вопросу. Я могу скопировать решение для моего конкретного случая, но моя голова взрывается, потому что я не могу систематизировать знания и из-за этого не могу двигаться вперёд.
Меня не совсем интересует поиск "совета как сделать", мне нужно чтобы подтвердили/опровергли/дополнили мою картину мира по вопросу "передача массива в функцию".
И так что я знаю на данный момент:
// ОДНОМЕРНЫЙ МАССИВ
по значению с определенным размером
Функция: void func(int massive[10]){}
Вызов в программе: func(massive);
по значению с неопределенным размером
Функция: void func(int massive[], int massiveSize){}
Вызов в программе: func(myMassive, 10);
по ссылке c определенным размером
Функция: void func(int (&massive)[10]){}
Вызов в программе: func(myMassive);
по ссылке c определенным размером
Функция: void func(int (&massive)[], int massiveSize){}
Вызов в программе: func(myMassive, 10);
по указателю с неопределенным размером (при этом если внутри функции будем мерить sizeof() указателя, то получим размер 4 байта - одного int
Функция: void func(int *massive, massiveSize){};
Вызов в программе: func(&myMassive,10);
// ДВУМЕРНЫЙ МАССИВ
по значению с определенным размером
Функция: void func(int massive[5][10]){}
Вызов в программе: func(myMassive);
по значению с неопределенным размером - но мы должны указать размерность второго измерения, то есть кол-во столбцов
Функция: void func( int massive[][10],int sizeRows){}
Вызов в программе: func(myMassive, 5);
по ссылке с неопределенным размером
Функция: void func(int& (*massive)[],int sizeRows, sizeCollums){}
Вызов в программе:
rows = sizeof(massive)/sizeof(*massive);
collums = sizeof(massive[0])/sizeof(massive[0][0]);
func (massive, rows,collums);
по ссылке с определенным размером
Функция: void func(int& (*massive[5])[10]){}
Вызов в программе: func(myMassive);
по указателю на первый элемент
Функция: void func(int* (&massive), sizeRows, sizeCollums){};
Вызов в программе:
rows = sizeof(massive)/sizeof(*massive);
collums = sizeof(massive[0])/sizeof(massive[0][0]);
func( (int*)massive, rows,collums);
// ТРЁХМЕРНЫЙ МАССИВ
по указателю на первый элемент, больше рабочего кода для себя я не нашёл
Функция: void func(int* (&massive), sizeDimension1, sizeDimension2,sizeDimension3){};
Вызов в программе:
dimension1 = sizeof(massive)/sizeof(*massive);
dimension2 = sizeof(massive[0])/sizeof(massive[0][0]);
dimension3 = sizeof(massive[0][0])/sizeof(massive[0][0][0]);
func( (int*)massive, dimension1,dimension2,dimension3);
Бонусный вопрос, как панчлайн к шутке:
А есть ли смысл, что я вообще так сильно запариваюсь с массивами?
Потому что я пока не приступил к изучению и освоению всех контейнеров из STL, насколько я понимаю, то в данном случае просто проще начать пользоваться контейнером array.
Ответы (1 шт):
Одномерные массивы
- Получение размера массива: для этого есть специальная функция в стандартной библиотеке. Типичная ошибка использовать для этих целей
sizeof
.
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [10];
int main()
{
items_t items{};
::std::size_t items_count{::std::size(items)}; // 10
}
- Передача указателя на первый элемент массива и размера массива: работает с массивами конкретного размера и неопределенного размера. Указатель потенциально может быть нулевым. Ответственность за указание правильного размера лежит на вызывающей стороне. Создание временного объекта с типом указателя на первый элемент массива из объекта с типом массива языком допускается даже неявное.
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [10];
void func(item_t * p_items, ::std::size_t items_count)
{}
int main()
{
items_t items{};
// то же самое func(static_cast<item_t *>(items), ::std::size(items));
// то же самое func(::std::addressof(items[0]), ::std::size(items));
func(items, ::std::size(items));
}
- Передача массива конкретного размера по значению: языком не поддерживается. При указании массива в качестве типа аргумента тип будет заменен компилятором на указатель на элемент массива. По сути получается как при передаче указателя на первый элемент, но без указания размера.
#include <type_traits>
using item_t = int;
using items_t = item_t [10];
void func(items_t items)
{
static_assert(::std::is_same_v<item_t *, decltype(items)>);
}
Так как передается указатель, то узнать размер массива внутри функции нельзя, а при передаче можно передвать нулевой указатель и размер не проверяется:
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [10];
void func(items_t items)
{
::std::size_t items_count{::std::size(items)}; // error
}
int main()
{
func(nullptr); // компилятору все равно
item_t small[5]{};
func(small); // компилятору все равно
}
- Передача массива неопределенного размера по значению: языком не поддерживается. При указании массива в качестве типа аргумента тип будет заменен компилятором на указатель на элемент массива. По сути получается как при передаче указателя на первый элемент, но без указания размера.
#include <type_traits>
using item_t = int;
using items_t = item_t [];
void func(items_t items)
{
static_assert(::std::is_same_v<item_t *, decltype(items)>);
}
Узнать размер массива внутри функции нельзя, а при передаче можно передавать нулевой указатель:
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [];
void func(items_t items)
{
::std::size_t items_count{::std::size(items)}; // error
}
int main()
{
func(nullptr); // компилятору все равно
}
- Передача массива конкретного размера по ссылке: работает без проблем. Внутри функции можно получить размер массива, а при вызове компилятор отловит попытки передать массив другого размера или нулевой указатель.
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [10];
void func(items_t & items)
{
::std::size_t items_count{::std::size(items)}; // 10
}
int main()
{
items_t items{};
func(items); // OK
func(nullptr); // error
item_t small[5]{};
func(small); // error
}
- Передача массива неопределенного размера по ссылке: возможно, но бесполезно. Внутри функции получить размер массива нельзя, а при вызове компилятор отловит попытки передать нулевой указатель.
#include <iterator>
#include <cstddef>
using item_t = int;
using items_t = item_t [];
void func(items_t & items)
{
::std::size_t items_count{::std::size(items)}; // error
}
int main()
{
item_t items[10];
func(items); // OK
func(nullptr); // error
item_t small[5]{};
func(small); // OK
}
- Передача массива конкретного размера по указателю: работает без проблем. Внутри функции можно получить размер массива, а при вызове компилятор отловит попытки передать массив другого размера.
#include <iterator>
#include <memory>
#include <cstddef>
using item_t = int;
using items_t = item_t [10];
void func(items_t * p_items)
{
::std::size_t items_count{::std::size(*p_items)}; // 10
}
int main()
{
items_t items{};
func(::std::addressof(items)); // OK
func(nullptr); // OK
item_t small[5]{};
func(::std::addressof(small)); // error
}
- Передача массива неопределенного размера по указателю: возможно, но еще более бесполезно, чем по ссылке. Внутри функции получить размер массива нельзя. При вызове ничего не проверяется.
#include <iterator>
#include <memory>
#include <cstddef>
using item_t = int;
using items_t = item_t [];
void func(items_t * p_items)
{
::std::size_t items_count{::std::size(*p_items)}; // error
}
int main()
{
item_t items[10];
func(::std::addressof(items)); // OK
func(nullptr); // OK
item_t small[5]{};
func(::std::addressof(small)); // OK
}
Двумерные массивы
- Являются одномерными массивами, элементами которых являются другие массивы. Так что к ним приминимо все из предыдущего раздела.
using item_t = int [10];
using items_t = item_t [10];
А еще в языке есть
- Обертка для массивов
::std::array
, позволяющая передавать массивы по значению, которые следует всегда использовать вместо c-style массивов. - Проекции массивов
::std::span
илиarray_view
, хранящие указатель на первый элемент и размер.