
- •«Технология программирования»
- •«Функции», «Перегрузка и шаблоны функций»
- •Самара 2007
- •Лабораторная работа №7 функции
- •Краткие сведения из теории
- •Описание лабораторной установки и по
- •Указания к выполнению работы
- •Задание 3. Рекурсивные функции
- •Контрольные вопросы
- •Лабораторная работа №8 перегрузка и шаблоны функций
- •Краткие сведения из теории
- •Указания к выполнению работы
- •Контрольные вопросы
- •Приборы и программное обеспечение
- •Содержание отчета
- •Библиографический список
Министерство Транспорта Российской Федерации
Федеральное агентство железнодорожного транспорта
Государственное образовательное учреждение высшего профессионального образования
СамарскИЙ государственнЫЙ УНИВЕРСИСТЕТ путей сообщения
Кафедра информационных систем и телекоммуникаций
«Технология программирования»
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
к выполнению лабораторных работ
«Функции», «Перегрузка и шаблоны функций»
для студентов специальности 230201
очной и заочной форм обучения
Составитель: Е.А. Часовских
Самара 2007
УДК 004.422.834 + 004.422.635
Технология программирования: методические указания к выполнению лабораторных работ «Функции» и «Перегрузка и шаблоны функций» для студентов специальности 230201 очной и заочной форм обучения [Текст] / составитель: Е.А. Часовских. – Самара: СамГУПС, 2007. - 26 с.
Утверждены на заседании кафедры 4 октября 2007г., протокол № 2.
Печатается по решению редакционно-издательского совета университета.
Приведены методические указания по выполнению лабораторных работ «Функции» и «Перегрузка и шаблоны функций» по дисциплине «Технология программирования» для студентов дневной и заочной форм обучения по специальности 230201 «Информационные системы и технологии», а также студентам других специальностей, аспирантам и преподавателям для самостоятельного изучения и получения практических навыков работы по созданию программ на языке С++.
В методических указаниях в краткой форме содержатся основные теоретические сведения по работе с функциями, приведены примеры программ с использованием перегрузки функций, а также написание программ, в которой решение задачи оформлено в виде шаблона функций.
Составитель: Часовских Евгений Анатольевич
Рецензенты: кандидат педагогических наук, доцент кафедры
«Информатика» СамГУПС Буркин В.В.
кандидат технических наук, доцент кафедры «Информационные системы
и технологии» ПГАТИ Овсянников А.С.
Редактор:
Компьютерная верстка:
Подписано в печать Формат 60х90 1/16.
Бумага писчая. Печать оперативная. Усл. п.л.
Тираж экз. Заказ № .
© Самарский государственный университет путей сообщения, 2007
Лабораторная работа №7 функции
Цель работы: изучить основы работы с функциями и практически освоить написание программы, решение задачи в которой оформлено в виде функции.
Краткие сведения из теории
Функция – это группа операторов, выполняющая законченное действие. К функции можно обратиться по имени, передать ей значения и получить из нее результат.
Функции нужны для упрощения структуры программы. Разбив задачу на подзадачи и оформив каждую из них в виде функций, мы поступаем по принципу, известному еще с древних времен: «Разделяй и властвуй». Передача в функцию различных аргументов позволяет, записав ее один раз, использовать многократно для разных данных. Чтобы использовать функцию, не требуется знать, как она работает – достаточно знать, как ее вызвать. Точно так же мы включаем телевизор или пользуемся стоп-краном в самолете. Страшно подумать, сколько информации пришлось бы держать в голове, если бы требовалось в деталях знать устройство всех приборов, которые мы ежедневно применяем! В реальной жизни мы успешно ограничиваемся знанием интерфейса, то есть правил обращения (и общения).
Для использования функции тоже требуется знать только ее интерфейс. Интерфейс грамотно написанной функции определяется ее заголовком, потому что в нем указывается все, что необходимо для ее вызова: имя функции, тип результата, который она возвращает, а также сколько аргументов и какого типа ей нужно передать.
Формат простейшего заголовка (прототипа) функции:
тип имя ([ список_параметров ]);
В квадратных скобках записано то, что может быть опущено. Например, заголовок функции main обычно имеет вид:
int main();
Это означает, что никаких параметров этой функции извне не передается, а возвращает она одно значение типа int (код завершения). Функция может и не возвращать никакого значения, в этом случае должен быть указан тип void. Вот, к примеру, заголовок стандартной библиотечной функции, вычисляющей синус угла:
double sin(double);
Здесь записано, что функция имеет имя sin, вычисляет значение синуса типа double, и для этого нужно передать ей аргумент типа dauble. А вот заголовок функции копирующей блок памяти длиной n байтов, начиная с адреса src, по адресу dest:
void *memcpy(void *dest, const void *src, size_t n);
Эта функция возвращает указатель неопределенного типа на начало области памяти, в которую выполнялось копирование. Какой именно смысл имеет каждый из параметров функции, описывается в документации на функцию. Имена параметров при записи прототипа функции имеют чисто декоративное значение, то есть они могут понадобиться нам, а не компилятору, поэтому их можно опускать:
void *memcpy(void *, const void *, size_t);
Неграмотно написанная функция наряду с аргументами использует и глобальные переменные, которые, как вам известно, доступны из любого блока текущего файла1. Поскольку это никак не отражается на заголовке, для использования такой функции требуется исследовать и ее текст. Представьте, что прежде чем позвонить по телефону, вам нужно было бы разобрать его и рассмотреть все внутренности, чтобы убедиться, что красный проводочек не подключен к взрывному устройству! Надеемся, что этот устрашающий пример сразу убедит вас не использовать в функциях глобальные переменные.
ВНИМАНИЕ: Все, что передается в функцию и обратно, должно отражаться в ее заголовке. Это требование не синтаксиса, а хорошего стиля.
Заголовок задает объявление функции. Определение функции, кроме заголовка, включает ее тело, то есть те операторы, которые выполняются при вызове функции, например:
int sumdnt а, int b) { // функция находит сумму двух значений return а + b; // тело функции
}
В тексте программы может содержаться произвольное количество объявлений одной и той же функции и только одно определение (в этом функции не отличаются от других программных объектов). Тело функции представляет собой блок, заключенный в фигурные скобки. Для возврата результата, вычисленного в функции, служит оператор return. После него указывается выражение, результат вычисления которого и передается в точку вызова функции. Результат при необходимости преобразуется по общим правилам к типу, указанному в заголовке. Функция может иметь несколько операторов возврата, это определяется алгоритмом.
Для того чтобы вызвать функцию, надо указать ее имя (тут прослеживается полная аналогия с реальной жизнью, например, «Ихтиандр!» или «Леопольд!»), а также передать ей набор аргументов в соответствии с указанным в ее заголовке. Соответствие должно соблюдаться строго, и это естественно: ведь если в заголовке функции указано, сколько величин и какого типа ей требуется для успешной работы, значит, надо их ей передать. Если мясоперерабатывающий конвейер рассчитан на то, что на вход поступает корова, а на выходе получается колбаса, трудно рассчитывать на колбасу, подав на вход даже самый современный автомобиль.
Вызов функции, возвращающей значение определенного типа (то есть не имеющей тип void), может быть записан в любом месте, где по синтаксису допустимо выражение – в правой части оператора присваивания, в составе выражения, в цепочке вывода и так далее. Вот, например, как можно вызвать функции, приведенные выше:
double у, x1 = 0.34, х2 = 2;
у = sin(x1);
cout << у << ' ' << sin(x2) << endl;
у = sin(x1 + 0.5) - sin(x1 - 0.5);
char *cite = "Never say never";
char b[100];
memcpy(b, cite, strlen(cite) + 1);
int summa, a = 2;
summa = sum(a, 4);
ВНИМАНИЕ: В определении, в объявлении и при вызове одной и той же функции типы и порядок следования параметров должны совпадать. Для имен параметров никакого соответствия не требуется.
Многофайловые проекты
До сих пор мы писали программы, исходный текст которых размещался в одном файле. Однако реальные задачи требуют создания многофайловых проектов с распределением решаемых подзадач по разным модулям (файлам).
ПРИМЕЧАНИЕ: Описанные в приложениях интегрированные среды Visual C++ 6.0 и Borland C++З.1, как и подавляющее большинство других, поддерживают создание, компиляцию и сборку многофайловых проектов. С технологией их создания вы можете ознакомиться по приложениям, а здесь мы рассмотрим вопросы, связанные с распределением функций по модулям, разделением интерфейса и реализации и особенностями использования глобальных переменных.
Напомним, что пользуясь технологией нисходящего проектирования программ, мы разбиваем исходную задачу на подзадачи, затем при необходимости каждая из них также разбивается на подзадачи, и так далее, пока решение очередной подзадачи не окажется достаточно простым, то есть реализуемым в виде функции обозримого размера (как уже указывалось, наиболее предпочтительным считается размер не более одного-двух экранов текстового редактора).
Исходные тексты совокупности функций для решения какой-либо подзадачи, как правило, размещаются в отдельном модуле (файле). Такой файл называют исходным (source file). Обычно он имеет расширение .с или .срр. Прототипы всех функций исходного файла выносят в отдельный так называемый заголовочный файл (header file), для него принято использовать расширение .h или .hpp.
Таким образом, заголовочный файл ххх.h содержит интерфейс для некоторого набора функций, а исходный файл ххх. срр содержит реализацию этого набора. Если некоторая функция из указанного набора вызывается из какого-то другого исходного модуля ууу.срр, то вы обязаны включить в этот модуль заголовочный файл ххх.h с помощью директивы #include2. Негласное правило стиля программирования на C++ требует включения этого же заголовочного файла (с помощью #include) и в исходный файл ххх.срр.
Теперь о глобальных переменных. В многофайловом проекте возможны два «вида глобальности». Если некоторая глобальная переменная glvar1 объявлена в файле ххх.срр с модификатором static, то она видима от точки определения до конца этого файла, то есть область ее видимости ограничена файлом. Если же другая глобальная переменная glvar2 объявлена в файле ххх.срр без модификатора statiс, то она может быть видимой в пределах всего проекта. Правда, для того, чтобы она оказалась видимой в другом файле, необходимо иметь в этом файле ее объявление с модификатором extern (рекомендуется это объявление поместить в файл ххх.h).
В заголовочном файле принято размещать:
определения типов, задаваемых пользователем, констант, шаблонов;
объявления (прототипы) функций;
объявления внешних глобальных переменных (с модификатором extern);
пространства имен.
Теперь обратим ваше внимание на проблему повторного включения заголовочных файлов. Проблема может возникнуть при иерархическом проектировании структур данных, когда в некоторый заголовочный файл ууу.h включается при помощи директивы #include другой заголовочный файл ххх.h (например, для использования типов, определенных в этом файле).
Каков выход из этой ситуации? Бьерн Страуструп рекомендует использовать так называемые стражи включения, и этот способ нашел широкое применение. Он состоит в следующем: чтобы предотвратить повторное включение заголовочных файлов, содержимое каждого .h-файла должно находиться между директивами условной компиляции #ifndef и #endif.
Теперь, когда мы получили общее представление о назначении и правилах записи функций, перейдем к рассмотрению заданий.