Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ИС / Лабораторные работы / Лабораторная работа#7

.pdf
Скачиваний:
76
Добавлен:
22.03.2015
Размер:
443.7 Кб
Скачать

Лабораторная работа № 7

ОРГАНИЗАЦИЯ ПРОГРАММ С ИСПОЛЬЗОВАНИЕМ ФУНКЦИЙ.

Цель занятия

1.Приобретение навыков составления программ с использованием функций.

2.Получение дополнительной практики программирования алгоритмов обработки массивов.

Постановка задачи

1.Для заданного варианта алгоритм обработки массива оформить в виде процедуры или функции.

2.Написать программу на языке C++, ввести, отладить и выполнить ее на ЭВМ для нескольких наборов исходных данных.

Содержание отчета

1.Постановка задачи для конкретного варианта.

2.Алгоритм решения задачи.

3.Текст программы и результаты выполнения.

Методические указания

Функции.

Большинство компьютерных программ, решающих реальные практические задачи, намного превышают те программы, которые были представлены в первых главах. Экспериментально показано, что наилучшим способом создания и поддержки больших программ является их конструирование из маленьких фрагментов, или модулей, каждый из которых более управляем, чем сложная программа.

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

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

Каждая функция в языке C++ имеет три составных части:

1.Прототип функции. Прототип функции является одной из наиболее важных особенностей C++. Прототип функции указывает компилятору тип данных, возвращаемых функцией, количество параметров, которое ожидает функция, тип параметров и ожидаемый порядок их следования. Компилятор использует прототип функции для проверки правильности вызовов функции. Вызов функции, который не соответствует прототипу функции, ведет к синтаксической ошибке. Синтаксическая ошибка возникает также в случае отсутствия согласования между прототипом и описанием функции. Другой важной особенностью прототипов функций является приведение типов аргументов, т.е. задание аргументам подходящего типа. Например, математическая библиотечная функция sqrt может быть вызвана

саргументом целого типа, даже если функция прототип в math.h определяет аргумент типа double, и при этом функция будет работать правильно. Правила приведения определяют, как типы могут быть преобразованы в другие типы без потерь. Тип int автоматически преобразуется в double без изменения его значений. Однако double преобразуется в int с отбрасыванием дробной части значения double. Преобразование больших целых типов в малые целые типы (например, long в short) может также привести к изменению значений.

2.Определения функций

Формат описания функции имеет вид: тип-возвращаемого-значения имя-функции (список-параметров) {объявления и операторы} Имя-функции – это любой правильно написанный идентификатор.

Тип-возвращаемого-значения – это тип данных результата, возвращаемого из функции оператору ее вызова. Тип возвращаемого значения void указывает, что функция не возвращает никакого значения.

Компилятор предполагает тип int для неопределенного типа возвращаемого значения. Список-параметров – это список разделенных запятыми объявлений тех параметров, которые

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

Объявления и операторы внутри фигурных скобок образуют тело функции. Тело функции рассматривается как блок. Блок – это просто составной оператор, который включает объявления. Переменные могут быть объявлены в любом блоке, а блоки могут быть вложенными. При любых обстоятельствах функция не может быть описана внутри другой функции.

3.Вызов функции. Функция вызывается указанием имени функции и правильного списка параметров. Существует два способа возврата управления к точке, из которой была вызвана функция. Если функция не должна возвращать результат, управление возвращается или просто при достижении правой фигурной скобки, завершающей функцию, или при выполнении оператора return. Если функция должна возвращать результат, то оператор return выражение; возвращает значение выражения в обращение к функции.

Каждая программа, которую мы рассматривали, содержала функцию, называемую main, которая вызывает стандартные библиотечные функции для выполнения соответствующих им задач. Теперь мы рассмотрим, как программисты пишут свои собственные необходимые им функции. Рассмотрим программу, которая использует функцию square для вычисления квадратов целых чисел.

#include<iostream.h> int square (int); main( )

{

int x;

cout << "Input x "; cin >> x;

cout << "x^2=" << square(x) << endl; system("PAUSE");

return 0;

}

int square (int a)

