Передача в функцию одномерного массива
Использование массива как параметра функции не вызывает ни каких трудностей. Как было сказано ранее, массив в подпрограмму всегда передаётся по адресу, поэтому достаточно при вызове функции указать адрес начала массива или адрес того элемента, начиная с которого предполагается обрабатывать массив.
Пример. Написать программу, которая будет вызывать функцию для вывода на печать элементов массива.
Возможный вариант решения:
#include <iostream>
using namespace std;
void print(int x[], int n);
int main()
{
const int n = 5;
int x[n] = {3, 5, 1 ,7, 4};
print(x, n);
return 0;
}
void print(int x[], int n)
{
cout << "Massiv:" << endl;
for(int i = 0; i < n; i++)
cout << x[i] << endl;
}
При вызове функции оператором
print(x, n);
в неё передаётся адрес начала массива x и количество элементов n. Количество элементов n передаётся по значению и здесь всё должно быть понятно, но вот с передачей самого массива может быть некоторое непонимание, которое необходимо устранить.
Итак, массив в функцию должен передаваться по адресу, и нам необходим в подпрограмме весь массив, поэтому логично вызов функции записать так:
print(&x[0], n);
С учётом того, что массив в подпрограмму чаще всего передаётся весь и с начала, разработчики языка запись вида &x[0] сократили до x, т.е. обращение к массиву по имени эквивалентно обращению по адресу к элементу с индексом 0.
В заголовке функции
void print(int x[], int n) // 1-й вариант
два формальных параметра. Запись x[] говорит о том, что в подпрограмму передаётся именно массив.
Заголовок может выглядеть и так:
void print(int *x, int n) // 2-й вариант
Массив передаётся по адресу, поэтому и записываем первый параметр как адрес на объект типа int. Этот объект-указатель принимает адрес того элемента массива, который вычисляется в вызывающей функции (например, в main()).
Какую форму использовать? Это дело вкуса. Компилятор рассматривает 1-й вариант как эквивалент 2-го, хотя для человека нагляднее именно 1-й вариант. По нему видно, что формальный параметр — это именно массив, а не указатель, например, на одиночный элемент.
Трактовка при вызове x как &x[0] позволяет при необходимости передать в подпрограмму не весь массив, а только его часть, начиная с какого-либо адреса. Например, вызов
print(&x[2], n - 2);
приводит к выводу на экран монитора трёх элементов массива, начиная с элемента с индексом 2. При этом сама функция не требует каких либо доработок. В этом плане языки С/С++ гораздо удобнее многих других языков. Так, в Паскале или Бейсике пришлось бы передавать в подпрограмму ещё один параметр — номер элемента, с которого необходимо начать обработку массива, а затем этот номер использовать в операторе цикла.
Многомерные массивы как параметры функций
Для многомерных массивов (имеются ввиду массивы трёхмерные, четырёхмерные и так далее, т.е. с размерностью более двух) мы имеем те же проблемы, что и для матриц. Если передавать, к примеру, обычный трёхмерный массив в подпрограмму, то прототип функции может выглядеть так:
// Прототип функции печати трёхмерного массива
void Print(int V[][N][M], int k, int n, int m);
Здесь необходимы уже две константы: N и M. Недостатки такой функции те же, что и при передачи в подпрограмму матрицы, т.е. отсутствие универсальности.
Решение проблемы — так же в использовании динамических массивов:
// Прототип функции печати трёхмерного динамического массива
void Print(int ***V, int k, int n, int m);
Универсальность достигнута, но в ущерб скорости работы программы.