Передача одномерного массива в функцию
Когда речь идет о простых переменных, то передача аргументов в функцию копированием в формальные параметры не создает проблем.
Но, когда в функцию нужно передать массив, то копирование может потребовать большого объема действий и значительного объема дополнительной памяти для хранения копии массива. Это нерационально, поэтому авторами языка Си было решено, что передача массива в функцию должна выполняется иначе, чем для простых переменных.
В задании 1 формальный параметр в виде указателя позволял работать внутри функции непосредственно с объектом, определенным в вызывающей функции. Эту идею можно распространить на массивы.
А именно, если в функцию передается адрес первого элемента массива, то в функции можно будет получить доступ ко всем его элементам, т.е работать напрямую с массивом. В этом случае при передаче массива достаточно будет скопировать только один указатель.
Тип формального параметра
Пример. В программе определены одномерный массив arr типа int и функция f. Массив необходимо передать в функцию, чтобы она обработала его элементы.
Так как имя одномерного массива — это указатель на его начало, то для передачи массива в функцию достаточно указать имя массива (только имя массива, без всяких квадратных скобок!). Например,
f(arr);
Очевидно, что соответствующий формальный параметр функции должен иметь тип указателя на базовый тип массива.
void f(int *a){…}
Исходя из этого определения, фактический параметр в вызове f не обязан быть именем массива. Т.е. функции можно передать любой указатель на базовый тип. Например, можно передать указатель не на первый, а на любой другой элемент массива.
Формальный параметр является обычным указателем, а значит не обладает способностью имени массива хранить размер выделенной для массива памяти.
В результате внутри функции размер переданного одномерного массива с помощью sizeof вычислить нельзя. Поэтому при передаче массива в функцию обычно требуется добавить дополнительный аргумент, через который функции сообщается размер массива.
Замечание
Эти рассуждения можно обобщить на случай массивов любой размерности: при передаче массива в функцию информация о его первом (левом) размере теряется.
ЗАДАНИЕ 2 (анализ размеров объектов)
1. Даны массив arr типа int и указатель pa:
int arr[]={1,2,3,4,5};
int* pa=arr;
Написать программу, в которой с помощью операции sizeof вычисляются и выводятся на экран размеры объектов arr и pa с поясняющим текстом Massiv и Ukazatel.
Объяснить результаты работы программы.
2. В программу добавить функцию с прототипом void size_of_arg(int* a). В этой функции вычисляется и выводится на экран размер переменной a.
В main поместить два вызова функции size_of_arg. Первый раз передать ей имя массива arr, а второй раз — указатель pa.
Перед выводом результатов на экран должен быть выведен поясняющий текст, соответственно, Peredan massiv и Peredan ukazatel.
Объяснить результаты работы программы.
Альтернативный синтаксис для задания типа аргумента-массива
Чтобы повысить самодокументируемость программ (подчеркнуть, что по смыслу программы аргументом функции является массив) в Си предлагается второй способ описания аргументов-массивов:
void f(int a[]);
Это еще один пример "синтаксического сахара", т.е. более удобный для восприятия способ записи. Различия с void f(int *a); чисто внешние. Встретив определение аргумента в виде int a[], компилятор заменит его на int *a.
Независимо от синтаксиса при передаче в функцию размер фактического массива будет утерян.
Замечание
Не будет синтаксической ошибкой, если в квадратных скобках указать размер массива — void f(int a[12]). Однако с практической точки зрения для одномерного массива это бесполезно, так как размер учитываться никак не будет.
ЗАДАНИЕ 3 (передача одномерного массива)
1. В функции main определяется и инициализируется массив из нескольких чисел типа double.
В программе после функции main определяется функция total, которой передается одномерный массив типа double, и количество элементов в нём.
Функция суммирует элементы этого массива и возвращает полученный результат.
Количество элементов массива вычисляется в функции main с помощью операции sizeof. Затем осуществляется вызов total.
Функция main выводит на экран:
а) подсчитанное количество элементов в массиве,
б) значение полученной суммы чисел.
Чтобы использовать total в main нужно в начале программе указать прототип total.
2. Чтобы убедиться, что компилятор две синтаксические формы определения типа формального параметра воспринимает как одну, использовать в прототипе функции и в её определении разный синтаксис задания типа аргумента.