{

int y=a*a; return y;

}

Функция square активизируется или вызывается в main вызовом square(x).

Функция создает копию значения x в параметре a. Затем square вычисляет y=a*a. Значение переменной y передается в ту точку main, из которой была вызвана square, и затем этот результат выводится на экран.

Описание square показывает, что эта функция ожидает передачи в нее целого параметра. Ключевое слово int, предшествующее имени функции, указывает, что square возвращает целый результат. Оператор return в square передает результат вычислений обратно в вызывающую функцию.

Функции с пустыми списками параметров

В C++ пустой список параметров определяют, либо записывая void, либо совсем ничего не записывая в круглых скобках. Объявление

void print ( ) ;

указывает, что функция print не требует никаких аргументов и не возвращает значений.

Роль пустого списка параметров функции в C++ существенно отличается от C. В C это означает, что все проверки аргументов отсутствуют (т.е. вызов функции может передать любой аргумент, который требуется). А в C++ пустой список означает отсутствие аргументов. Таким образом, программа на C, использующая эту особенность, может сообщить о синтаксической ошибке при компиляции в

C++.

Встраиваемые функции

Реализация программы как набора функций хороша с точки зрения разработки программного обеспечения, но вызовы функций, приводят к накладным расходам во время выполнения. В C++ для снижения этих накладных расходов на вызовы функций – особенно небольших функций – предусмотрены встраиваемые (inline) функции. Спецификация inline перед указанием типа результата в объявлении функции «советует» компилятору сгенерировать копию кода функции в соответствующем месте, чтобы избежать вызова этой функции. В результате получается множество копий кода функции, вставленных в программу, вместо единственной копии, которой передается управление при каждом вызове функции. Компилятор может игнорировать спецификацию inline и обычно так и делает для всех функций, кроме самых малых.

//Использование встраиваемой функции для расчета объема куба

#include <iostream.h>

inline float square(const float a) {return a*a;} main()

{

float x;

cout << "Input x "; cin >> x;

cout << "x^2=" << square(x) << endl; system("PAUSE");

return 0;

}

Аргументы по умолчанию

Обычно при вызове функций в нее передается конкретное значение каждого аргумента. Но программист может указать, что аргумент является аргументом по умолчанию и приписать этому аргументу значение по умолчанию. Если аргумент по умолчанию не указан в вызове функции, то в вызов автоматически передается значение этого аргумента по умолчанию. Аргументы по умолчанию должны быть самыми правыми (последними) аргументами в списке параметров функции. Если вызывается функция с двумя или более аргументами по умолчанию и если пропущенный аргумент не является самым правым в списке аргументов, то все аргументы справа от пропущенного тоже пропускаются. Аргументы по умолчанию должны быть указаны при первом упоминании имени функции – обычно в прототипе. Значения по умолчанию могут быть константами, глобальными переменными или вызовами функций. Аргументы по умолчанию можно использовать также с функциями inline.

#include <iostream.h>

inline int boxVolume(int length = 1, int width=1, int height = 1) { return length * width * height; }

main ( )

{

cout << " Объем параллелепипеда по умолчанию равен: " << boxVolume() << endl <<"Объем параллелепипеда с длиной 10, шириной 1 и высотой 1 равен:"

<<boxVolume(10) << endl

<<"Объем параллелепипеда с длиной 10, шириной 5 и высотой 1 равен: "

<<boxVolume(10,5) << endl

<<" Объем параллелепипеда с длиной 10, шириной 5 и высотой 2 равен:"

<<boxVolume(10,5,2) endl;

return 0;

}

Всем трем аргументам было дано значение по умолчанию 1. В первом вызове встроенной функции boxVolume не указаны аргументы, поэтому используются все три значения по умолчанию. Во втором вызове передается аргумент length, поэтому используются значения по умолчанию аргументов width и height. В третьем вызове передаются аргументы width и height, поэтому используется значение по

умолчанию аргумента height. В последнем вызове передаются аргументы length, width и height, поэтому значения по умолчанию не используются ни для одного аргумента.

Заголовочные файлы

