#cpp #массивы
Я хочу передать в функцию статический массив определённого размера, который будет проверяться при компиляции. #includevoid print(int arr[3]) { std::cout << sizeof(arr) << '\n'; //выводит 4 при каждом вызове for (int i = 0; i < 3; i++) { std::cout << arr[i] << ' '; } std::cout << '\n'; } int main() { int staticArr2[2] = {8, 5}; int staticArr3[3] = {2, 4, 7}; std::cout << sizeof(staticArr2) << '\n'; //выводит 8 std::cout << sizeof(staticArr3) << '\n'; //выводит 12 print(staticArr2); // выводит 3 элемент, указывающий на память вне массива // хочется чтобы не компилировалось print(staticArr3); // ок return 0; } Но вот конструкция int arr[3] воспринимается как int * в объявлении входных параметров функции. Подскажите, как можно реализовать передачу массива конкретного размера.
Ответы
Ответ 1
Можно воспользоваться шаблонами для того, чтобы передавать массив как массив, а не как указатель. При таком вызове сохраняется информация о размере массива. Если дополнить код вызовом static_assert, то ошибка будет выдаваться во время компиляции. templatevoid print(int (&arr)[N]) { static_assert(N == 3, "Array must contain 3 elements"); // Проверка выполняется // во время компиляции std::cout << N << ' ' << sizeof(arr) << '\n'; // Размер вычисляется корректно for (int i = 0; i < 3; i++) { std::cout << arr[i] << ' '; } std::cout << '\n'; } При попытке передать массив из двух элементов будет выведена ошибка: prog.cpp: In instantiation of 'void print(int (&)[N]) [with unsigned int N = 2u]': prog.cpp:22:21: required from here prog.cpp:6:2: error: static assertion failed: Array must contain 3 elements static_assert(N == 3, "Array must contain 3 elements"); ^ Ответ 2
Конкретный размер передается отдельным параметром. В функцию надо передавать два параметра: ссылку на первый элемент массива (это имя массива без квадратных скобок размерность массива.Ответ 3
можно завернуть массив в структуру и передавать экземпляр структуры в качестве аргумента функции: struct Array3 { int items[3]; }; void print(struct Array3 arr) { // code here }Ответ 4
А Вы надеялись увидеть 12? С т.з. языка аргумент функции, хоть и описывающий массив с указанием размера все равно является указалем. И ведь на самом же деле в функцию в стеке (или в некоторых архитектурах в одном из регистров) передается указатель, который в 32-bit системах имеет размер 4 байта (которые Вы и видите на печати). Причем, даже в gcc, который "на самом деле понимает" размеры массивов (точнее низшие размерности многомерных массивов), например, вот такой код -- int f (int m, int n, int a[m][n]) { printf("n = %d a[n] = %ld\n", n, (long)sizeof(a)); int i, j; for (i = 0; i < m; i++) for (j = 0; j < n || !puts(""); j++) printf("%d ", a[i][j]); // обратите внимание он (компайлер) в самом деле учитывает количество элементов в строке матрицы!!! return 0; } int main (int ac, char *av[]) { static int c[2][5] = { {1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}}; f(2, 5, c); } все равно sizeof(a) выдает 4.Ответ 5
Если нужно разрешать только определенную размерность, имхо, ей и стоит ограничиться. Т.е. не городить шаблонов со ссылками и static_assert внутри, а явно сделать функцию, принимающую сущность, максимально близкую сырому массиву, но являющуюся при этом объектом первого класса. Такой сущностью, в частности, является std::array. Пример: #include#include constexpr int size = 3; void f(const std::array & a) { for(int e : a) { std::cout << e << ' '; } std::cout << '\n'; } int main() { std::array a {1,2,3}; f(a); f({4,5,6}); } Ответ 6
Передавайте вторым аргументом размер массива. Если хотите, чтобы при определенном размере не компилировалось, в функции проверяйте размер и выкидывайте исключение.
Комментариев нет:
Отправить комментарий