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

Вид материалаЛабораторная работа

Содержание


Лабораторная работа № 14
Практические задания
Лексические основы языка с++
Общие сведения
_bp _ds _flags
Практические задания
Лабораторная работа № 16
Практические задания
Библиографический список
Подобный материал:
1   2   3   4   5   6
Лабораторная работа № 14

СОСТАВНЫЕ ТИПЫ ДАННЫХ. ПРАВИЛА ОБЪЯВЛЕНИЯ, ИНИЦИАЛИЗАЦИИ И РАБОТЫ С СОСТАВНЫМИ ТИПАМИ ДАННЫХ

Цель: Изучить основные общие правила работы с составными типами данных.


Общие сведения


Массив – это совокупность однородных объектов, имеющая общее имя I-идентификатор массива. Другими словами, все элементы массива являются объектами одного и того же типа. Это не всегда удобно. Пусть, например, библиотечная (библиографическая) карточка каталога должна включать сведения, которые приведены для книг в списке литературы, помещенном в конце нашей книги. Таким образом, для каждой книги будет указываться следующая информация:

• фамилия и инициалы автора;

• заглавие книги;

• место издания;

• издательство;

• год издания;

• количество страниц.

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


struct card { char * author; // Ф.И.О. автора книги

char * title; // Заголовок книги

char *city; // Место издания

char *finn; // Издательство

int year; // Год издания

int pages; // Количество страниц.


Если структура определяется однократно, т. е. нет необходимости в разных частях программы определять или описывать одинаковые по внутреннему составу структурированные объекты, то можно не вводить именованный структурный тип, а непосредственно определять структуры одновременно с определением их компонентного состава. Следующий оператор определяет две структуры с именами XX, YY, массив структур с именем ЕЕ и указатель pst на структуру:


struct { char N[12]; int value; } XX, YY, EE[8], *pst;


В XX,YY и в каждый элемент массива EE[0],..., EE[7] входят в качестве элементов массив char N[12] и целая переменная value. Имени у соответствующего структурного типа нет. Для обращения к объектам, входящим в качестве элементов в контурную структуру, чаще всего используются уточненные имена. Общей формой уточненного имени элемента структуры является следующая конструкция: имя структуры, имя элемента структуры. Например, для определенной выше структуры YY оператор YY. value =86; присвоит переменной value значение 86.

Для ввода значения переменной value структуры EE[4] можно использовать оператор cin » ЕЕ[4].value;


69
Точно так можно вывести в выходной поток cout значение переменной из любой структуры. Другими словами, элемент структуры обладает правами объекта того типа, который указан в конструкции (в определении) структурного типа.

Например, для переменных с именем value из структур EE[0],..., EE[7], XX, YY определен тип int. При определении структур возможна их инициализация, т. е. задание начальных значений их элементов. Например, введя структурный тип card, можно определить и инициализировать конкретную структуру:


card dictionary = ( "Hornby A.S.", "Oxford students\

dictionary of Current English", "Oxford",

"Oxford University", 1984, 769);


Такое определение эквивалентно следующей последовательности операторов:


card dictionary;

dictionary.author = "Hornby A.S.";

dictionary.title =

"Oxford students dictionary of Current English" ;

dictionary.city = "Oxford";

dictionary.firm = "Oxford University";

dictionary.year = 1984;

dictionary.pages = 769;


Нужно еще раз обратить внимание на отличие имени конкретной структуры (в наших примерах dictionary, ree1, rac2, rec3, XX, YY, EE [0],..., EE [7]) от имени структурного типа (в нашем случае card).

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

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

Например, после наших определений структурного типа card и структуры rec2 можно так записать определение указателя на структуру типа card: card *ptrcard = &rec2;

Здесь определен указатель ptrcard и ему с помощью инициализации присвоено значение адреса одной из конкретных структур типа card.


Практические задания:


Составить макет данных и написать программу для ввода и реализации печати введенных данных для следующих документов:


1. График выполнения проекта

- ------------------------------------------------

| № п/п | Ф.И.О. | Дата | % выполнения |

- ------------------------------------------------


2. Список литературы

- ----------------------------------------------------------

| № п/п | Уч. дисциплина | Литература | Автор |

- ----------------------------------------------------------


3. Платежная ведомость за электроэнергию

-------------------------------------------------------------------------------------------

| Ф.И.О.| Расход электроэнергии | Стоимость | 1кВт/ч | Сумма к оплате |

-------------------------------------------------------------------------------------------

4. Зачетная ведомость

- ----------------------------------------------------------------------------

| № п/п | Ф.И.О. | Отметка о зачете | Подпись преподавателя |

- ----------------------------------------------------------------------------


5. Ведомость защиты лабораторных работ

- --------------------------------------------------------------------------------------------

| № п/п | Группа | Ф.И.О. | № лаб. работы | Дата | Подпись преподавателя |

- --------------------------------------------------------------------------------------------


6. График защиты дипломных проектов

- ----------------------------------------------------------

| № п/п | Ф.И.О. | Тема проекта | № ГЭК | Дата |

- ----------------------------------------------------------


7. Карта трудовой дисциплины ФЭТ

- -----------------------------------------------------------------

| | Количество пропущенных часов |

| Номер группы |---------------------------------------------|

| | Всего | По н/у | Лекций |


8. График защиты курсовых работ

- ------------------------------------------------------------------

| № п/п | Ф.И.О. | Тема проекта | Руководитель | Дата |

- ------------------------------------------------------------------


9. График дежурства по вахте общежития

- --------------------------------------------

| № п/п | № комнаты | Ф.И.О. | Дата |

- --------------------------------------------


10. Платежная ведомость

- -------------------------------------------------------

| № п/п | Ф.И.О. | Сумма к выдаче | Подпись |

- -------------------------------------------------------


11. График отпусков

- ---------------------------------------------------------------------------

| № п/п | Ф.И.О. | Начало отпуска | Конец отпуска | Подпись |

- ---------------------------------------------------------------------------


12. Требования к материалам

- ------------------------------------------------------------------------

| № п/п | Наименование материала | Кол-во | Дата выдачи |

- ------------------------------------------------------------------------


21

13. График сдачи ГТО

- ---------------------------------------------------

| № п/п | Отдел | Вид спорта | Дата сдачи |

- ---------------------------------------------------


14. Список путевок на курортное лечение

- -----------------------------------------------------------------------------------------------

| № п/п | Назв. курорта | Показания для лечения | Срок путевки | Стоимость |

- -----------------------------------------------------------------------------------------------


15. План выпуска учебно-методической документации

------------------------------------------------------------------------------------------------

| № п/п | Наим. мероприятия | Объем в листах | Тираж в экземплярах | Дата |

------------------------------------------------------------------------------------------------


16. План мероприятий НИР

- ------------------------------------------------------------------------------

| № п/п | Наим. мероприятия | Исполнитель | Срок исполнения |

- ------------------------------------------------------------------------------


17. Численность работников отдела

- --------------------------------------------------------------------------

| № п/п | Должность | План | Факт | % к предыдущему году |

- --------------------------------------------------------------------------


18. Список абитуриентов, зачисленных в ХГТУ

- ---------------------------------------------------------------------------------------------

| № п/п | Факультет | Специальность | Общий балл | Категория зачисления |

- ---------------------------------------------------------------------------------------------


19. Расход материалов за сутки

- -----------------------------------------------------------------------------------------

| № п/п | Наименование материала | Единица измерения | Расход | Дата |

- -----------------------------------------------------------------------------------------


20. Список студентов групп

- -------------------------------------------------------------------------------------------

| № п/п | Ф.И.О. | Домашний адрес | Общественное поручение | Возраст |

---------------------------------------------------------------------------------------------


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

ЛЕКСИЧЕСКИЕ ОСНОВЫ ЯЗЫКА С++

Цель: Получить общие сведения о лексемах, алфавите,

идентификаторах, служебных словах, константах и знаках

операций, используемых в языке С++.


Общие сведения


Основная программная единица на языке Си++ – это текстовый файл с названием <имя>.срр, где срр – принятое расширение для программ на Си++, а имя выбирается достаточно произвольно. Для удобства ссылок и сопоставления программ с их внешними именами целесообразно помещать в начале текста каждой программы строку комментария с именем файла, в котором она находится. Текстовый файл с программой на Си++ вначале обрабатывает препроцессор, который распознает команды (директивы) препроцессора (каждая такая команда начинается с символа ‘#’) и выполняет их. В приведенных выше программах использованы препроцессорные команды #include <имя включаемого файла>


19
Выполняя препроцессорные директивы, препроцессор изменяет исходный текст программы. Команда #include вставляет в программу заранее подготовленные тексты из включаемых файлов. Сформированный таким образом измененный текст программы поступает на компиляцию. Компилятор, во-первых, выделяет из поступившего к нему текста программы лексические элементы, т. е. лексемы, а затем на основе грамматики языка распознает смысловые конструкции языка (выражения, определения, описания, операторы и т. д.), построенные из этих лексем. Фазы работы компилятора здесь рассматривать нет необходимости. Важно только отметить, что в результате работы компилятора формируется объектный модуль программы.

Алфавит и лексемы языка СИ++.

В алфавит языка Си++ входят:

· прописные и строчные буквы латинского алфавита;

· цифры 0,1, 2, 3, 4, 5, 6, 7, 8, 9;

· специальные знаки:

“ { } , | [ ] ( ) + – / % | ; ‘ : ? < = > _ ! & # ~ . *

Из символов алфавита формируются лексемы языка:

· идентификаторы;

· ключевые (служебные, или зарезервированные) слова;

· константы;

· знаки операций;

· разделители (знаки пунктуации).

Рассмотрим эти лексические элементы языка подробнее.

Прописные и строчные буквы различаются. Таким образом, в этом примере два первых идентификатора различны. На длину различаемой части идентификатора конкретные реализации накладывают ограничение. Компиляторы фирмы Borland различают не более 32 первых символов любого идентификатора. Некоторые реализации Си++ на ЭВМ типа VAX допускают идентификаторы длиной до 8 символов.

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

Ключевые слова Си++:


Asm Double New Switch

Auto Else Operator Template

Break Enua Private This

Case Extern Protected Throw

Catch Float Public Try

Char For Register Typedef

Class Friend Return Typeid

Const Goto Short Union

Continue If Signed Unsigned

Default Inline Sizeof Virtual

Delete Int Static Void

Do Long Struct Volatile

While


Ранее в языке Си++ был зарезервирован в качестве ключевого слова идентификатор overload. Для компиляторов фирмы Borland (ВС++ и ТС++) дополнительно введены ключевые слова:


cdecl _export

_loadds saveregs

_cs far

near _seg

_ds huge

pascal _ss

_es interrupt

_regparam


Там же введены как служебные слова регистровые переменные:


_АН _ВН _СН

_DH _SI _SP

_SS _AL _BI

_CL _DL _DI

_CS _ES _AX

_BX _CX _DX

_BP _DS _FLAGS


Отметим, что ранние версии ВС++ и ТС++ не включали в качестве ключевых слов идентификаторы throw, try, typeid, catch.

Не все из перечисленных служебных слов сразу же необходимы программисту, однако их запрещено использовать в качестве произвольно выбираемых имен, и список служебных слов нужно иметь уже на начальном этапе знакомства с языком Си++. Кроме того, идентификаторы, включающие два подряд символа подчеркивания (_), резервируются для реализации Си++ и стандартных библиотек. Идентификаторы, начинающиеся с символа подчеркивания (_), используются в реализациях языка Си. В связи с этим начинать выбираемые пользователем идентификаторы с символа подчеркивания и использовать в них два подряд символа подчеркивания не рекомендуется.

Константа (литерал) – это лексема, представляющая изображение фиксированного числового, строкового или символьного (литерного) значения.

Константы делятся на пять групп: целые, вещественные (с плавающей точкой), перечислимые, символьные (литерные) и строковые (строки или литерные строки). Перечислимые константы проект стандарта языка Си++ относит к одному из целочисленных типов.

Компилятор, выделив константу в качестве лексемы, относит её к той или другой группе, а внутри группы – к тому или иному типу данных по ее "внешнему виду" (по форме записи) в исходном тексте и по числовому значению.

Целые константы могут быть десятичными, восьмеричными и шестнадцатеричными.

Вещественные константы, т. е. константы с плавающей точкой, даже не отличаясь от целых констант по значению, имеют другую форму внутреннего представления в ЭВМ. Эта форма требует использования арифметики с плавающей точкой при операциях с такими константами. Поэтому компилятор должен уметь распознавать вещественные константы. Распознает он их по внешним признакам. Константа с плавающей точкой может включать следующие семь частей: целая часть (десятичная целая константа); десятичную точку; дробную часть (десятичная целая константа); признак (символ) экспоненты е или в; показатель десятичной степени (десятичная целая константа, возможно со знаком); суффикс F (или f) либо L (или l).

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

Например: 66. .0 .12 3.14159F 1.12е-2 2E+6L 2.71

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


enum { one=1, two=2, three=3 };


Символьные (литерные) константы – это один или два символа, заключенные в апострофы. Односимвольные константы имеют стандартный тип char. Для представления их значений могут вводиться переменные символьного типа, т. е. типа char. Примеры констант: ‘z’, ‘*’, ‘\12’, ‘\0’, ‘\n’ – односимвольные константы, ‘db’,‘\х07\х07’, ‘\n\t’ – двухсимвольные константы. В этих примерах заслуживают внимания последовательности, начинающиеся со знака ‘\’. Символ обратной косой черты ‘\’ используется, во-первых, при записи кодов, не имеющих графического изображения, и, во-вторых, символов: апостроф (‘), обратная косая черта (\), знак вопроса (?) и кавычки (“). Кроме того, обратная косая черта позволяет вводить символьные константы, явно задавая их коды в восьмеричном или шестнадцатеричном виде. Последовательности литер, начинающиеся со знака ‘\’, называют эскейп-последовательностями. Знаки операций обеспечивают формирование и последующее вычисление выражений. Выражение – есть правило для получения значения. Один и тот же знак операции может употребляться в различных выражениях и по-разному интерпретироваться в зависимости от контекста. Для изображения операций в большинстве случаев используется несколько символов. В ANSI-стандарте языка Си++ определены следующие знаки операций:


[] () . -> ++ --

& * + - ~ sizeof

! / % << >> <

> <= >= ++ !=

| && || ?: = *=

/= %= += –= <<= >>=

&= = |= , # ##


Дополнительно к перечисленным в Си++ введены:


:: .* –>* new delete typeid


За исключением операций [], () и ?: все знаки операций распознаются компилятором как отдельные лексемы. В зависимости от контекста одна и та же лексема может обозначать разные операции. Например, бинарная операция & – это поразрядная конъюнкция, а унарная операция & – это операция получения адреса.


Практические задания


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


2. Показать участки памяти, выделяемые для вещественных констант разного типа.


3. Определить размер памяти в байтах, выделяемый для операнда.


4. Вывести слово с помощью символьных констант.


5. Вывести 3 строки с использованием эскейп-последовательностей.


6. Склеить несколько строк в одну.


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


8. Определить размер в байтах для разных типов данных.


9. Проиллюстрировать возможности унарных операций.


10. Проиллюстрировать возможности аддитивных операций.


11. Проиллюстрировать возможности мультипликативных операций.


12. Проиллюстрировать возможности операций сдвига.


13. Проиллюстрировать возможности поразрядных операций.


14. Проиллюстрировать возможности операций отношения (сравнения).


15. Проиллюстрировать возможности логических бинарных операций.


16. Проиллюстрировать возможности операций присваивания.


17. Проиллюстрировать возможности операций выбора компонентов структурного объекта.


18. Проиллюстрировать возможности условных операций.


19. Проиллюстрировать возможности операций явного преобразования (приведения) типа.


20. Проиллюстрировать возможности операций new и delete для динамического распределения памяти.


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

ФУНКЦИИ, УКАЗАТЕЛИ, ССЫЛКИ

Цель: Изучить определения, описания и вызовы функций,

указателей и ссылок на функции.


Общие сведения


Если в таких языках как Алгол, Фортран, ПЛ/1, Паскаль и др. делается различие между программами, подпрограммами, процедурами, функциями, то в языке Си++ и в его предшественнике – языке Си – используются только функции.

При программировании на языке Си++ функция – это основное понятие, без которого невозможно обойтись. Во-первых, каждая программа обязательно должна включать единственную функцию с именем main (главная функция). Именно функция main обеспечивает создание точки входа в откомпилированную программу. Кроме функции с именем main, в программу может входить произвольное количество неглавных функций, выполнение которых инициируется прямо или опосредованно вызовами из функции main. Всем именам функций программы по умолчанию присваивается класс памяти extern, т. е. каждая функция имеет внешний тип компоновки и статическую продолжительность существования. Как объект с классом памяти extern, каждая функция глобальна, т. е. при определенных условиях доступна в модуле и даже во всех модулях программы. Для доступности в модуле функция должна быть в нем определена или описана до первого вызова.


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

В языках Си и Си++ допустимы функции, количество параметров у которых при компиляции определения функции не определено. Кроме того, могут быть неизвестными и типы параметров. Количество и типы параметров становятся известными только в момент вызова функции, когда явно задан список фактических параметров. При определении и описании таких функций, имеющих списки параметров неопределенной длины, спецификация формальных параметров заканчивается многоточием. Формат прототипа функции с переменным списком параметров:


тип имя (спецификация явных параметров, ...);


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


81
Для доступа к списку параметров используется указатель pik типа int *. Вначале ему присваивается адрес явно заданного параметра k, т. е. он устанавливается на начало списка параметров в памяти (в стеке). Затем в цикле указатель pik перемещается по адресам следующих фактических параметров, соответствующих неявным формальным параметрам. С помощью разыменования *pik выполняется выборка их значений. Параметром цикла суммирования служит аргумент k, значение которого уменьшается на 1 после каждой итерации и, наконец, становится нулевым. Особенность функции – возможность работы только с целочисленными фактическими параметрами, т. к. указатель pik после обработки значения очередного параметра "перемещается вперед" на величину sizeof(int) и должен быть всегда установлен на начало следующего параметра.

Следующий пример содержит функцию для вычисления произведения переменного количества параметров. Признаком окончания списка фактических параметров служит параметр с нулевым значением.


//индексация конца переменного списка параметров

#include

// Функция вычисляет произведение параметров:

double prod(double arg, ...)

{ double aa = 1.0; // Формируемое произведение

double *prt = farg; // Настроили указатель

// на первый параметр

if (*prt =я 0.0) return 0.0;

for (; *prt; prt++) aa *= *prt; void main()

{ long minimum(char г, int k, ...); // Прототип функции

cout « "\n\tminimum('l', 3, 10L, 20L, 30L) = " «

minimum('1',3,10L,20L,30L);

cout «"\n\tminimum('i', 4, 11, 2, 3, 4) = " «

minimumCi',4,11,2,3,4) ;

cout « "\n\tminimum(4c1, 2, 0, 64) = " «

minimum('k',2,0,64);

}

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

long minimum(char z, int k, ...) 'i')

{ int *pi = bk + 1; // Настроились на первый

// необязательный параметр

int min = *рi; // Значение первого

// необязательного параметра

for(; k; k--, pi++)

min = min > *pi ? *pi : min;

return (long)min;

}

if (z == ‘l’)

{ long *pl - (long*) (tlc+1) ;

long min = *pl; // Значение первого параметра

for (;k; k--, pi++) Bin »« ain > *pl ? *pl : min;

return (long)min;

}

cout « "\пОшибка! Неверно задан 1-й параметр:";

return 2222L;

}


Результат выполнения программы:


minimum('1', 310L, 20L, 30L) = 10

minimum(‘i’, 4, 11, 2, 3, 4) = 2

Ошибка! Неверно задан 1-й параметр:

minimum('k',2,0,64) = 2222


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


long fact(int k)

{ if (k < 0) return 0;

if (k == 0) return 1;

return k * fact(k-l); }


Для отрицательного аргумента результат по определению факториала не существует. В этом случае функция возвратит нулевое значение. Для нулевого параметра функция возвращает значение 1, т. к. по определению 0! равен 1. В противном случае вызывается та же функция с уменьшенным на 1 значением параметра и результат умножается на текущее значение параметра. Тем самым для положительного значения параметра k организуется вычисление произведения k * (k-l) * (k-2) *…*3*2*1*1.


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


тип функции (*имя указателя)(спецификация параметров);


Например: int (*func1Ptr)(char); – определение указателя funclptr на функцию с параметром типа char, возвращающую значение типа int.
  • постфиксное выражение.имя;
  • постфиксное выражение->имя;
  • постфиксное_выражение++;

Постфиксное выражение – прототип некой функции с именем fun и параметром типа char, возвращающей значение указателя типа int *.

Второй пример: char * (*func2Ptr) (char *,int); – определение указателя func2Ptr на функцию с параметрами типа указатель на char i и типа int, возвращающую значение типа указатель на char.

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

В качестве простейшей иллюстрации сказанного приведем программу с указателем на функцию.


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

#include // Для ввода-вывода

void fl(void) // Определение fl

{cout « "\nВыполняется f1()"; }

void f2(void) // Определение f2

{ cout « "\пВыполняется f2()"; }

void main()

{ void (*ptr) (void) ; // ptr – указатель на функции

ptr = f2; // Присваивается адрес f2()

(*ptr)(); // Вызов f2() по ее адресу

ptr = fl; // Присваивается адрес fl()

(*ptr)(); // Вызов fl0 no ее адресу

ptr(); // Вызов эквивалентен (*ptr)() ;

85
Результат выполнения программы:

Выполняется f2()

Выполняется f1()

Выполняется f1()


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

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


//массив указателей на функции

#include // Для exit()

#include // Для cout, cin

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

//обработки меню:

void act1(char* name)

{ cout « "Действия no созданию файла " « name; )

void act2(char* name)

( cout « "Действия по уничтожению файла " « name; )

void act3(char* name)

{cout « "Действия по чтению файла " « name; )

void act4(char* name)

{cout « "Действия по модификации файла " « name; }

void act5(char* name)

{ cout « "Действия по закрытию файла.";

exit(0); // Завершить программу

}

// Тип MENU указателей на

//функции типа void (char *):

typedef void(*MENU)(char *) ;

// Инициализация таблицы

//адресов функций меню:

MENU MenuAct[5] - ( acti, act2, act3, act4, act5 );

void main()

{ int number; // Номер выбранного пункта меню

char FileName[30]; // Строка для имени файла

cout « "\n 1 – создание файла"; cout « "\n 2 – уничтожение файла";

cout « "\n 3 – чтение файла";

cout « "\n 4 – модификация файла";

cout « "\n 5 – выход из программы";

while (1) // Бесконечный цикл

{ while (I)

{ // Цикл продолжается до

//ввода правильного номера

cout « "\n\nВведите номер пункта меню: ";

cin » number;

if (number >= 1 && number <= 5) break;

cout « "\nОшибка в номере пункта меню!";

} if (number != 5)

{ cout « "Введите имя файла: ";

cin » FileName; // Читать имя файла

}

// Вызов функции по указателю на нее:

(*ManuAct[number-l])(FileName) ;

}// Конец бесконечного цикла

}


При выполнении программы возможен, например, такой диалог:

1 – создание файла;

2 – уничтожение файла;

3 – чтение файла;

4 – модификация файла;

5 – выход из программы.


Введите номер пункта меню: 3

Введите имя файла: PROBA.TXT

Действия по чтению файла PROBA.TXT

. . .

Введите номер пункта меню: 5

Действия по закрытию файла.


В языке Си++ ссылка определена как другое имя уже существующего объекта. Основные достоинства ссылок проявляются при работе с функциями, однако ссылки могут использоваться и безотносительно к функциям. Для определения ссылки используется символ &, если он употребляется в types имя_ссылки инициализатор.

В соответствии с синтаксисом инициализатора, наличие которого обязательно, определение ссылки может быть таким:


type С имя_ссылки » выражение; или

types_имя ссылки (выражение);


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

Значением ссылки после определения с инициализацией становится адрес этого объекта. Примеры определений ссылок:


int L = 777; // Определена и инициализирована переменная L

int& RL = L; // Значением ссылки RL является адрес

// переменной L

int&6 RI(0); // Опасная инициализация – значением ссылки RI

// становится адрес об'ъекта, в котором

// временно размещено нулевое целое значение

В определении ссылки символ '&' не является частью типа, т. е. rl или ri имеют тип int и именно так должны восприниматься в программе.


Практические задания


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

  1. Написать функцию нахождения МАХ среди массива целых чисел. Найти МАХ в двух массивах разной длины.



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



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



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



  1. Написать функцию инвертирования строки символов. Инвертировать две строки.


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

  1. Написать функцию перевода целого числа в двоичное. Обработать три числа.



  1. Написать функцию перевода целого числа в восьмеричное. Обработать 3 числа.


9. Написать функцию перевода целого числа в шестнадцатеричное. Обработать 3 числа.

  1. Написать функцию замены всех русских символов в строке пробелами.

Ввести и обработать две смешанные строки.

  1. Написать функцию разделения русских и латинских букв в отдельные строки. Ввести и обработать две смешанные строки.


12. Написать функцию объединения двух строк в одну (вторая присваивается к концу первой). Объединить две строки, затем еще две.


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



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


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


16. Написать функцию выделения произвольной строки двумерного массива в одномерный. Выделить две произвольные строки.


17. Написать функцию умножения произвольного столбца двумерного массива на const. Умножить два столбца массива на разные константы.


18. Написать функцию повторения символа n раз. Ввести строку символов. Повторить символ трижды, вывести новую строку.


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


Библиографический список




  1. Подбельский В. В. Язык Си++. – М.: Финансы и статистика, 1995. –560 с.



  1. Романовская Л.М. Программирование в среде Си для ПЭВМ ЕС. – М.: Финансы и статистика, 1992. – 352 с.



  1. Информатика: Методические указания к лабораторным работам № 1–8 для студентов специальности 210100 «Управление и информатика в технических системах» / Сост. И. В. Кочетова – Издательство Хабаровского государственного технического университета, 1996. – 28 с.






Оглавление


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

Структура программы. Скалярные типы данных.

Выражения и присваивания ………………….…………………………………..3


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

Правила использования директив препроцессора ……………………………..8


Лабораторная работа № 11.Часть 1

Операторы языка С++: операторы деления…………………..………………..13


Лабораторная работа № 11. Часть 2

Операторы языка С++: операторы цикла……………………..………………..17


Лабораторная работа № 11. Часть 3

Операторы языка С++: операторы передачи управления..…..………………..23


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

Указатели и адреса объектов….…………………………………..…………….29


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

Массивы и указатели…………………………………………………………….36


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

Составные типы данных. Правила объявления, инициализации и

работы с составными типами данных.…………………………………………48


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

Лексические основы языка С++………..……………………….………………52

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

Функции, указатели, ссылки……………………………………………………57


Библиографический список .…………………………………………………...65