Каждая стандартная библиотека имеет соответствующий заголовочный файл, содержащий прототипы всех функций библиотеки и объявления различных типов данных и констант, которые используются этими функциям. В таблице в алфавитном порядке перечислены заголовочные файлы стандартной библиотеки С ANSI/ISO, которые можно включать в программы на C++.

Программист может сам создавать требующиеся ему заголовочные файлы. Заголовочные файлы, определяемые программистом, также должны иметь расширение .h. Заголовочные файлы, определяемые программистом, могут быть включены с помощью директивы препроцессора #include. Например, заголовочный файл square.h может быть включен в нашу программу директивой #include "square.h" в начале программы.

Заголовочныйфайл

 

стандартной

Объяснение

библиотеки

 

<assert.h>

Содержит макросы и информацию для дополнительной диагностики,

помогающей при отладке программы.

 

 

Содержит прототипы функций, проверяющих некоторые свойства

<ctype.h>

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

 

преобразования строчных букв в заглавные и обратно.

<errno.h>

Определяет макросы, полезные для получения сообщений об ошибках.

<float.h>

Содержит ограничения на числа с плавающей запятой в системе.

<limits.h>

Содержит общие ограничения системы.

 

Содержит прототипы функций и другую информацию, которая позволяет

 

модифицировать программу в зависимости от места ее выполнения.

<locale.h>

Позволяет компьютерной системе в зависимости от географического места

выполнения программы применять различные соглашения относительно

 

 

формы представления таких данных, как даты, время, долларовые расчеты

 

и большие числа в различных регионах мира.

<math.h>

Содержит прототипы математических библиотечных функций.

<setjmp.h>

Содержит прототипы функций, которые позволяют обходить обычную

последовательность вызова функции и возврата из нее.

 

<signal.h>

Содержит прототипы функций и макросы для обработки различных

ситуаций, которые могут возникнуть во время выполнения программы.

 

<stdarg.h>

Определяет макросы для работы со списком аргументов функции при

неизвестном количестве и типе аргументов.

 

<stddef,h>

Содержит объявления типов, используемых для выполнения некоторых

вычислений.

 

<stdio.h>

Содержит прототипы стандартных библиотечных функций ввода-вывода и

используемую ими информацию.

 

 

Содержит прототипы функций, преобразующих числа в текст и текст в

<stdlib.h>

числа, ведающих выделением памяти, генерирующих случайные числа и

 

осуществляющих другие полезные операции.

<string.h>

Содержит прототипы функций, обрабатывающих строки.

<time.h>

Содержит прототипы функций и типы для работы с временем и датами.

Передача массивов в функции

Чтобы передать массив в качестве аргумента в функцию, укажите имя массива без каких-либо квадратных скобок. Например, если массив hourlyTemperatures объявлен как

int hourlyTemperatures[24];

то оператор вызова функции modifyArray(hourlyTemperatures, 24);

передает массив hourlyTemperatures и его размер функции modifyArray.

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

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

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

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

void modifyArray(int b[ ], int arraySize)

указывая, что modifyArray ожидает принятия массива целых чисел в параметре b, и количество элементов массива в параметре arraySize. Размер массива в квадратных скобках указывать не нужно. Если он включен, компилятор его проигнорирует. Поскольку массивы передаются моделируемым вызовом по ссылке, то вызываемая функция, используя имя массива b, в действительности будет работать с истинным массивом в источнике вызова (массив hourlyTemperatures в предыдущем вызове). В главе 5 мы познакомимся с другими формами записи, указывающими, что функция принимает массив. Как мы увидим, эти записи основаны на тесных связях между массивами и указателями.

Отметим необычный вид прототипа функции для modifyArray void modifyArray (int [ ], int);

Этот прототип мог бы быть записан в виде

void modifyArray (int anyArrayName[ ], int anyVariableName)

но, компиляторы C++ игнорируют имена переменных в прототипах.

Напомним, что прототип сообщает компилятору количество аргументов и типы каждого аргумента (в порядке их ожидаемого появления).

Рекурсия

