Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Передача статического одномерного массива определённого размера в функцию

#cpp #массивы


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

#include 
void 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, то ошибка будет выдаваться во время компиляции. template void 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



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

Комментариев нет:

Отправить комментарий