Программы, которые мы обсуждали до сих пор, в общем случае состояли из функций, которые вызывали какие-либо другие функции в строгой иерархической манере. В некоторых случаях полезно иметь функции, которые вызывают сами себя. Рекурсивная функция – это функция, которая вызывает сама себя либо непосредственно, либо косвенно с помощью другой функции.

Сначала мы рассмотрим понятие рекурсии, а затем проанализируем несколько программ, содержащих рекурсивные функции. Рекурсивная задача в общем случае разбивается на ряд этапов. Для решения задачи вызывается рекурсивная функция. Эта функция знает, как решать только простейшую часть задачи – так называемую базовую задачу (или несколько таких задач). Если эта функция вызывается для решения базовой задачи, она просто возвращает результат. Если функция вызывается для решения более сложной задачи, она делит эту задачу на две части: одну часть, которую функция умеет решать, и другую, которую функция решать не умеет. Чтобы сделать рекурсию выполнимой, последняя часть должна быть похожа на исходную задачу, но быть по сравнению с ней несколько проще или несколько меньше. Поскольку эта новая задача подобна исходной, функция вызывает новую копию самой себя, чтобы начать работать над меньшей проблемой – это называется рекурсивным вызовом, или шагом рекурсии. Шаг рекурсии включает ключевое слово return, так как в дальнейшем его результат будет объединен с той частью задачи, которую функция умеет решать, и сформируется конечный результат, который будет передан обратно в исходное место вызова, возможно, в main.

Шаг рекурсии выполняется до тех пор, пока исходное обращение к функции не закрыто, т.е. пока еще не закончено выполнение функции. Шаг рекурсии может приводить к большому числу таких рекурсивных вызовов, поскольку функция продолжает деление каждой новой подзадачи на две части. Чтобы завершить процесс рекурсии, каждый раз, как функции вызывает саму себя с несколько

упрощенной версией исходной задачи, должна формироваться последовательность все меньших и меньших задач, в конце концов сходящаяся к базовой задаче. В этот момент функция распознает базовую задачу, возвращает результат предыдущей копии функции и последовательность возвратов повторяет весь путь назад, пока не дойдет до первоначального вызова и не возвратит конечный результат в функцию main. Все это звучит довольно экзотично по сравнению с традиционным решением задач, которое мы рассматривали до сих пор. Как пример работы данной концепции, рассмотрим рекурсивную программу для выполнения одного распространенного математического расчета.

Факториал неотрицательного целого числа n, записываемый как n!, равен

! = ∙( −1) ∙( − 2)∙ …∙1

причем считается, что 1!=1 и 0!=1.

Например, 5! вычисляется как 5×4×3×2×1 и равен 120 Рекурсивное определение функции факториал дается следующим соотношением: п!=п×(п-1)! Например, факториал 5! очевидно равен 5x4!. В самом деле:

5!= 5×4×3×2×1 5!= 5×(4×3×2×1) 5!=5×4!

Вычисление 5! должно происходить в соответствии с рисунком. Рис а) показывает, как протекает последовательность рекурсивных вызовов до тех пор, пока не будет вычислен 1! = 1, что приведет к завершению рекурсии. Рис б) показывает значения, возвращаемые из каждого рекурсивного вызова оператору вызова до тех пор, пока не будет вычислено и возвращено окончательное значение.

5!

5!

 

5!=5×24=120 возвращается

5×4!

5×4!

 

4!=4×6=24 возвращается

4×3!

4×3!

 

3!=3×2=6 возвращается

3×2!

3×2!

 

2!=2×1=2 возвращается

2×1!

2×1!

 

1 возвращено

1!

1!

а) Процесс рекурсивных вызовов

б) Значения, возвращаемые после каждого

 

рекурсивного вызова.

#include<iostream.h> int factorial (int); main ( )

{

int n, f;

setlocale(LC_ALL, "Russian");

cout<<"Ввести число для вычисления факториала"<<endl; cin>>n;

f=factorial(n);

cout<<n<<"!="<<f<<endl;

system("PAUSE"); return 0;

}

int factorial (int x)

{

int y;

if (x==1) y=1; else y=x*factorial(x-1) ; return y;

}

Перегрузка функций

C++ позволяет определить несколько функций с одним и тем же именем, если эти функции имеют разные наборы параметров (по меньшей мере, разные типы параметров). Эта особенность называется перегрузкой функции. При вызове перегруженной функции компилятор C++ определяет соответствующую функцию путем анализа количества, типов и порядка следования аргументов в вызове. Перегрузка функции обычно используется для создания нескольких функций с одинаковым именем, предназначенных для выполнения сходных задач, но с разными типами данных.

Впримере перегруженная функция square используется для расчета квадрата переменной типа int

иквадрата переменной типа double.

#include <iostream.h>

inline int square (int x){return x*x;}

inline double square (double y){return y*y;}

inline void square (char z) {cout << "This is impossible"<< endl;} main ()

{

cout << "Square of integer = " << square(5)<< endl; cout << "Square of float = " << square(5.5)<< endl; cout << "Square of char = ";

square('A');

system("PAUSE"); return 0;

}

Перегруженные функции различаются с помощью их сигнатуры – комбинации имени функции и типов ее параметров. Компилятор кодирует идентификатор каждой функции по числу и типу ее параметров (иногда это называется декорированием имени), чтобы иметь возможность осуществлять надежное связывание типов. Надежное связывание типов гарантирует, что вызывается надлежащая функция и что аргументы согласуются с параметрами. Компилятор выявляет ошибки связывания и выдает сообщения о них.

Шаблоны функции

Перегруженные функции обычно используются для выполнения сходных операций над различными типами данных. Если операции идентичны для каждого типа, это можно выполнить более компактно и удобно, используя шаблоны функций – свойство, введенное в последней версии C++. Программист пишет единственное определение шаблона функции. Основываясь на типах аргументов, указанных в вызовах этой функции, C++ автоматически генерирует разные функции для соответствующей обработки каждого типа. Таким образом, определение единственного шаблона определяет целое семейство решений.

Все определения шаблона функции начинаются с ключевого слова template, за которым следует список формальных типов параметров функции, заключенный в угловые скобки (< и >). Каждый формальный тип параметра предваряется ключевым словом class. Формальные типы параметров – это встроенные типы или типы, определяемые пользователем. Они используются для задания типов аргументов функции, для задания типов возвращаемого значения функции и для объявления переменных внутри тела описания функции. После шаблона следует обычное описание функции.

#include <iostream.h> template <class T>

T square (T x) {return x*x;} main ()

{

cout << "Square of integer = " << square(5)<< endl;

cout << "Square of float = " << square(5.5)<< endl; system("PAUSE");

return 0;

}

Этот шаблон функции объявляет единственный формальный параметр T как тип данных, который должен проверяться функцией square. Когда компилятор обнаруживает вызов square в исходном коде программы, этот тип данных, переданных в square, подставляется вместо T всюду в определении шаблона и C++ создает законченную функцию для определения максимального из трех значений указанного типа данных. Затем заново созданная функция компилируется. Таким образом, шаблоны в действительности играют роль средств генерации кода.

Вызов функций по ссылке

Существуют три способа передачи аргументов в функцию:

вызов по значению;

вызов по ссылке с аргументами ссылками;

вызов по ссылке с аргументами указателями.

Вызов по значению. Когда аргумент передается вызовом по значению, создается копия аргумента и она передается вызываемой функции. Изменения копии не влияют на значение оригинала в операторе вызова. Это предотвращает случайный побочный эффект, который так сильно мешает развитию корректного и надежного программного обеспечения. Один из недостатков вызова по значению состоит в том, что если передается большой элемент данных, создание копии этих данных может привести к значительным потерям времени выполнения.

// Возведение переменной в куб с использованием вызова по значению

#include <iostream.h> int cubeByValue(int); main ( )

{

setlocale(LC_ALL, "Russian"); int number=5, volume;

cout << "Number="<< number << endl; volume=cubeByValue(number);

cout << "Number="<< number << endl; cout << "Volume="<< volume << endl; system("PAUSE");

return 0;

}

int cubeByValue(int n)

{

n=n*n*n; return n;

}

Вызов по ссылке. В случае вызова по ссылке оператор вызова дает вызываемой функции возможность прямого доступа к передаваемым данным, а также возможность изменения этих данных. Вызов по ссылке хорош в смысле производительности, потому что он исключает накладные расходы на копирование больших объемов данных, но вызов по ссылке может ослабить защищенность, потому что вызываемая функция может испортить передаваемые в нее данные.

Ссылочный параметр – это псевдоним соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, после типа параметра в прототипе функции ставится символ амперсанда (&); такое же обозначение используется в списке типов параметров в заголовке функции. Например, объявление

int &count

в заголовке функции может читаться как «count является ссылкой на int». В вызове функции достаточно указать имя переменной, и она будет передана по ссылке. Тогда упоминание в теле

вызываемой функции переменной по имени ее параметра в действительности является обращением к исходной переменной в вызывающей функции, и эта исходная переменная может быть изменена непосредственно вызываемой функцией.

#include <iostream.h> void cubeByRef(int &); main ( )

{

setlocale(LC_ALL, "Russian"); int number=5;

cout << "Number="<< number << endl; cubeByRef(number);

cout << "Number="<< number << endl; cout << "Volume="<< number << endl; system("PAUSE");

return 0;

}

int cubeByRef(int &n)

{

n=n*n*n;

}

Вызов по указателю. Указатели, подобно ссылкам, тоже можно использовать для модификации одного или более значений переменных в вызывающем операторе, или передавать указатели на большие объекты данных, чтобы избежать накладных расходов, сопутствующих передаче объектов по значению.

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

(&)переменной, которая должна быть модифицирована.

//Возведение переменной в куб с использованием вызова по ссылке с аргументом указателем

#include <iostream.h> void cubeByPtr(int *); main ( )

{

setlocale(LC_ALL, "Russian"); int number=5;

cout << "Number="<< number << endl; cubeByPtr(&number);

cout << "Number="<< number << endl; cout << "Volume="<< number << endl; system("PAUSE");

return 0;

}

void cubeByPtr(int *nPtr)

{

*nPtr=*nPtr * *nPtr * *nPtr;

}

Функция, принимающая адрес в качестве аргумента, должна определить параметр как указатель, чтобы принять адрес. Например, заголовок функции cubeByPtr имеет вид

void cubeByPtr(int *nPtr)

Этот заголовок указывает, что функция cubeByPtr принимает адрес целой переменной как аргумент, сохраняет адрес локально в nPtr и не возвращает значение.

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

В заголовке функции и в прототипе функции, которая ожидает в качестве аргумента одномерный массив, можно использовать запись указателя в списке параметров функции. Компилятор не делает различий между функцией, которая принимает указатель, и функцией, которая принимает одномерный массив. Это означает, конечно, что функция должна «знать», принимает ли она массив или просто одну переменную, для которой выполняется передача вызовом по ссылке. Когда компилятор сталкивается с параметром функции в виде одномерного массива, например, int b[ ], он преобразует параметр в запись указателя int * const b. Обе формы объявления параметра функции как одномерного массива равнозначны.

Массивы не передаются с использованием операции &, потому что имя массива – это начальный адрес массива в памяти. При передаче функции адреса переменной может использоваться операция косвенной адресации (*) для модификации значения (если значение не объявлено как const) ячейки в памяти вызывающего оператора.

Пример программы. Заданы три массива Х(4), Y(3) и Z(5). Требуется, упорядочить по возрастанию числа а,b,с, которые представляют собой соответственно минимальные элементы массивов X, Y, Z. Вызов функций осуществляется по имени массива и по указателю на первый элемент массива.

Алгоритм решения данной задачи может выглядеть следующим образом:

Подпрограмма поиска минимального элемента

Подпрограмма ввода элементов массива vvod

Вход в

 

подпрограмму

 

min=a[1]

 

 

Вход в

i=0(1)…N

подпрограмму

-

i=0(1)…N

A[i]<min

 

+

Ввод

 

min=a[i]

массива

 

Возврат min

Выход из

подпрограммы

Основная программа