ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык...

343
УДК 002.6:004.43 ББК 73:32.973-01 Т12

Transcript of ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык...

Page 1: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

УДК 002.6:004.43 ББК 73:32.973-01 Т12

Page 2: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

2

Рецензенты : О.В. Герман, доцент кафедры проектирования информационно-

компьютерных систем Белорусского государственного университета инфор-матики и радиоэлектроники, кандидат технических наук, доцент

В.Ф. Алексеев ,доцент кафедры информационных технологий автома-тизированных систем Белорусского государственного университета инфор-матики и радиоэлектроники, кандидат технических наук, доцент

УМК рекомендован к изданию научно-методическим советом Минского инновационного университета (протокол № ____ от «___».01.2017) ISBN 978-985-490-331-6

Таборовец, В.В. Т12 Основы алгоритмизации и программирования: электронный учеб.-

метод.компл. / В.В. Таборовец, Т.В. Русак. - Минск: 2017. – 343с.

ISBN 978-985-490-331-6.

Электронный учебно-методический комплекс по дисциплине «Основы алгоритмизации и программирования» содержит программу учебной дисци-плины, опорный конспект лекций, лабораторный практикум, тестовые вопро-сы для подготовки к экзаменам. В составе лекционного курса рассмотрены основы алгоритмизации и общие сведения о системах программирования, а также основы программирования с использованием алгоритмического языка высокого уровня С/С++.

Лабораторный практикум предназначен для преобретения студентами практических навыков программирования на языке С/С++ и дополняет тео-ретический материал.

Электронный учебно-методический комплекс предназначен для сту-дентов высших учебных заведений специальностей «Информационные сис-темы и технологии» и «Программное обеспечение информационных техно-логий».

© Таборовец В.В., Русак Т.В., 2017

Page 3: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

3

СОДЕРЖАНИЕ ВВЕДЕНИЕ…………………………………………………………………..5 1. ТРЕБОВАНИЯ К ОСВОЕНИЮ СОДЕРЖАНИЯ И ПРОГРАММЫ ДИСЦИПЛИНЫ .......................................................... 7

1.1 ТРЕБОВАНИЯ К УРОВНЮ ОСВОЕНИЯ СОДЕРЖАНИЯ УЧЕБНОЙ ДИСЦИПЛИНЫ .......................................................................... 7 1.2 ПРОГРАММА ДИСЦИПЛИНЫ .......................................................... 9

2. ОПОРНЫЙ КОНСПЕКТ ЛЕКЦИЙ ................................................... 11 Тема 1 ОБЩИЕ СВЕДЕНИЯ ОБ АЛГОРИТМАХ .................................... 11

1.1 Понятие алгоритма.................................................................... 11 1.2 Свойства алгоритма .................................................................. 13 1.3 Способы описания алгоритмов .................................................... 14 1.4 Разновидности структур алгоритмов .......................................... 19

Тема 2. ОБЩИЕ СВЕДЕНИЯ О СИСТЕМАХ ПРОГРАММИРОВАНИЯ ........................................................................ 32

2.1 СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ЭВМ ............... 33 2.1.1 Операционные системы ............................................................ 35 2.1.2 Базовая система ввода-вывода (BIOS) .................................... 36 2.1.3 Файловые системы .................................................................... 38 2.1.4 Виды операционных систем .................................................... 43 2.1.5 Операционные оболочки .......................................................... 49 2.1.6 Сетевое программное обеспечение ......................................... 50

2.2 ПРИКЛАДНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ КОМПЬЮТЕРОВ .......................................................................................... 52

2.2.1 Прикладное программное обеспечение общего назначения ................................................................................. 52

2.2.2 Методо-ориентированные прикладное программное обеспечение ........................................................ 56

2.2.3 Проблемно-ориентированное прикладное программное обеспечение ............................................................................... 57

2.3 ИНСТРУМЕНТАРИЙ ТЕХНОЛОГИЙ ПРОГРАММИРОВАНИЯ ............................................................................ 57 2.4 ОБРАБОТКА ПРОГРАММ НА КОМПЬЮТЕРАХ ........................ 60 Тема 3 ОСНОВНЫЕ ЭЛЕМЕНТЫ ЯЗЫКА Си ......................................... 63

3.1 Введение в язык Си ................................................................... 63 3.2 Основные элементы языка С/С++ ........................................... 65 3.3 Типы данных .............................................................................. 67 3.4 Базовые типы данных ............................................................... 69 3.5 Структура простой программы ................................................ 73 3.6 Функции ввода-вывода ............................................................. 80 3.7 Выражения и операции ............................................................. 84 3.8 Последовательность выполнения операций ........................... 91 3.9 Указатели и операции с адресами ........................................... 94 3.10 Управляющие структуры ......................................................... 98

Page 4: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

4

Тема 4 СЛОЖНЫЕ ТИПЫ ДАННЫХ ...................................................... 115 4.1 Массивы ................................................................................... 115 4.2 Многомерные массивы ........................................................... 119 4.3 Строковые литералы (строки) ............................................... 123 4.4 Связь между указателями и массивами ................................ 135 4.5 Структуры ................................................................................ 140

Тема 5 ФУНКЦИИ (ПОДПРОГРАММЫ) ................................................ 149 5.1 Общие сведения о функциях.................................................. 149 5.2 Прототип функции .................................................................. 152 5.3 Определение функции ............................................................ 152 5.4 Вызов функции ........................................................................ 152 5.5 Возвращаемые значения ......................................................... 154 5.6 Передача аргументов в функцию .......................................... 155 5.7 Передача массивов в функции ............................................... 156 5.8 Рекурсия ................................................................................... 158

Тема 6 ФАЙЛЫ ........................................................................................... 162 6.1 Понятие файла ......................................................................... 162 6.2 Открытие и закрытие файла ................................................... 163 6.3 Запись и чтение информации ................................................. 164 6.4 Позиционирование в файле.................................................... 166

Тема 7. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ ............................ 171 7.1 Динамическое распределение памяти .................................. 171 7.2 Связанные списки, очереди, стеки, кольца .......................... 175 7.3 Бинарные деревья ................................................................... 193

Тема 8 ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ ЯЗЫКА С/С++ ........ 199 8.1 Классы памяти ......................................................................... 199 8.2 Методы и алгоритмы оптимизации ....................................... 203

3 ЛАБОРАТОРНЫЙ ПРАКТИКУМ .................................................... 209

Лабораторная работа №1. СЛОВЕСНОЕ ОПИСАНИЕ АЛГОРИТМА 209

Лабораторная работа №2. ГРАФИЧЕСКОЕ ОПИСАНИЕ АЛГОРИТМА .............................................................................................. 221

Лабораторная работа №3 СТРУКТУРА ПРОСТОЙ ПРОГРАММЫ НА Си. ФУНКЦИИ ВВОДА-ВЫВОДА ........................................................ 2365

Лабораторная работа № 4 ОПЕРАТОРЫ ВЕТВЛЕНИЯ ........................ 245

Лабораторная работа № 5 ОПЕРАТОРЫ ЦИКЛА (for и while) ................................................................................................... 253

Лабораторная работа № 6 ОПЕРАТОРЫ ЦИКЛА (do…while) .............. 258

Лабораторная работа № 7. ОДНОМЕРНЫЕ МАССИВЫ ...................... 263

Лабораторная работа № 8 МНОГОМЕРНЫЕ МАССИВЫ .................... 269

Лабораторная работа 9. ФУНКЦИИ ......................................................... 274

Лабораторная работа № 10 УКАЗАТЕЛИ ................................................ 287

Лабораторная работа № 11. СТРУКТУРЫ ............................................... 297

Лабораторная работа № 12. ФАЙЛЫ ........................................................ 304

4 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ПО ВЫПОЛНЕНИЮ КУРСОВОЙ РАБОТЫ ......................................................................... 312

Page 5: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

5

4.1 Общие положения ................................................................................. 312

4.2 Требования к содержанию этапов проектирования ...................... 312

4.3 Требования к разработке и оформлению работы .......................... 314

4.4 Допуск и защита курсовой работы .................................................. 314

4.5 Рекомендуемые темы курсовых работ ............................................ 316

5 УПРАВЛЯЕМАЯ САМОСТОЯТЕЛЬНАЯ РАБОТА СТУДЕНТОВ ......................................................................................... 321

6 ПЕРЕЧЕНЬ ТЕСТОВЫХ ВОПРОСОВ К ЭКЗАМЕНАМ ............ 333

7 СПИСОК ЛИТЕРАТУРЫ ПО ДИСЦИПЛИНЕ ............................. 342

7.1 Основная литература ........................................................................ 342

7.2 Дополнительная литература ............................................................ 343

Page 6: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

6

ВВЕДЕНИЕ

Данный электронный учебно-методический комплекс (ЭУМК) состав-лен на основе преподавания дисциплины «Основы алгоритмизации и про-граммирования» в Минском инновационном университете для студентов высших учебных заведений специальностей «Информационные системы и технологии» и «Программное обеспечение информационных технологий». В основу последовательности изложения материала положена типовая учебная программа дисциплины.

ЭУМК включает такие основные разделы, как: - учебную программу дисциплины «Основы алгоритмизации и про-

граммирования», составленную авторами и утвержденную в установленном порядке в Минском инновационном университете;

- опорный конспект лекций, включающий все основные разделы и темы курса;

- лабораторный практикум, предназначенный для закрепления теоре-тических знаний и приобретения практических навыков программирования;

- задания студентам, выносимые на управляемую самостоятельную работу студентов под управлением преподавателя (УСРС);

- примерный перечень вопросов для компьютерного тестирования, предназначенных для проведения текущего контроля знаний студентов;

- список основной и дополнительной литературы, рекомендованной студентам.

В ЭУМК в качестве базового языка используется алгоритмический язык Си с элементами языка С++, так как в настоящее время данный язык получил довольно широкое распространение и дальнейшее развитие в языках С++, С#, Java, хотя основные приемы программирования, описанные в ЭУМК, в общем случае не зависят от языка программирования.

При изучении языка Си рекомендуется следовать той последовательно-сти, в которой изложен материал в опорном конспекте лекций и дополнять его теоретическое изучение выполнением практических заданий, приведен-ных в описании лабораторных работ. Предложенные в лабораторном практи-куме задания не привязаны к конкретному лабораторному оборудованию и могут выполняться студентами самостоятельно на любом персональном ком-пьютере в среде Microsoft Visual Studio C++.

Page 7: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

7

Задания на УСРС представляют собой перечень задач для самостоя-тельного составления программ и охватывают все основные темы опорного конспекта лекций.

Все рассмотренные в ЭУМК элементы языка Си иллюстрируются большим количеством примеров решения конкретных задач, при этом внача-ле идут простые задачи, затем их сложность возрастает.

Тексты программ, приведенные в УМК, компилировались и выполня-лись в среде Microsoft Visual Studio C++.

При написании ЭУМК в той или иной мере были использованы мате-риалы литературных источников, предложенных студентам в качестве ос-новной и дополнительной литературы, список которых приведен в ЭУМК.

Page 8: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

8

1. ТРЕБОВАНИЯ К ОСВОЕНИЮ СОДЕРЖАНИЯ И ПРОГРАММЫ ДИСЦИПЛИНЫ

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

1.1 ТРЕБОВАНИЯ К УРОВНЮ ОСВОЕНИЯ СОДЕРЖАНИЯ УЧЕБНОЙ ДИСЦИПЛИНЫ

В результате изучения дисциплины «Основы алгоритмизации и про-граммирования» формируются следующие компетенции:

академические: – уметь применять базовые научно-теоретические знания для решения

теоретических и практических задач; – владеть системным и сравнительным анализом; – владеть исследовательскими навыками; – уметь работать самостоятельно; – быть способным порождать новые идеи (обладать креативностью); – иметь навыки, связанные с использованием технических устройств,

управлением информацией и работой с компьютером; – уметь учиться, повышать свою квалификацию в течение всей жизни; – использовать основные законы естественнонаучных дисциплин в

про-фессиональной деятельности; – владеть основными методами, способами и средствами получения,

хра-нения, переработки информации с использованием компьютерной техни-ки.

– на научной основе организовывать свой труд, самостоятельно оцени-вать результаты своей деятельности;

социально-личностные: – уметь работать в команде; – быть способным к социальному взаимодействию; – обладать способностью к межличностным коммуникациям; профессиональные: – анализировать и оценивать собранные данные;

Page 9: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

9

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

– разрабатывать алгоритмы с использованием имеющихся средств ис-сле-дований, включая стандартные пакеты прикладных программ;

– разрабатывать программы, включая выбор технических средств и об-ра-ботку результатов;

– пользоваться глобальными информационными ресурсами; – разрабатывать и согласовывать представляемые материалы; – создавать и поддерживать базы данных. В результате изучения дисциплины«Основы алгоритмизации и про-

граммирования» обучаемый должен: знать: - основы алгоритмизации; - основы структурного проектирования программ; - способы представления алгоритмов; - современный процедурно-ориентированный алгоритмический язык

программирования С/С++; уметь: - выполнять алгоритмизацию инженерных и экономических задач; - программировать на процедурно-ориентированном алгоритмиче-

ском языке С/С++; - отлаживать и тестировать программы; - использовать имеющееся программное обеспечение; - анализировать исходные и выходные данные решаемых задач и

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

1.2 ПРОГРАММА ДИСЦИПЛИНЫ

Тема 1. Общие сведения об алгоритмах. Алгоритм и его свойства. Разновидности структур алгоритмов. Способы описания алгоритмов. Стан-дартизация графического представления алгоритмов.

Тема 2. Системы программирования. Назначение и состав системы программирования. Классификация программного обеспечения. Назначение и состав операционных систем. Пакеты прикладных программ. Текстовые и графические редакторы. Базы данных. Интегрированные, методо- и проблем-но-ориентированные пакеты прикладных программ.

Тема 3. Основные элементы языка С/С++. Основные понятия языка. Базовые типы данных. Структура программы. Функции ввода-вывода. Опе-

Page 10: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

10

рации и их приоритет. Выражения. Операторы организации перехода. Опера-торы организации циклов.

Тема 4. Сложные типы данных. Массивы. Одномерные и многомер-ные массивы. Объявление, инициализация массивов, обращение к элементам массива.

Строки. Объявление и инициализация массива символов (строк). Нуле-вой символ. Библиотечные функции работы со строками.

Структуры. Объявление шаблонов структур. Определение и инициали-зация структур-переменных. Доступ к компонентам структуры.

Указатели. Операции над указателями. Связь между указателями и массивами.

Тема 5. Функции (подпрограммы). Функции. Прототип, определение, вызов функции. Передача параметров между функциями. Рекурсия. Рекурсия в сравнении с итерацией.

Тема 6. Файлы. Файлы. Бинарные и текстовые файлы. Библиотечные функции для открытия и закрытия файлов. Запись и чтение данных в/из фай-ла. Файлы прямого и последовательного доступа.

Тема 7. Динамические структуры данных. Динамическое распреде-ление памяти. Библиотечные функции для выделения и освобождения дина-мической памяти. Списки. Кольца. Стеки. Очереди. Бинарные деревья. Опе-рации над динамическими структурами данных.

Тема 3.6 Дополнительные возможности языка С/С++. Классы хра-нения и видимость переменных. Локальные и глобальные переменные. Ав-томатические, внешние, статистические и регистровые переменные.

Методы сортировки. Метод пузырька или сортировки простым обме-ном. Сортировка выбором наименьшего элемента. Метод Шелла. Метод Хоара.

Page 11: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

11

2. ОПОРНЫЙ КОНСПЕКТ ЛЕКЦИЙ Тема 1 ОБЩИЕ СВЕДЕНИЯ ОБ АЛГОРИТМАХ

1.1 Понятие алгоритма Слово «алгоритм» произошло от имени выдающегося средневекового

ученого, жившего в IX веке, Ал-Хорезми. В одном из своих трудов Ал-Хорезми описал десятичную систему счисления и впервые сформулировал правила выполнения арифметических действий над целыми числами и про-стыми дробями.

В латинском переводе арифметического труда Ал-Хорезми правила на-чинались словами Dixit Algorizmi (Алгоризми сказал). В других латинских переводах автор именовался Algorithmus (Алгоритмус). Постепенно люди за-были, что Алгоризми — это автор правил, и стали сами эти правила называть алгоритмами. Так «Алгоризми сказал» постепенно преобразовалось в «алго-ритм гласит».

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

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

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

Рассмотрим более подробно определение алгоритма. «Конечный набор правил или команд (указаний, предписаний)» озна-

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

Page 12: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

12

нированности алгоритма. При этом предписание должно быть выражено на понятном исполните-

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

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

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

Во-вторых, «решить задачу» означает решить ее «за конечное число шагов». Получение результата за конечное число шагов составляет свойство результативности алгоритма.

В-третьих, так как предписание, задающее алгоритм, обеспечивает по-лучение результата за конечное число шагов, то это означает также, что вся-кий алгоритм представляет собой упорядоченное конечное множество шагов. А всякое такое множество обладает свойством дискретности. Например, этим свойством обладает множество N натуральных чисел, хотя оно и беско-нечное. Это свойство состоит в том, что для каждого натурального числа можно указать единственное непосредственно следующее за ним натураль-ное число, т. е. такое, что между ними нет других натуральных чисел. В лю-бом алгоритме для каждого шага (кроме, разумеется, последнего) можно ука-зать единственный (при данном выборе исходных объектов), непосредствен-но следующий за ним шаг, т. е. такой, что между ними нет других шагов. По-этому и говорят, что алгоритм обладает свойством дискретности или дис-кретной структурой.

Класс однотипных задач или общая задача обычно формулируется (в математике) с использованием некоторых переменных — параметров.

Page 13: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

13

Например, общая задача «Решить уравнение 2 0 ( , , )ax bx c a b c Q+ + = Î »

содержит три параметра ( , , )a b c , при этом задается область значений пара-метров (Q). Подставляя вместо ( , , )a b c в формулировке обшей задачи любую тройку рациональных чисел, получаем частную задачу этого класса.

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

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

Например, натуральное число — конструктивный объект, так как лю-бое натуральное число можно закодировать с помощью слова в алфавите {0, 1, 2, ...,9} десятичной системы счисления или с помощью слова в алфавите {0, 1} двоичной системы счисления и т. п.

Арифметические выражения, составленные из чисел, знаков арифмети-ческих действий и скобок, можно рассматривать как слова в алфавите {0, 1, 2, ..., 9, +, — ,- , /, ( , )}.

Итак, подведя некоторый итог сказанному, можно дать и следующее объяснение термину «алгоритм»: под алгоритмом понимают единый метод решения определенного класса однотипных задач, обладающий свойствами дискретности, массовости, определенности, результативности и опери-рующий конструктивными объектами.

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

1.2 Свойства алгоритма

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

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

2) Детерминированность алгоритма. Система величин, получаемых в

Page 14: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

14

любой не начальный момент времени, однозначно определяется системой ве-личин, полученных в предыдущие моменты времени.

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

4) Результативность алгоритма. Результат выполнения алгоритма должен быть получен за конечное число шагов.

5) Направленность алгоритма. Если способ получения последующей величины из какой-нибудь заданной величины не дает результата, то должно быть указано, что надо считать результатом алгоритма.

6) Массовость алгоритма. Алгоритм должен быть пригоден для ре-шения всех задач из заданного класса, т.е. алгоритм является единым мето-дом, позволяющим по любой исходной системе величин из определенного бесконечного множества их получить искомый результат.

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

1.3 Способы описания алгоритмов

Существуют следующие основные способы описания алгоритмов: 1) запись на естественном языке (словесное описание); 2) изображение в виде схемы (графическое описание); 3) запись на алгоритмическом языке (составление программы). Словесное описание. Словесный алгоритм — описание последователь-

ных этапов обработки данных на естественном языке. Существуют различные способы словесного описания алгоритмов. Они

отличаются применяемыми метаязыками. Так, в программировании метаязы-ком называется язык, предназначенный для описания языка программирова-ния.

Уточним понятие словесного алгоритма на примерах.

Пример 1. Имеет ли уравнение 2 0 ( , , )ax bx c a b c Q+ + = Î вещественные

корни? Представим решение данной задачи в виде словесного предписания,

разделенного на отдельные указания (шаги).

1) Вычислить 2 4D b ac= - . Перейти к шагу 2.

2) Если 0D ³ , то перейти к шагу 3, иначе к шагу 4. 3) Уравнение имеет вещественные корни. Перейти к шагу 5.

Page 15: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

15

4) Уравнение не имеет вещественных корней. Перейти к шагу 5. 5) Процесс решения закончен.

Пример 2. Сложить п чисел 1 2, ,..., nx x x , т. е. произвести вычисления по формуле:

1

n

ii

S x=

= å

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

1) Положить значение S равным x1. 2) Положить значение i равным 2. 3) Заменить значение S на значение S + xi, т.е. к значению переменной

S добавить значение переменной xi, полученный результат опять обозначить буквой S.

4) Заменить значение переменной i на значение i+1, т.е. к значению переменной i добавить единицу и полученный результат опять обозначить буквой i.

5) Сравнить значения i и п. Если i n< , то повторить действия, начиная с п. 3, иначе перейти к п. 6.

6) Прекратить действия. Искомый результат уже получен. Он равен значению переменной S.

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

Графическое описание. Графическое описание позволяет представить алгоритм в наглядной форме в виде схемы.

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

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

Блок-схема. Анализ приведенных примеров выявляет в их составе два основных вида предписаний (команд):

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

Page 16: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

16

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

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

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

1) каждый шаг представляется с помощью блока; 2) блок, соответствующий команде первого вида, изображается прямо-

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

3) блок, соответствующий команде второго вида, изображается в виде ромба, внутри которого записывается проверяемое логическое условие (эти блоки называются также логическими);

4) если за шагом А непосредственно следует шаг В, то от блока А к блоку В проведена стрелка;

5) от каждого арифметического блока (прямоугольника) исходит толь-ко одна стрелка; от каждого логического блока (ромба) — две стрелки: одна с пометкой «да», идущая к блоку, следующему за логическим блоком, если ус-ловие выполняется, другая — с пометкой «нет», идущая к блоку, следующе-му за логическим, если условие не выполняется (как видно, логический блок осуществляет ветвление процесса);

6) начало и конец процесса выполнения алгоритма также изображают-ся блоками в виде фигур, ограниченных овалами, внутри которых записы-ваются соответственно слова «начало», «конец»;

7) блоки «ввод» (исходных данных) и «вывод» (результатов) изобра-жаются в виде параллелограммов (эти блоки обычно опускаются, когда алго-ритмы адресованы исполнителю-человеку, но обязательно присутствуют в блок-схемах алгоритмов, предназначенных для ЭВМ, т.е. для перевода в про-граммы.

Page 17: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

17

С использованием вышеописанных символов алгоритм вычисления суммы значений xi можно описать блок-схемой, изображенной на рис. 1.1.

Начало

),1( nix i =

1: xS =

2:=i

ixSS +=:

1: += ii i n<

Конец

Да

Нет

0

54

3

1

2

Рис. 1.1. Блок-схема алгоритма вычисления суммы

Блок-схема наглядно изображает последовательность выполнения предписаний.

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

Рис. 1.2. Описание алгоритма ориентированным графом

Недостатком такого описания является то, что не видно различия меж-ду блоками.

Запись на алгоритмическом языке (алгоритмическая запись). Алго-ритмическая запись – это некоторая стандартная запись алгоритмов на опре-деленном языке, именуемом алгоритмическим языком (АЯ). Алгоритмиче-

Page 18: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

18

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

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

1) алфавит алгоритмического языка, 2) способ конструирования выражений, 3) перечень используемых слов, 4) правила организации записей на алгоритмическом языке (синтакси-

ческие правила этого языка), 5) разъяснение смысла (семантики) конструкций из символов (слов и

выражений) языка. Алфавит — перечень символов (знаков), используемых в данном язы-

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

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

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

В любом алфавите объекты реального мира можно изображать слова-ми.

Слово (строка алфавита) — любая конечная упорядоченная последо-вательность символов. Число символов в слове называют длиной слова.

Выражения. Выделяются арифметические и логические выражения. С синтаксической точки зрения арифметические выражения в АЯ строятся так же, как и в математическом языке, так как последний полностью включается в первый.

Логические выражения (условия) конструируют последовательность действий алгоритма, т.е. позволяют изменить последовательность решения задачи в зависимости от проверки условий. Логические выражения прини-мают только два значения – «Истина» или «Ложь».

Служебные (ключевые) слова. В АЯ выделяется некоторое число «слов», называемых служебными или ключевыми словами этого языка, смысл и способ применения которых в записях алгоритмов точно определя-ется. В качестве служебных слов АЯ используются сокращения некоторых английских (русских) слов или целиком некоторые слова. Служебные слова, как правило, выделяются жирным шрифтом.

Page 19: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

19

Правила организации алгоритмической записи. Синтаксические прави-ла записи алгоритмов на АЯ представляют собой своеобразные «фигуры» расположения слов в записи алгоритмов. Данные правила определяют поря-док создания заголовка алгоритма, общий вид записи алгоритма, порядок ор-ганизации ветвлений и циклов, организации обращения к другим алгоритмам и др.

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

1.4 Разновидности структур алгоритмов

Различают следующие структуры алгоритмов: - линейные; - разветвляющиеся; - циклические. Линейный вычислительный процесс. Линейный вычислительный про-

цесс – это процесс, в котором направление вычислений является единствен-ным.

Пример 1. Вычислить значение функции вида (sin 2cos( / ) 3 / )y x x z x z= + +

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

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

Page 20: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

20

Начало

Ввод X,Z

A:=X/Z

Конец

Вывод Y

1

1

Υ: 3* Α=

Υ : Υ 2* cos Α= +

Υ : Υ sin Χ= +

Υ:Υ =

Рис. 1.3. Схема алгоритма вычисления функции Y

Для повышения эффективности алгоритма желательно, чтобы выраже-ния, участвующие в вычислениях несколько раз, вычислялись один раз, а за-тем использовались уже вычисленные их значения (на рис. 1.3 один раз вы-числено значение X/Z, полученное значение присвоено переменной А, кото-рая затем используется в вычислениях).

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

Рассмотрим пример построения разветвляющегося алгоритма. Пример 2. Вычислить значение функции:

ïî

ïí

ì

<-=>-

=0. xесли , ,0 если ,0 ,0 если ,1 2

xxxx

y

Page 21: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

21

Для заданного значения х получим одно значение у. Но какое именно из трех возможных — это зависит от значения х. Поэтому в описании алго-ритма необходимо учесть все три возможности.

На блок-схеме алгоритма данного примера (рис. 1.4) видно, что на ветвь 1 (блоки 5, 7) можно попасть, если х>0. В противном случае вычисле-ния пойдут по ветви 2 (блоки 3, 4, 6, 7). Но и на ветви 2 есть два возможных направления: для, x = 0 работает ветвь 2.1 (блоки 6, 7), для x<0 — ветвь 2.2 (блоки 4, 7).

Начало

X

Y:= – X Конец

X>0

X=0

Y:= 1 – X2

Y:= 0

Да

Нет

2

1

3

4

5

6

7Нет

Да

Ветвь 1

Ветвь 2.1Ветвь 2

Ветвь 2.2

Рис. 1.4. Пример разветвляющейся блок-схемы

Циклический вычислительный процесс. Циклический вычислитель-ный процесс – это процесс, в котором отдельные участки вычислений выпол-няются многократно.

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

В соответствии с взаимным расположением циклов в теле программы или алгоритма различают следующие циклы:

1) простые – циклы, не содержащие внутри себя других циклов; 2) сложные – циклы, содержащие внутри себя другие циклы;

Page 22: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

22

3) вложенные (внутренние) – циклы, входящие в состав других циклов (цикл в цикле);

4) внешние – циклы, не являющиеся составной частью других циклов, но содержащие в своем составе внутренние циклы.

В зависимости от местоположения условия выполнения цикла разли-чают:

1) циклы с предусловием; 2) циклы с постусловием. В соответствии с видом условия выполнения циклы делятся на: 1) циклы с параметром; 2) итерационные циклы. Для решения вопроса о том, сколько раз нужно выполнять цикл, ис-

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

В общем случае схема алгоритма циклического процесса с параметром имеет вид, приведенный на рис. 1.5.

Изменение параметра

Инициализация

Вычисления

?

Да

Нет

Присвоение начального значения параметру цикла

Изменение значения параметра цикла

Проверка условия окончания цикла

Рис. 1.5. Блок-схема алгоритма циклического процесса

(с постусловием)

Блоки, выполняющие вычисления и изменение значения параметра цикла, составляют так называемое тело цикла - последовательность дейст-вий, которая выполняется многократно.

Page 23: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

23

В терминах метода структурного программирования вышеприведенный цикл называется циклом «До» (циклом с постусловием) – в нем тело цикла выполняется до проверки условия выхода из цикла.

В цикле «Пока» (цикле с предусловием) проверка условия выполнения цикла производится до тела цикла (рис. 1.6).

?

Инициализация

Проверка условия выполнения цикла

Тело цикла

Присвоение начального значения параметру цикла

Да

Нет

Рис. 1.6. Блок-схема алгоритма циклического процесса

(с предусловием)

Пример 3. Пусть в задаче требуется найти сумму чисел от 1 до 5. Оче-видно, что 1+2+3+4+5=15. Количество слагаемых может быть не пять, а зада-ваться как значение некоторой переменной N. Изобразим алгоритм с исполь-зованием блока проверки условия. В качестве такого условия возьмем A N£ . До тех пор, пока А остается не больше N, можно значение А прибавлять к сумме. Как только это условие не выполнится, следует прекратить вычисле-ния (рис. 1.7).

Page 24: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

24

Начало

N

S:= 1

А ≤ N

Конец

A:= 2

S:= S+A

A:= A+1

Нет

Да

1

2

3

4

5

6

7

8

Рис. 1.7. Пример циклической блок-схемы вычисления суммы

На рис. 1.7 цикл состоит из блоков 5, 6 и 7. Он выполнится N-1 раз. Циклы с известным количеством повторений. Циклический про-

цесс, в котором число выполнений тела цикла заранее определено, называет-ся циклическим процессом с известным количеством повторений (циклы со счетчиками, циклы с параметром цикла).

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

Пример 4. Рассмотрим простейший случай, когда параметр цикла из-меняется в заданных пределах с постоянным положительным шагом. Пусть i — параметр цикла; А, В — начальное и конечное значения i; h>0— шаг из-менения i. Тогда блок-схема цикла имеет вид, изображенный на рис. 1.8.

Page 25: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

25

i :=A

Повторяемый участок

i := i+h

i >B

Вход в цикл

Выход из цикла

Да

Нет

1

2

3

4

Рис. 1.8. Блок-схема цикла с известным количеством повторений

В блоке 1 параметру цикла i присваивается начальное значение А. В блоке 2 проверяется условие окончания работы цикла. В блоке 3 объединены повторяемые операции. В блоке 4 параметр цикла получает очередное значе-ние. Такой цикл, с известным количеством повторений, использован в при-мере 1.7 при вычислении суммы.

Итерационные циклы. Итерационные методы решения задач приводят к многократно повторяющимся вычислениям, но сколько раз их придется по-вторить, как правило, заранее неизвестно. Для итерационных процессов ха-рактерно то, что значения, получаемые на текущем шаге итерации, исполь-зуются, как правило, в качестве исходных данных для следующего шага ите-рации.

Циклы с заранее неизвестным числом повторений, зависящим от полу-чающихся в ходе вычисления результатов, называют итерационными.

В общем виде итерационный процесс может быть представлен сле-дующим образом (рис. 1.9).

Page 26: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

26

Инициализация

Вычисления

Подготовка

Определение

?Нет

Да

Присвоение начальных значений

Подготовка к следующей итерации

Определение значения величины, влияющей на окончание процесса

Проверка условия окончания цикла

Рис. 1.9. Блок-схема алгоритма итерационного процесса

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

Пример 5. Составить блок-схему алгоритма вычисления

( ), 0ky x x= >,

как предела последовательности у0, . . . , уn, где k – целое число, а у0 за-дается как некоторое начальное приближение к искомому результату у (на-

пример, чтобы найти 2 , можно взять у0=1). Для i = 0, 1, 2, ... каждое сле-дующее приближение yi+1 вычисляется через предыдущее yi по формуле (ме-тод Ньютона):

Page 27: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

27

... ... 2, 1, ,0 ,11 =-

-= -+ iky

xyyy ki

ki

ii

Как правило, корень считается вычисленным, если два последователь-

ных приближения yi+1 и уi отличаются друг от друга меньше чем на заданное

малое e , т.е. должно выполняться условие e<-+ ii yy 1 , где i = 0, 1, 2, ..; e >0 — заданное число, определяющее точность вычисления корня.

Блок-схема данного алгоритма изображена на рис. 1.10.

Начало

Конец

i:= -1

i:=i+1

2

1

3

4

5

Да

Нет

x, y0, k, ε

1ki

ki

i1 i kyxyy:y -+

--=

εyy i1i <-+

Рис. 1.10. Блок-схема алгоритма итерационного цикла вычисления функции y

Из блок-схемы видно, что возможно многократное выполнение блоков 3, 4, 5, но неизвестно, сколько раз повторится цикл. О числе повторений цик-ла можно судить лишь по значению переменной i, которое совпадает с чис-лом повторений цикла. Возможна ситуация, когда при реализации данного

Page 28: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

28

алгоритма на ЭВМ выхода из цикла не произойдет. Такая ситуация называет-ся «зацикливанием».

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

Пример 6. Составить блок-схему алгоритма для вычисления функции ( ), , 1, ; 1,i j i jf x y x y где i m j k= * = = .

Для получения результатов потребуется вычислить mk произведений xi*yj, что можно организовать следующим образом:

1. Умножим х1 последовательно на y1, y2, . . .,yк. Для организации дан-ного вычисления необходимо организовать циклический процесс, парамет-ром цикла которого является переменная j.

2. Затем х2 умножим последовательно на у1, у2,… ,уk и получим тот же цикл, но с индексом 2 у переменной х.

3. Выполнив такие же вычисления с переменными х3, x4,, ..., хт, полу-чим все искомые произведения. Для перехода от x1 к x2 и т.д. введем индекс цикла i и построим еще один цикл, в котором i изменяется от 1 до т.

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

Page 29: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

29

Начало

Конец

jiji yxyxf =:),(

kjy

mix

j

i

,1,

,1,

=

=

Нет Да

Нет

Да

1

2

3

4

5

6

7 8

: 1i =

: 1j =

: 1j j= +

j k£

: 1i i= + i m£

Рис. 1.11. Пример блок-схемы алгоритма вычисления «цикл в цикле»

Page 30: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

30

По отношению друг к другу циклы могут быть внутренними (цикл по j) и внешними (цикл по i). Говорят, что цикл по j вложен в цикл по i. Для каж-дого значения параметра i внешнего цикла параметр j внутреннего цикла должен принять все свои k значений. Следовательно, если обозначить общее число повторений внутреннего цикла через N, то в нашем примере N=km.

В общем виде блок-схема вложенного цикла может быть представлена следующим образом (рис. 1.12).

Вход в цикл А

Вход в цикл В

Вход в цикл С

Выход из цикла С

Выход из цикла В

Выход из цикла А

Рис. 1.12. Блок-схема алгоритма с вложенными циклами

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

Page 31: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

31

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

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

Page 32: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

32

Тема 2. ОБЩИЕ СВЕДЕНИЯ О СИСТЕМАХ ПРОГРАММИРОВАНИЯ

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

К программному обеспечению (ПО) относится также вся область дея-тельности по проектированию и разработке ПО: технология проектирования программ (например, нисходящее проектирование, структурное и объектно-ориентированное проектирование и др.); методы тестирования программ; анализ качества работы программ; документирование программ; разработка и использование программных средств, облегчающих процесс проектирования программного обеспечения, и многое другое.

Все программы по характеру использования и категориям пользовате-лей подразделяют на два класса — утилитарные программы и программные продукты (изделия).

Утилитарные программы («программы для себя») предназначены для удовлетворения нужд их разработчиков. Чаще всего утилитарные программы выполняют роль сервиса в технологии обработки данных, либо являются программами решения функциональных задач, не предназначенных для ши-рокого распространения.

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

Программный продукт — комплекс взаимосвязанных программ для решения определенной проблемы (задачи) массового спроса, подготовлен-ный к реализации как любой вид промышленной продукции.

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

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

обеспечения компьютеров: - системное программное обеспечение; - инструментарий технологии программирования; - пакеты прикладных программ.

Page 33: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

33

2.1 СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ЭВМ

Системное программное обеспечение (System Software) — совокуп-ность программ и программных комплексов для обеспечения работы компь-ютеров и сетей ЭВМ.

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

Состав системного программного обеспечения представлен на рис. 2.1.

Рис. 2.1. Классификация системного ПО

Системное ПО состоит из базового программного обеспечения, кото-рое, как правило, поставляется вместе с компьютером, и сервисного про-граммного обеспечения, которое устанавливается на компьютер дополни-тельно.

В базовое программное обеспечение входят: - операционная система; - операционные оболочки (текстовые и графические);

Page 34: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

34

- системные утилиты. Операционная система (ОС) предназначена для управления выполне-

нием пользовательских программ, планирования и управления вычислитель-ными ресурсами ЭВМ. Она выполняет роль связующего звена между аппара-турой компьютера, с одной стороны, и выполняемыми программами, а также пользователем — с другой.

Операционные оболочки — специальные программы, предназначен-ные для облегчения общения пользователя с командами операционной сис-темы.

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

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

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

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

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

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

- программы оптимизации и контроля качества дискового пространст-ва;

- программы восстановления информации, форматирования, защиты

Page 35: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

35

данных; - коммуникационные программы, организующие обмен информацией

между компьютерами; - программы для управления памятью, обеспечивающие более гибкое

использование оперативной памяти; - программы обслуживания сети; - программы для записи CD-ROM, CD-R и многие другие. Сервисные программы часто также называются утилитами. Они либо

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

2.1.1 Операционные системы Операционная система обычно хранится во внешней памяти компью-

тера — на диске. При включении компьютера она считывается с дисковой памяти и размещается в оперативном запоминающем устройстве. Этот про-цесс называется загрузкой операционной системы.

В функции операционной системы входит: - осуществление диалога с пользователем; - ввод-вывод и управление данными; - планирование и организация процесса обработки программ; - распределение ресурсов (оперативной памяти, процессора, внешних

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

ми; - программная поддержка работы периферийных устройств (дисплея,

клавиатуры, дисковых накопителей, принтера и др.). Операционную систему можно назвать программным продолжением

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

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

каемых и выполняемых прикладных процессов); - одно- и многопользовательские (в зависимости от числа пользовате-

Page 36: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

36

лей, одновременно работающих с операционной системой); - несетевые и сетевые, обеспечивающие работу в локальной вычисли-

тельной сети ЭВМ. Операционная система для персонального компьютера, ориентирован-

ного на профессиональное применение, должна содержать следующие ос-новные программные компоненты:

- управление вводом-выводом; - управление файловой системой; - планирование процессов; - анализ и выполнение команд, адресованных операционной системе. Каждая операционная система имеет свой командный язык, который

позволяет пользователю выполнять те или иные действия: - обращаться к каталогу; - выполнять разметку внешних носителей; - запускать программы и др. Анализ и исполнение команд пользователя, включая загрузку готовых

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

Перед тем как рассмотреть существующие типы операционных систем персональных компьютеров рассмотрим основные компоненты, присутст-вующие во всех ОС, а именно: базовую систему ввода-вывода и файловую систему.

2.1.2 Базовая система ввода-вывода (BIOS)

Базовая система ввода-вывода (Basic Input/Output System) выполняет наиболее простые и универсальные услуги операционной системы, связан-ные с осуществлением ввода-вывода и предназначена для начального "ожив-ления" компьютера. Универсальная программа BIOS записана в постоянном запоминающем устройстве (ПЗУ), носящем название ROM BIOS Объем со-временной BIOS не менее 1—2 Мбайт.

Программы, записанные в микросхеме BIOS, предназначены для вы-полнения следующих функций:

- инициализации и начального тестирования всех основных (стандарт-ных) узлов компьютера, для этого предназначена программа POST (Power On Self Test);

- загрузки операционной системы с внешнего устройства (гибкого дис-ка, жесткого диска, компакт-диска или ПЗУ сетевой карты);

Page 37: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

37

- обслуживания аппаратных прерываний; например, от клавиатуры и таймера;

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

- выполнения базовых функций, например, вывода на экран монитора символов;

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

подключенных к ней, что выполняется с помощью программы BIOS Setup. Инициализация и начальное тестирование (программа POST). При

включении компьютера и при перезагрузке операционной системы BIOS проверяет флаги условий, при которых произошло данное событие. Если со-стояние флагов говорит о том, что производится начальный старт компьюте-ра, то первой из комплекта BIOS запускается программа POST (Power On Self Test), которая инициализирует и тестирует аппаратные средства компьютера, определяя его конфигурацию и исправность всех основных узлов.

При обнаружении какой-либо ошибки при тестировании аппаратуры BIOS информирует пользователя об этом событии звуковым сигналом или выводом текстового сообщения.

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

Загрузка операционной системы. При успешном завершении тестиро-вания управление передается программе, которая должна найти устройство (какой-либо дисковод), с которого можно загрузить операционную систему.

Поиск устройства проводится в том порядке, который установил поль-зователь при настройке BIOS. Наиболее частый вариант — А:, С:, CD-ROM, хотя в последнее время часто используют вариант CD-ROM, С:, А:.

В первом случае, когда гибкий диск А: вставлен в дисковод, проводит-ся проверка — является ли он загрузочным. Весьма частым является случай, когда пользователь забывает в дисководе гибкий диск, не являющийся загру-зочным, пустой или с какими-либо данными. Тогда вырабатывается сигнал ошибки, о чем выводится сообщение на экран монитора, а программа ожида-ет решения пользователя.

При обычном старте компьютера операционная система загружается с жесткого диска (для MS-DOS и Windows 95/98/ME — обязательно с диска

Page 38: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

38

С:). При этом в память компьютера всегда считывается самый первый сектор загрузочного диска, где находится загрузочная запись — MBR (Master Boot Record). Если данный диск содержит операционную систему, то первый байт записи содержит флаг Boot (флаг загрузки). Значение флага Boot проверяется и определяется – является ли данный раздел диска загрузочным.

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

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

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

2.1.3 Файловые системы

Файловая система является важной частью любой ОС, которая отвечает за организацию хранения и доступа к информации на каких-либо носителях. Рассмотрим файловые системы для таких носителей информации, как маг-нитные диски. Информация на жестком диске хранится в секторах (обычно 512 байт) и само устройство может выполнять команды считать/записать ин-формацию в определенный сектор на диске.

Файловая система — это часть ОС, предназначенная для организации работы с хранящимися на диске данными и обеспечения совместного исполь-зования файлов несколькими пользователями и процессами.

Файловая система берет на себя организацию взаимодействия про-грамм с файлами, расположенными на диске; определяет структуру хранения файлов и каталогов на диске; правила задания имен файлов; допустимые ат-рибуты и права доступа и др.

Page 39: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

39

Файл — это поименованный объект, хранящий данные (команды, про-граммы или любую другую информацию) на каком-либо носителе.

Имена файлов служат для идентификации файлов. Пользователи дают файлам символьные имена, при этом учитываются ограничения ОС на ис-пользуемые символы и длину имени. Так, в файловой системе FAT DOS дли-на имен ограничивается 8 символами на имя файла и 3 символами на расши-рение имени, а в ОС UNIX System V длина имени не превосходит 14 симво-лов. Современные файловые системы, как правило, поддерживают длинные символьные имена файлов. Например, в файловой системе NTFS (Windows NT) имя файла содержит до 255 символов. Длинные имена поддерживаются не только новыми файловыми системами, но и новыми версиями старых файловых систем.

Различают следующие типы файлов: - текстовые, - двоичные, - файлы-каталоги и др. Текстовые файлы состоят из строк символов, представленных в ASCII-

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

Двоичные файлы не используют ASCII-коды и имеют сложную внут-реннюю структуру, например объектный код программы или архивный файл.

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

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

Каталоги обычно образовывают иерархическую структуру путем включения каталогов низкого уровня в каталог более высокого уровня. Ката-логи образуют древовидную структуру, если файлу разрешено входить толь-ко в один каталог (MS-DOS и Windows), и сетевую — если файл может вхо-дить одновременно в несколько каталогов (UNIX).

Page 40: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

40

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

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

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

Мандатный подход, когда система наделяет пользователя определен-ными правами в зависимости от его принадлежности к группе. Для пользова-телей одной группы определяются единые права доступа. Например, в ОС Windows NT пользователи подразделяются на группы: администратора, пользователя и пр.

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

Файловая система выполняет следующие основные функции: - отслеживание занятого и свободного места (а также плохих секто-

ров); - поддержка структуры, имен каталогов и имен файлов; - отслеживание физического расположения файлов на диске. В широком смысле понятие «файловая система» включает: - совокупность всех файлов на диске; - наборы служебных структур данных, используемых для управления

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

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

Page 41: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

41

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

Выбор файловой системы часто связан с проблемой непроизводитель-ных потерь дискового пространства. Действительно, при записи информации место на диске выделяется ОС целыми блоками — кластерами.

Кластер (cluster) – минимальное дисковое пространство, которое мо-жет занимать файл, представляющее собой объединение смежных секторов диска.

Размер кластера (4К, 8К, 16К, 32 Кбайт и т.д.) зависит от типа файло-вой системы и емкости диска. Например, файловая система FAT16 позволяет адресовать 216= 65 536 кластеров. В результате для логического диска емко-стью 500 Мбайт каждый кластер занимает 8 Кбайт, а для диска 1,0 Гбайт размер кластера становится уже 16 Кбайт. В результате при хранении файла небольшого размера (меньше 1 Кбайт) значительная часть кластера не будет использована. Чем больше размер раздела жесткого диска, тем больше объем минимальной выделяемой файлу неделимой области памяти и тем больше потери.

Эти потери существенно сокращаются при использовании более эф-фективных файловых систем. Переход на HPFS (OS/2) позволяет установить минимальный размер выделяемого блока — 512 байт для любых размеров диска. Аналогичный эффект дает и применение файловой системы NTFS (Windows NT).

Рассмотрим назначение и особенности некоторых файловых систем. Файловая система FAT (File Allocation Table) — это таблица разме-

щения файлов в операционных системах DOS и Windows 9x, изначально раз-рабатывавшаяся для гибких дисков (операционные системы CP/M, MS DOS 1,0). Система имеет ограничения на длину имени (не более 8 алфавитно-цифровых символов и не более 3 символов расширения имени файла); ре-гистр символов в именах не различается. Система имеет низкую отказо-устойчивость. Преимуществом FAT являются широкая распространенность и поддержка большинством ОС. Различают две версии FAT: FAT16 и FAT32, использующие для адресации 16 и 32 бита соответственно, а в результате ад-ресующие поле 216 и 232 кластеров.

Файловая система HPFS (High Performance File System). Высокопро-изводительная файловая система, разработанная совместно корпорациями IBM и Microsoft, позволяет преодолеть ряд недостатков FAT, а имнено:

Page 42: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

42

- использовать имена файлов до 255 символов с прописными и заглав-ными буквами;

- распределять информацию на диске не кластерами, как в FAT, а фи-зическими секторами по 512 байт;

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

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

- уменьшать непроизводительные затраты памяти, вызванные больши-ми размерами кластеров.

Файловая система NTFS (NT File System) — разработка компании Mi-crosoft, является развитием файловой системы HPFS. Она поддерживает дис-ки объемом до 16 777 216 терабайт и содержит две копии MFT (Master File Table) с системой транзакций (запросов на изменение данных) при записи файлов на диск, что увеличивает надежность. NTFS гарантирует сохранность данных в случае копирования, перемещения и удаления файлов или папок, даже если при этом произойдет программно-аппаратный сбой или отключе-ние электропитания.

Файловая система UFS (Unix File System) – предназначена для работы с операционной системой Unix. Особенностью системы является возмож-ность выделения атрибутов файла в отдельном объекте файловой системы – inode, что позволяет иметь доступ к файлу (к набору данных хранящихся в файле) более чем по одному имени. Такой подход повышает эффективность функционирования системы.

Файловая система EXT2FS поддерживается ОС Linux. Эта система позволяет использовать имена файлов длиной до 255 символов и различает символы заглавных и прописных букв, поддерживает работу в локальных и глобальных сетях.

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

Page 43: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

43

Эволюция файловых систем была напрямую связана с развитием тех-нологий реляционных баз данных, которые активно использовались при про-ектировании файловых систем. Так даже понятие «файл» претерпело изме-нения в его толковании – от первоначального, как упорядоченной последова-тельности логических записей, до понятия файла, как объекта, имеющего на-бор характеризующих его атрибутов (включая имя файла, его псевдоним, время создания и собственно данные), реализованного в структуре NTFS.

Дальнейшая эволюция файловых систем пойдет по пути совершенство-вания механизмов хранения данных, оптимизации хранения мультимедий-ных данных, использования новых технологий, применяемых в базах данных.

2.1.4 Виды операционных систем

В настоящее время наиболее распространенными и известными ОС яв-ляются следующие:

- операционную систему MS-DOS; - семейство операционных систем MS Windows; - семейство операционных систем Unix; - операционную систему Linux; - некоторые сетевые операционные системы. Операционная система MS-DOS. Операционная система MS DOS

(Microsoft Disk Operating System) — самая распространенная ОС на 16-разрядных персональных компьютерах (рис. 2.2).

Рис. 2.2. Состав операционной системы MS DOS

Она состоит из следующих основных модулей: - базовая система ввода-вывода (BIOS); - блок начальной загрузки (Boot Record);

Page 44: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

44

- модуль расширения базовой системы ввода-вывода (IO.SYS); - модуль обработки прерываний (MSDOS.SYS); - командный процессор (COMMAND. COM); - утилиты MS DOS. Каждый из указанных модулей выполняет определенную часть функ-

ций, возложенных на ОС. Места постоянного размещения этих модулей раз-личны.

Блок начальной загрузки (или просто загрузчик) — это очень короткая программа, единственная функция которой заключается в считывании с дис-ка в оперативную память двух других частей DOS — модуля расширения ба-зовой системы ввода-вывода и модуля обработки прерываний.

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

Драйвер внешнего устройства – специальная программа разработанная для конкретного внешнего устройства, обеспечивающая обмен информацией центрального процессора с внешним устройством.

Модуль обработки прерываний реализует основные высокоуровневые услуги DOS, поэтому его и называют основным.

Командный процессор DOS обрабатывает команды, вводимые пользо-вателем.

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

MS DOS была заменена ОС Windows — 32-разрядной многозадачной и многопоточной операционной системой с графическим интерфейсом и рас-ширенными сетевыми возможностями.

Операционные системы MS Windows. Существует целый ряд опера-ционных систем MS Windows, используемых в настоящее время. Рассмотрим некоторые из них.

Windows 95 представляет собой универсальную высокопроизводитель-ную многозадачную 32-разрядную ОС с графическим интерфейсом и расши-ренными сетевыми возможностями. Windows 95 — интегрированная среда, обеспечивающая эффективный обмен информацией между отдельными про-граммами и предоставляющая пользователю широкие возможности работы с мультимедиа, обработки текстовой, графической, звуковой и видеоинформа-

Page 45: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

45

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

Windows 98 отличается от Windows 95 тем, что в ней операционная система объединена с браузером Internet Explorer. Кроме этого, в ней улуч-шена совместимость с новыми аппаратными средствами компьютера, она одинаково удобна как для использования на настольных, так и на портатив-ных компьютерах.

Windows NT (NT— от англ. New Technology) — 32-разрядная ОС со встроенной сетевой поддержкой и развитыми многопользовательскими сред-ствами. Она предоставляет пользователям многозадачность, надежность, многопроцессорную поддержку, секретность, защиту данных и многое дру-гое. Эта операционная система очень удобна для пользователей, работающих в рамках локальной сети, для коллективных пользователей, особенно для групп, работающих над большими проектами и обменивающихся данными.

Windows 2000 — операционная система на базе технологии NT, ориен-тированная прежде всего на работу с бизнес-приложениями для делового ис-пользования на самых разнообразных компьютерах — от портативных до серверов. Эта ОС является одной из лучших для ведения коммерческой дея-тельности в Интернете. Windows 2000 выпускается в следующих вариантах — универсальном (Windows 2000 Professional) и серверных (Windows 2000 Server, Advanced Server и DataCenter Server). В Windows 2000 включен ряд усовершенствований для работы с Интернетом. Она объединяет присущую Windows 98 простоту использования с присущими Windows NT надежно-стью, экономичностью и безопасностью.

Windows XP, (символы XP являются сокращением от английского eXPerience — опыт) – операционная система основанная на ядре NT и не поддерживает DOS. Основные отличительные качества данной ОС — полно-стью переработанный интерфейс и высокая стабильность. Система ориенти-рована на работу с Интернетом, службами ASP и рядом других сетевых тех-нологий. Кроме того, владельцы Windows XP смогут подключаться к своим компьютерам с помощью удаленного доступа. Windows XP предлагается в различных версиях: Windows XP Home Edition предназначена для домашних

Page 46: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

46

пользователей, Windows XP Professional — для корпоративных пользовате-лей и учебных заведений. Наиболее заметным новшеством Windows XP стал полностью переработанный пользовательский интерфейс. Он стал более кра-сочным и удобным: используется новая цветовая гамма, геометрические формы стали более плавными и объемными, в папках появились контекстные меню с наборами наиболее частых операций. В Windows XP задействованы новые методы работы с удаленными системами. Пользователи могут полу-чить доступ к своему компьютеру с другого компьютера, работающего под управлением Win9x/ME/2000/XP с помощью протокола RDP (Remote Desktop Protocol). Операционная система Windows XP поддерживает новейшие стан-дарты чтения DVD-дисков.

Windows Server 2003 – серверная многозадачная операционная система, способная централизовано или распределено управлять различными набора-ми ролей, в зависимости от потребностей пользователей. Некоторые из ролей сервера: файловый сервер и сервер печати; веб-сервер и веб-сервер приложе-ний; почтовый сервер; сервер терминалов; сервер удаленного доступа; сервер виртуальной частной сети (VPN); служба каталогов; система доменных имен (DNS); сервер протокола динамической настройки узлов (DHCP) и служба Windows Internet Naming Service (WINS); сервер потокового мультимедиа-вещания. Windows Server 2003 основана на технологиях надежности ОС Windows 2000 Server. Надежность и безотказность в работе, доступность, масштабируемость и безопасность делают Windows Server 2003 платформой высокой надежности.

Packet (Windows CE) — операционная система для мобильных вычис-лительных устройств, таких как карманные компьютеры, цифровые инфор-мационные пейджеры, сотовые телефоны, мультимедийные и развлекатель-ные приставки, включая DVD-проигрыватели и устройства целевого доступа в Интернет. Это 32-разрядная, многозадачная, многопоточная операционная система, имеющая открытую архитектуру, разрешающую использование множества устройств. Packet (Windows СЕ) позволяет устройствам различных категорий «говорить» и обмениваться информацией друг с другом, связы-ваться с корпоративными сетями и с Интернетом, пользоваться электронной почтой. Она компактна, но высокопроизводительна. Это мобильная система, функционирующая с микропроцессорами различных марок и изготовителей.

Windows Vista – новая операционная система, которая намного проще и дружественней в обращении, чем Windows XP. Vista по-испански и по-итальянски означает «взгляд, взор», на латыни – «дорога в будущее», «пер-

Page 47: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

47

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

Операционная система Unix. Операционная система Unix была соз-дана в Bell Telephone Laboratories. Unix — многозадачная операционная сис-тема, способная обеспечить одновременную работу очень большого количе-ство пользователей. Ядро ОС Unix написано на языке высокого уровня Си и имеет только около 10% кода на ассемблере. Это позволяет за считанные ме-сяцы переносить ОС Unix на другие аппаратные платформы и достаточно легко вносить в нее серьезные изменения и дополнения. Unix является пер-вой действительно переносимой операционной системой. В многочисленные существующие версии Unix постоянно вносятся изменения. С одной сторо-ны, это расширяет возможности системы, делает ее мощнее и надежнее, с другой — ведет к появлению различий между существующими версиями. В связи с этим возникает необходимость стандартизации различных свойств системы. Наличие стандартов облегчает переносимость приложений между различными версиями Unix и защищает как пользователей, так и производи-телей программного обеспечения. Поэтому в 80-х годах разработан ряд стан-дартов, оказывающих влияние на развитие Unix. Сейчас существуют десятки операционных систем, которые можно объединить под общим названием Unix. В основном это коммерческие версии, выпущенные производителями аппаратных платформ для компьютеров своего производства. Основными факторами, обеспечивающим популярность Unix, являются следующие:

1) Код системы написан на языке высокого уровня С, что сделало ее простой для понимания, изменения и переноса на другие платформы. Можно смело сказать, что Unix является одной из наиболее открытых систем.

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

3) Наличие стандартов. Несмотря на разнообразие версий Unix, осно-вой всего семейства являются принципиально одинаковая архитектура и ряд стандартных интерфейсов. Для администратора переход на другую версию

Page 48: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

48

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

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

5) Использование единой, легко обслуживаемой иерархической фай-ловой системы. Файловая система Unix — это не только доступ к данным, хранящимся на диске. Через унифицированный интерфейс файловой системы осуществляется доступ к терминалам, принтерам, сети и т. п.

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

Операционная система Linux. Начало созданию системы Linux поло-жено в 1991 г. финским студентом Линусом Торвальдсом (Linus Torvalds). 3 сентябре 1991 г. он распространил по Интернету первый прототип своей опе-рационной системы и призвал откликнуться на его работу всех, кому она нравится или нет. С этого момента многие программисты стали поддержи-вать Linux, добавляя драйверы устройств, разрабатывая различные приложе-ния и др. Атмосфера работы энтузиастов над полезным проектом, а также свободное распространение и использование исходных текстов стали осно-вой феномена Linux. В настоящее время Linux — очень мощная система, и при этом она бесплатная.

Л. Торгвальдс разработал не саму операционную систему, а только ее ядро, подключив уже имеющиеся компоненты. Сторонние компании, увидев хорошие перспективы для развития своего бизнеса, довольно скоро стали на-сыщать ОС утилитами и прикладным программным обеспечениеям. Недос-таток такого подхода — отсутствие унифицированной и продуманной проце-дуры установки системы, и это до сих пор является одним из главных сдер-живающих факторов для более широкого распространения Linux. Иными словами, разработка Linux — это метод проб и ошибок, построенный на ин-тенсивном тестировании.

Сетевые операционные системы. В настоящее время наибольшее распространение получили три основные сетевые ОС — UNIX, Windows NT и Novell Netware.

ОС UNIX применяют преимущественно в крупных корпоративных се-тях, поскольку эта система характеризуется высокой надежностью, возмож-

Page 49: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

49

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

ОС Windows NT включает в себя серверную (Windows NT Server) и клиентскую (Windows NT Workstation) версии и тем самым обеспечивает ра-боту в системах «клиент-сервер». Windows NT обычно применяют в средних по масштабам сетях.

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

2.1.5 Операционные оболочки

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

Наиболее популярны следующие виды текстовых и графических обо-лочек операционной системы Windows (MS DOS):

- Norton Commander; - Volkov Commander; - Total Commander - Far Manager; - Windows Commander; - XTree Gold 4.0 и др. Эти программы существенно упрощают задание управляющей инфор-

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

Например, пакет программ Total Commander обеспечивает: - создание, копирование, пересылку, переименование, удаление, поиск

файлов, а также изменение их атрибутов; - отображение дерева каталогов и характеристик входящих в них фай-

лов в форме, удобной для восприятия человека;

Page 50: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

50

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

2.1.6 Сетевое программное обеспечение

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

Основными функциями сетевых ОС являются: - управление каталогами и файлами; - управление ресурсами; - коммуникационные функции; - защита от несанкционированного доступа; - обеспечение отказоустойчивости; - управление сетью. Управление каталогами и файлами в сетях заключается в обеспечении

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

Управление ресурсами включает в себя обслуживание запросов на пре-доставление ресурсов, доступных по сети.

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

Защита от несанкционированного доступа. Разграничение прав дос-тупа — важная функция, способствующая поддержанию целостности данных

Page 51: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

51

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

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

Под отображением обычно понимают наличие в системе двух копий данных с их расположением на разных дисках, но подключенных к одному контроллеру.

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

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

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

Page 52: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

52

характеристиками «интеллектуальности», скорости, объема буферной памя-ти.

2.2 ПРИКЛАДНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ КОМПЬЮТЕРОВ

Прикладное ПО обеспечивает решение пользовательских задач. Клю-чевым понятием здесь является пакет прикладных программ (ППП).

Пакет прикладных программ (application program package) – комплекс взаимосвязанных программ для решения задач определенного класса кон-кретной предметной области.

Различают следующие типы ППП: - общего назначения; - методо-ориентированные; - проблемно-ориентированные.

2.2.1 Прикладное программное обеспечение общего назначения

ППП общего назначения ориентированы на автоматизацию широкого класса задач пользователя. К этому классу ППП относятся:

- текстовые процессоры (MS Word); - издательские системы (PageMaker, Quark XPress); - графические редакторы (растровые – Paint, Adobe Photoshop и т.д.;

векторные – CorelDraw, Adobe Illustrator, 3-D Studio и др.); - табличные процессоры (MS Excel, Lotus 1-2-3); - системы управления базами данных (FoxPro, Paradox, MS Access); - системы динамических презентаций (MS PowerPoint); - интегрированные пакеты (MS Office, МS Works); - системы автоматизации проектирования (CASE-технологии); - системы автоматизированного перевода (Promt XP, Styles); - системы распознавания изображения (FineReader); - системы распознавания речи; - оболочки экспертных систем; - систем поддержки принятия решений и др. Рассмотрим назначение некоторые из названных ППП. Текстовый редактор — программа, используемая специально для

ввода и редактирования текстовых данных.

Page 53: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

53

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

- редактирование строк текста; - возможность использования различных шрифтов символов; - копирование и перенос части текста с одного места на другое или из

одного документа в другой; - контекстный поиск и замену частей текста; - задание произвольных межстрочных промежутков; - автоматический перенос слов на новую строку; - автоматическую нумерацию страниц; - обработку и нумерацию сносок; - выравнивание краев абзаца; - создание таблиц и построение диаграмм; - проверку правописания слов и подбор синонимов; - построение оглавлений и предметных указателей; - распечатку подготовленного текста на принтере в нужном количестве

экземпляров и т. п. Наиболее известный текстовый редактор — Microsoft Word. Возможности текстовых редакторов различны — от программ, предна-

значенных для подготовки небольших документов простой структуры, до программ для набора, оформления и полной подготовки к типографскому из-данию книг и журналов (издательские системы). Наиболее широко исполь-зуемые из них PageMaker, Quark XPress.

Графический редактор — это программа, предназначенная для авто-матизации процессов построения на экране дисплея графических изображе-ний.

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

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

ППП графических редакторов: Paint, Adobe Photoshop, CorelDraw, Adobe Illustrator, 3-D Studio.

Page 54: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

54

Табличный процессор — комплекс взаимосвязанных программ, пред-назначенных для обработки электронных таблиц.

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

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

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

Столбцам и строкам можно присваивать наименования. Экран монито-ра трактуется как окно, через которое можно рассматривать таблицу целиком или по частям.

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

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

Самые популярные табличные процессоры — Microsoft Excel и Lotus 1-2-3.

В Microsoft Excel автоматизированы многие рутинные операции, спе-циальные шаблоны помогают создавать отчеты, импортировать данные и многое другое.

Lotus 1-2-3 — профессиональный процессор электронных таблиц. Ши-рокие графические возможности и удобный интерфейс пакета позволяют бы-стро ориентироваться в нем. С его помощью можно создать любой финансо-вый документ, отчет для бухгалтерии, составить бюджет, а затем разместить все эти документы в базах данных.

База данных — это один или несколько файлов данных, предназначен-ных для хранения, изменения и обработки больших объемов взаимосвязан-ной информации.

Page 55: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

55

В базе данных предприятия, например, может храниться: - вся информация о штатном расписании, о рабочих и служащих пред-

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

систем управления базами данных (СУБД). Система управления базами данных (СУБД) — система программно-

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

СУБД обеспечивают правильность, полноту и непротиворечивость данных, а также удобный доступ к ним.

Наиболее популярные СУБД — FoxPro, MS Access, Paradox. Для менее сложных применений вместо СУБД используются информа-

ционно-поисковые системы (ИПС), которые выполняют следующие функ-ции:

- хранение большого объема информации; - быстрый поиск требуемой информации; - добавление, удаление и изменение хранимой информации; - вывод ее в удобном для человека виде. Системы динамических презентаций – ППП, предназначенные для

визуальной поддержки докладов, выступлений, лекций и т.п. Представителем таких систем является MS PowerPoint.

Интегрированные пакеты представляют собой набор нескольких программных продуктов, объединенных в единый удобный инструмент.

Наиболее развитые из них состоят из текстового редактора, органайзе-ра, электронной таблицы, СУБД, средств поддержки электронной почты, программы создания презентационной графики.

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

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

Page 56: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

56

Наиболее распространенным интегрированным пакетом является Mi-crosoft Office. В этот мощный профессиональный пакет вошли такие необхо-димые программы, как текстовый редактор Word, электронная таблица Excel, программа создания презентаций PowerPoint, СУБД Access, средство под-держки электронной почты Mail. При этом, все части этого пакета составля-ют единое целое, и даже внешне все программы выглядят единообразно, что облегчает как их освоение, так и ежедневное использование.

2.2.2 Методо-ориентированные прикладное программное обеспечение

В основе методо-ориентированных ППП лежит реализация разнооб-разных экономико-математических методов решения задач:

- математического программирования (линейного, динамического, ста-тистического и др.)

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

граммных средств моделирования сложных дискретных систем на персо-нальных ЭВМ является ППП GPSS (General Purpose Simulating System). Он успешно используется для моделирования систем, формализованных в виде схем массового обслуживания.

На сегодняшний день среди широко известных программных сред для проведения научно-технических расчетов можно выделить: MathCAD, Mat-Lab и Mathematica.

Важным достоинством среды MathCAD является возможность записи алгоритмов в естественном научно-техническом виде. Данная среда на сего-дняшний день является одной из наиболее удобных сред для проведения ма-тематических расчетов. В последних реализациях MathCAD значительно об-легчен ввод математических выражений, увеличено число встроенных про-цедур и приложений, расширены возможности языка программирования, усовершенствованы средства обмена с Windows приложениями.

Среда MatLab (Matrix Laboratory — матричная лаборатория) представ-ляет собой апробированную и надежную систему, рассчитанную на решение широкого круга инженерных задач с представлением данных в универсаль-ной матричной форме. Среда MatLab позволяет применять символьную за-пись математических выражений. Широкому применению MatLab при ими-тационном моделировании способствует не только разнообразный набор

Page 57: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

57

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

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

2.2.3 Проблемно-ориентированное прикладное программное обеспечение

Проблемно-ориентированные ППП направлены на решение определен-ной задачи (проблемы) в конкретной предметной области. Это наиболее ши-рокий класс пакетов прикладных программ. Среди них следует выделить: системы проектирования в различных областях знаний, банковские пакеты, пакеты бухгалтерского учета, финансового менеджмента, правовых справоч-ных систем и др. К пакетам по проектированию можно отнести все пакета CAD (Computer Aid Design), для проектирования электронных устройств (PCAD), технического конструирования (AutoCAD), проектирования в облас-ти архитектуры и дизайна (ArhiCAD) и др.

К ППП бухгалтерского учета и управления предприятием относятся: 1C: бухгалтерия, 1C: предприятие, ГАЛАКТИКА, BEST и др. Правовые спра-вочные пакеты: Консультант Плюс, Эталон и др.

2.3 ИНСТРУМЕНТАРИЙ ТЕХНОЛОГИЙ ПРОГРАММИРОВАНИЯ

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

Page 58: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

58

тестирования создаваемых программ. Пользователями технологии програм-мирования выступают системные и прикладные программисты.

Инструментарий технологии программирования — совокупность про-грамм и программных комплексов, обеспечивающих технологию разработки, отладки и внедрения создаваемых программ.

Разбиение на группы инструментальных средств технологии програм-мирования показано на рис. 2.3.

Рис. 2.3. Классификация инструментария технологии программирования

Средства для создания приложений включают: — локальные средства, обеспечивающие выполнение отдельных работ

по созданию программ; — интегрированные среды разработчиков программ, обеспечивающие

выполнение комплекса взаимосвязанных работ по созданию программ. Локальные средства разработки программ состоят из языков и систем

программирования, а также инструментальной среды пользователя. Язык программирования — формализованный язык для описания алго-

ритма решения задачи на компьютере. Языки программирования, если в качестве признака классификации

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

- машинные языки (computer language) — языки программирования, воспринимаемые аппаратной частью компьютера (машинные коды);

Page 59: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

59

- машинно-ориентированные языки (computer-oriented language) — языки программирования, которые отражают структуру конкретного типа компьютера (ассемблеры);

- алгоритмические языки (algorithmic language) — не зависящие от ар-хитектуры компьютера языки программирования для отражения структуры алгоритма (Паскаль, Фортран, Бейсик и др.);

- процедурно-ориентированные языки (procedure-oriented language) — языки программирования, где имеется возможность описания программы как совокупности процедур (подпрограмм);

- проблемно-ориентированные языки (universal programming language) — языки программирования, предназначенные для решения задач опреде-ленного класса (Лисп, Симула и др.);

- интегрированные системы программирования. Программа, подготовленная на языке программирования высокого

уровня, проходит этап трансляции. Трансляторы реализуются в виде компиляторов или интерпретаторов.

С точки зрения выполнения работы компилятор и интерпретатор существен-но различаются.

Компилятор (compiler — составитель, собиратель) читает всю про-грамму целиком, делает ее перевод и создает законченный вариант програм-мы на машинном языке, который затем и выполняется.

Интерпретатор (interpreter — истолкователь, устный переводчик) пе-реводит и выполняет программу построчно.

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

Откомпилированные программы работают быстрее, но интерпретируе-мые проще исправлять и изменять.

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

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

ранять ошибки в программе;

Page 60: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

60

- «дружественная» к пользователю диалоговая среда; - многооконный режим работы; - мощные графические библиотеки; - утилиты для работы с библиотеками; - встроенный ассемблер; - встроенная справочная служба и др. Инструментальная среда пользователя представлена специальными

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

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

CASE-технология (Computer-Aided System Engineering), представляю-щая методы анализа, проектирования и создания программных систем и предназначенная для автоматизации процессов разработки и реализации ин-формационных систем.

2.4 ОБРАБОТКА ПРОГРАММ НА КОМПЬЮТЕРАХ

Рассмотрим последовательность выполнения программ. В процессе разработки программа проходит ряд преобразований и различных представ-лений.

Исходный модуль (source code) – это текст программы на языке про-граммирования.

Page 61: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

61

Объектный модуль (оbject code) – результат обработки компилятором исходного модуля. Объектный модуль не может быть выполнен. Это неза-вершённый вариант машинной программы. К объектному модулю в общем случае должны быть подсоединены модули стандартной библиотеки и он должен быть настроен на конкретный адрес памяти по месту выполнения.

Исполняемый (executive) модуль создаётся с помощью компоновщика (linker), который объединяет в один общий модуль объектные модули, реали-зующие отдельные части алгоритма. На этом этапе к машинной программе подсоединяются необходимые функции стандартной библиотеки.

Стандартная библиотека (library) – набор программных модулей вы-полняющих наиболее часто встречающиеся в программировании задачи: ввод, вывод данных, вычисление математических функций, сортировки, ра-бота с памятью и т.д. Модули библиотеки хранятся в откомпилированном виде.

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

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

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

Директивы препроцессора начинаются знаком # (hash). Директива мо-жет занимать несколько строк. В конце каждой строки, имеющей продолже-ние (т.е. кроме последней), ставится обратная косая черта.

Например,

#define text \\Этот текст \\будет замещать \\слово text в программе.

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

Например,

Page 62: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

62

#include<stdio.h> #include<iostream.h> #include<math.h> #include<alloc.h>

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

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

#include "progr.cpp"

препроцессор данную директиву заменит текстом исходного модуля имею-щего имя progr.cpp.

Если имя задано в знаках < >, то поиск файла с этим именем выполня-ется в системных каталогах, т.е. в системной библиотеке языка С/С++.

Обычно в " " указывается имя файла программиста, текст которого не-обходимо включить в программу (в С++ это имя можно записывать и в зна-ках < >). Имя записывается либо с указанием полного пути к файлу, либо (как выше) поиск файла будет осуществляться только в текущем каталоге.

Процесс обработки программы в интегрированной среде можно пред-ставить в виде схемы, приведенной на рис. 2.4.

Page 63: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

63

Рис. 2.4. Схема обработки программ на ПЭВМ

Из рисунка 2.4 схемы видно, что разработанная на исходном языке программа (в данном примере prog.cpp) проходит все вышеперечисленные стадии компиляции, компоновки, отладки и выполнения.

Тема3 ОСНОВНЫЕ ЭЛЕМЕНТЫ ЯЗЫКА Си

3.1 Введение в язык Си

Целью большинства программ является решение какой-либо задачи пу-тем различных преобразований исходных данных. Для этого необходимо:

1) ввести данные в программу; 2) установить места для хранения информации (выделить область па-

мяти); 3) реализовать инструкции обработки информации;

Page 64: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

64

4) вывести информацию из программы; 5) организовать выполнение некоторых инструкций лишь тогда, когда

какое-либо условие либо набор условий дает требуемое значение (например, истинное или ложное);

6) реализовать возможность повторения инструкции или группы инст-рукций некоторое число раз;

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

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

Ввод – чтение данных с клавиатуры, магнитного диска, порта ввода-вывода или из другой программы.

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

Операторы – присваивают значения переменным, реализуют переходы между различными инструкциями программы, вызывают подпрограммы и т.п. Их важный подкласс составляют операторы перехода и операторы цикла.

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

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

Операторы цикла – реализуют выполнение одной или нескольких ин-струкций заданное число раз либо до тех пор, пока не удовлетворится неко-торое условие.

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

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

Page 65: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

65

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

3.2 Основные элементы языка С/С++

Основными элементами языка Си, как и любого другого алгоритмиче-ского языка высокого уровня, являются:

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

ются определенные символы, составляющие алфавит языка. Множество символов языка Си можно разделить на четыре группы. В первую группу входят буквы латинского алфавита и символ подчер-

кивания. Строчные буквы используются для написания ключевых слов. Оди-наковые строчные и прописные буквы (например а и А) имеют различные коды и при записи идентификаторов различаются. Буквы русского алфавита используются для вывода информации и в комментариях.

Вторую группу символов составляют цифры: 0, 1, …, 9. В третью группу входят специальные символы, приведенные в табли-

це 3.1.

Таблица 3.1. Специальные символы языка Си Символ Название Символ Название

. точка ( круглая скобка левая , запятая ) круглая скобка правая ; точка с запятой [ квадратная открывающая

скобка : двоеточие ] квадратная закрывающая

скобка ? вопросительный

знак { фигурная открывающая

скобка ! восклицательный

знак } фигурная закрывающая

скобка ' апостроф < знак меньше | вертикальная черта > знак больше

Page 66: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

66

/ дробная черта = знак равно \ обратная черта ^ исключающее или ~ тильда & знак амперсанд + плюс % знак процента - минус # номер * звездочка " кавычки

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

Четвертую группу символов составляют управляющие последова-тельности (ESC-последовательности – escape), используемые при вво-де/выводе информации. Управляющая последовательность начинается со знака обратной черты (\).

Идентификатор – это имя, которым обозначается некоторый объект (данное) в программе. Данные в оперативной памяти размещаются по неко-торым адресам, которые программисту заранее неизвестны. Для того чтобы в программе иметь возможность обращаться к этим данным и обрабатывать их, программист этим данным даёт условные имена - идентификаторы, которые компилятор в программе заменит адресами данных в оперативной памяти.

1) Идентификаторы должны обязательно начинаться с буквы латинско-го алфавита (a, …, z, A, …, Z) или с символа подчеркивания (_). Однако не рекомендуется начинать идентификатор со знака подчеркивания, т.к. этот символ используется в именах некоторых библиотечных функций, и при сов-падении имен эти функции будут недоступны программе. Кроме того, к име-нам транслируемых функций, составляющих программу, компилятор автома-тически добавляет первым символом знак подчеркивания.

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

3) При выборе идентификатора необходимо учитывать то, что иденти-фикатор не должен совпадать с именами функций из библиотеки языка С/С++ и ключевыми словами языка.

Примеры идентификаторов: n, m, array, sum, result и т.д.

Ошибочные идентификаторы: n+m, wrong-2, 9illegal, if, int, &f, %d.

Page 67: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

67

4) На длину идентификатора не существует никаких ограничений, од-нако при выполнении программы воспринимаются и используются для выяв-ления различных объектов (имен) только первые 32 символа.

Буквы нижнего регистра (a, …, z), применяемые в идентификаторах, отличаются от букв верхнего регистра (A, …, Z). Это означает, что следую-щие идентификаторы считаются разными: prog, Prog, PROG, pRoG.

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

Таблица 3.2 Ключевые слова языка Си asm else operator throw auto enum private true bool extern protected try break false public typedef case float register typeid catch for return typename char friend short union class goto signed unsigned const if sizeof using continue int static virtual default long struct void delete mutable switch volatile do namespace template wchar_ double New this while

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

Константами называются данные, значения которых во время выпол-нения программы остаются неизменными.

Более подробно назначение переменных и констант будет рассмотрено ниже.

3.3 Типы данных

Программа оперирует с различными данными, которые могут быть простыми (скалярными) и структурированными (составными). Простые данные – это целые и вещественные числа, текст и указатели (адреса), пере-числения. Данные структурированного типа – это массивы, структуры, объе-динения, записи и файлы (рис. 3.1).

Page 68: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

68

Рис. 3.1. Типы данных

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

Таблица 3.3 Типы данных Ключевое слово

Тип данных

int целый float вещественный double вещественный с двоичной точностью char символьный void пустой тип

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

К модификаторам типа относятся (таблица 3.4). Таблица 3.4 Модификаторы типа Ключевое слово

Модификатор типа

unsigned беззнаковый signed знаковый short короткий long длинный

Page 69: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

69

Тип данных и модификатор типа определяют: - формат хранения данных в оперативной памяти (внутреннее пред-

ставление данных); - диапазон значений, в пределах которого может изменяться пере-

менная; - операции, которые могут выполняться над данными соответствую-

щего типа. В зависимости от типа данных и модификатора типа для их обработки

будут использоваться те или иные машинные команды микропроцессора. Множество значений типа void пусто. Он используется: ­ для определения функций, которые не возвращают значений; ­ для указания пустого списка аргументов функции; ­ как базовый тип указателей; ­ в операции приведения типов.

3.4 Базовые типы данных

Данные целого типа. Характеристики данных целого типа приведены в таблице 3.5.

Таблица 3.5 Характеристика данных целого типа

Тип данных Синоним(ы) Размер (байт)

Диапазон значений

signed int signed, int 2 или 4 -32 768 ... 32 767 unsigned int unsigned 2 или 4 0...65 535 signed short int short, signed short 2 -32 768 ... 32 767 unsigned short int unsigned short 2 0 … 65 536 signed long int long, signed long 4 -2 147 483 648 …

2 147 483 647 unsigned long int unsigned long 4 0 ... 4 294 967 295 signed char char 1 -128 ... 127 unsigned char - 1 0 ... 255

Размер типа int зависит от реализации. Для 16-тиразрядного процессо-ра – 2 байта, для тридцатидвухразрядного – 4 байта. Модификатор типа short перед именем типа указывает компилятору, что под число требуется отвести два байта, независимо от разрядности процессора. Модификатор типа long означает, что целая величина занимает 4 байта. Таким образом, на 16-

Page 70: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

70

тиразрядном процессоре эквивалентны типы int и short int, а на 32-хразрядном – int и long int.

Внутреннее представление величины целого типа – целое число в дво-ичном коде. При использовании модификатора типа signed старший бит чис-ла интерпретируется как знаковый (0 – положительное число, 1 – отрица-тельное). Модификатор типа unsigned позволяет представлять только поло-жительные числа, поскольку старший разряд рассматривается как часть кода числа.

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

Вещественный тип данных. Числа с дробными компонентами пред-ставляются типами с плавающей точкой. Таких типов только три: float, double и long double (таблице 3.6). Внутреннее представление для типов с плавающей точкой состоит из двух частей – мантиссы M и порядка P. Длина мантиссы определяет точность числа, а длина порядока – диапазон числа.

PMC 2*= Таблица 3.6 Характеристика данных вещественного типа

Ключевое слово

Размер в байтах

Диапазон

float 4 1.17E-38…3.17E+38 double 8 2.23E-308…1.67E+308 long double 10 3.37E-4932…1.2E+4932

Величина типа float занимает 4 байта, из которых один двоичный раз-ряд отводиться под знак мантиссы, 8 разрядов под порядок и 23 под мантис-су.

Для величины типа double, занимающей восемь байт, под порядок и мантиссу отводятся соответственно 11 и 52 разряда.

Модификатор типа long перед именем типа double указывает, что под число отводиться 10 байт.

Символьные данные. Данные типа char занимают в памяти 1 байт. Код от 0 до 255 в этом байте задает один из 256 возможных символов. Тип char является типом «целое». Данные типа char могут рассматриваться и как дан-ные со знаком signed char и без знака unsigned char.

Константа типа char – это символ, заключенный в одинарные кавычки. Например: 'a', 'c'. Каждому символу ставиться в соответствие некоторый код.

Page 71: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

71

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

Пример объявления символьных данных.

char g,h;

Здесь g и h символьные переменные. Они могут принимать значения, совпадающие с символами кодовой таблицы ASCII. Например, оператор присвоения вида

g='Q'; h='h';

присваивает переменным g и h конкретные значения символов Q и h из таб-лицы кодов (рис. 3.2,а). В результате операции в ячейке памяти, которая за-резервирована для переменной g, будет записан код символа Q, а для пере-менной h – код символа h. В данном случае переменная h и значение h это не одно и тоже. Например, можно присвоить переменным g и h новые значения: g='q'; h='и'; (рис. 3.2,б). Естественно, что значения g и h могут быть не только буквы, например, g='3'; h='!' (рис. 3.2,в).

Рис. 3.2. Значения и коды символов

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

В символьных и строковых константах могут использоваться специ-альные управляющие знаки (таблица 3.7).

Таблица 3.7 Специальные управляющие знаки

Page 72: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

72

Управляющий знак Наименование Код \n Переход на новую строку \х0A \t Горизонтальная табуляция \x09 \v Вертикальная табуляция \x0B \b Возврат на одну позицию \x08 \r Перевод курсора в начало строки \x0C \f Новая страница \x0D \a Звонок (сигнал) \x07 \' Одиночная кавычка \x27 \" Двойная кавычка \x22 \\ Наклонная черта влево (обратный слэш) \x5C

\ddd ASCII символ в восьмеричном представ-лении

\xdd ASCII символ в шестнадцатеричном представлении

Строка - это нуль или более символов, заключённых в двойные кавыч-ки. Например: "СТРОКА". Кавычки не входят в строку. Фактически строко-вая константа – это массив символов. Во внутреннем представлении строки в конце автоматически помещается нуль-символ ('\0'), поэтому для строки требуется память на один байт больше, чем количество символов между двойными кавычками.

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

Пример:

enum name {Anna, Vera, Masha, Nina, Toma, Ira};

Здесь мы ввели свой тип name и seasons. Определим переменную типа name:

enum name girl;

Переменная girl может принимать значение из списка, перечисленного в фигурных скобках. Каждому значению из списка соответствует порядковое число, начиная с нуля, т.е. в фигурных скобках введены именованные кон-станты:

Anna=0, Vera=1, Masha=2, Nina=3, Toma=4, Ira=5

Page 73: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

73

Именованным константам в списке можно задать значение не по по-рядку, например:

enum name {Anna=1, Vera, Masha=5, Nina, Toma, Ira=9};

В этом случае значения именованных констант будут следующими:

Anna=1, Vera=2, Masha=5, Nina=6, Toma=7, Ira=9

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

Именованные константы списка имеют тип int. Переменные типа enum могут использоваться в индексных выражениях, как операнды в арифметиче-ских выражениях и в операциях отношения. Имя константы из списка пере-числения эквивалентно ее числовому значению.

При объявлении типа перечисление необходимо соблюдать следующие правила:

­ идентификаторы в списке перечисление не должны совпадать с дру-гими идентификаторами той же области видимости;

­ объявляемый тип перечисление (имя) должно быть отлично от других имен типов вводимых пользователем в той же области видимости;

­ именованным константам можно устанавливать одинаковые (повто-ряющиеся) значения, однако имена в списке должны быть разными.

Указатели. Указатель – переменная, которая содержит адрес элемента памяти, где записано значение другой переменной. Таким образом, так как указатель – это адрес некоторого объекта, то через него можно обратиться к этому объекту. Имя переменной-указателя начинается с символа звездочка (*). Тип переменной-указателя должен быть объявлен до момента ее исполь-зования.

Пример:

int *a, *b, *point;

Более подробно использование указателей и операции с ними будет рассмотрены ниже.

3.5 Структура простой программы

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

Page 74: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

74

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

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

Тело функции состоит из операторов и заключается в фигурные скобки {}. Оператор представляет собой законченную инструкцию для компьютера. В конце каждого оператора, а также каждой строки с обращением к функции ставиться точка с запятой (;). Исключение составляют команды препроцессо-ра и имена функций, стоящие в начале программной единицы. Структуры программ на языке Си представлены на рис. 3.3 и 3.4.

main () { Тело программы

} Рис. 3.3. Структура программы без обращения к подпрограммам

main () {

Тело программы (обращение к функции fun)

} fun () {

Тело функции fun }

Рис. 3.4. Структура программы с обращением к подпрограмме

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

Рассмотрим пример программы на языке Си, которая выводит на экран сумму и произведение двух целых чисел. Кроме этого функция main обраща-ется к другой функции – fun, которая выводит на экран сообщение.

Пример:

#include<stdio.h> main() //тело функции main { void fun(void); //прототип функции fun int a=10, b=5, sum; //определение данных

Page 75: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

75

sum=a+b; //вычисления printf("a+b=%d a*b=%d\n", sum, a*b); //вывод результата fun(); //обращение к функции fun return 0; //завершает функцию } void fun() //тело функции fun { puts("Function fun"); }

В первой строке указана команда препроцессора #include, по которой к программе будет подсоединен раздел системной библиотеки, содержащий функции ввода/вывода на стандартные устройства (клавиатуру – stdin и эк-ран – stdout). stdio.h – имя этого раздела (standard input / output header).

Переменные. Объявление и определение. Данные, значение которых во время выполнения программы можно изменять называются переменными, неизменяемые данные называются константами. В программе все данные перед их использованием должны быть объявлены или определены. В опера-торах определения данных указывается тип данных, и перечисляются через запятую имена переменных имеющих данный тип. В модуле, в котором запи-сано определение переменных, для каждой переменной в соответствии с ти-пом выделяются необходимое количество байт памяти. Выделенному полю байт памяти присваивается имя переменной (константы), которое в дальней-шем используется в программе. Адрес размещения значения переменной можно получить программным путем.

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

Определение переменных в общем случае имеет следующий формат:

[класс-памяти] тип имя_переменной1 [=начальное значение] [, имя_переменной2 [=начальное значение] ];

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

Page 76: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

76

*(звездочка). Дополнительная информация будет дана в следующих темах. При определении переменных им можно присвоить начальное значение.

Тип – одно или несколько ключевых слов, определяющих тип перемен-ной.

Класс памяти определяет каким образом для объявляемой переменной распределяется память и в каких фрагментах программы можно использовать ее значение. Класс памяти определяется четырьмя ключевыми словами: auto, extern, register и static. Если ключевое слово, определяющее класс памяти, опущено, то класс памяти определяется по контексту.

Примеры:

char ch, s1[20]; string s; int x, y, count=1; extern int error_number; struct User;

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

Большинство объявлений являются еще и определением, т.е. они опре-деляют некую сущность, которая соответствует имени. Из всех приведенных объявлений только extern int error_number; и struct User; не являются опре-делением. Память для целой переменной error_number выделяется некоторым другим объявлением, и какое-то другое объявление типа User должно опре-делить, как выглядит данный тип переменной.

При определении переменных им можно присвоить начальное значе-ние. Любое объявление, в котором задается значение, является определени-ем.

В программе на Си для каждого имени должно быть ровно одно опре-деление. Объявлений же может быть несколько. Все объявления некой сущ-ности должны согласовываться по типу этой сущности.

Примеры: int count; int count; // Ошибка - повторное определение extern int error_number; extern short error_number; // Ошибка – несоответствие типов

Объявление вводит имя переменной в области видимости. Это значит, что имя переменной может использоваться только в определенной части про-

Page 77: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

77

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

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

Рис. 3.5. Объявление глобальных и локальных переменных

На рис.3.5,а показано место в программе, где объявляются глобальные переменные. Здесь же помечена область их действия. На рис 3.5,б представ-лены возможные места в программе, где объявляются локальные перемен-ные. Если они записаны в списке параметров функции (в круглых скобках), то объявление следует до первой открывающейся фигурной скобки. Для тех локальных переменных, которых нет в списке параметров, объявление дела-ется после первой открывающейся фигурной скобки.

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

Пример:

int x; // глобальная переменная х void f() { int x; // локальная переменная х, скрывает глобальную

Page 78: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

78

x=1; // присвоение локальной переменной х } int k=x; // значение глобальной переменной x // присваивается переменной k

К скрытому глобальному имени можно обратиться с помощью операто-ра разрешения области видимости :: . Не существует способа обращения к скрытой локальной переменной.

Пример:

int x; // глобальная переменная х void f() { int x; // локальная переменная х, скрывает глобальную x=1; // присвоение локальной переменной х ::x=2; // присвоение глобальной переменной х }

Пример ошибочного объявления:

void f1(int x) { int x; // ошибка – повторное определение }

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

Константы. Константой называется данное неизменяемое в процес-се выполнения программы.

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

Целая константа - это целое число записанное в десятичной, шестна-дцатеричной или восьмеричной системе счисления.

Десятичная константа - любое целое десятичное число со знаком или без него и начинающееся со значащей цифры.

Восьмеричная константа - это целое число записанное в восьмеричной системе счисления и начинающееся с обязательного нуля.

Шестнадцатеричная константа начинается с обязательных знаков 0х или 0Х (нуль, х) и является записью числа в шестнадцатеричной системе (таблица 3.8).

Page 79: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

79

Таблица 3.8 Примеры записи целых констант.

Десятичная Восьмеричная Шестнадцатеричная +15 +017 0хf -71 -087 -0x47 379 0573 0x17B

При записи длинных целых (long) констант в конец числа добавляется буква L (l), а для беззнаковых (unsigned) указывается буква U (u), например: 1234567L, 543l, 0xabcd123U, 375u .

Примеры записи символьных констант: 'A' , '9' , '+' , '%' , '-' , '#'. Примеры записи строковых констант: "МИУ", "ЭВМ", "СИ" , "JAVA" ,

"int". В символьных и строковых константах могут использоваться управ-

ляющие знаки, которые были рассмотрены выше (таблица 3.7). Каждая управляющая последовательность представляется как один символ.

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

Таблица 3.9 Примеры вещественных констант

3.14 -0.13 .625 -.375 +1.5 +5. 3.1е0 .31415е1 +0.314159Е+01 314.15926е-2 31е-1 31415Е-04

По умолчанию (при отсутствии суффиксов е, l, L, f, F) константа с пла-вающей точкой имеет тип double.

Определение констант в общем случае имеет следующий формат:

const [тип] имя_константы1=начальное значение [, имя_переменной2=начальное значение];

Примеры определения констант:

const int ik=1, il=-5, ij=17; const float f24=2.4, f13=1.3, f3=3; const unsigned u=113; const k=17;

Комментарии. Для документирования программ и для того, чтобы сделать их более понятными программисты вставляют в код комментарии. Комментарии не оказывают никакого влияния на работу компьютера во вре-мя исполнения программы. Компилятор Си (С++) просто игнорирует ком-ментарии, не создавая для них никакого машинного объектного кода. Ком-ментарии также помогают другим людям прочитать и понять вашу програм-

Page 80: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

80

му, однако слишком многочисленные комментарии могут, наоборот, затруд-нить ее прочтение.

Существует два способа указания на комментарии: традиционный ме-тод Си и метод С++.

Традиционный комментарий Си открываются парой символов /*. При-знаком конца комментария является пара символов */.

Пример:

/* Первая программа на С Лабораторная работа*/ void main () { printf("Welcome to C!\n"); }

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

Пример:

const int N = 200; //N-это число попыток

Разрешается смешанное использование комментариев любого типа в программах С/С++, но комментарии не могут быть вложенными.

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

3.6 Функции ввода-вывода

Функции вывода. Для вывода данных используется наиболее часто ис-пользуется функция printf из стандартной библиотеки Си stdio.h.

Функция printf формально описывается следующим образом:

printf ("управляющая строка", аргумент 1, аргумент 2,…);

Управляющая строка содержит объекты трех типов: - обычные символы, которые просто выводятся на экран монитора (ко-

пируются в стандартный выходной поток); - спецификации преобразования (форматы), каждая из которых вызы-

вает вывод на экран значения основного аргумента из последующего списка; - управляющие символьные константы.

Page 81: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

81

Каждая спецификация преобразования начинается со знака % и закан-чивается некоторым символом, задающим преобразования.

Между знаком % и символом преобразования могут встречаться: - знак минус, указывающий, что преобразованный параметр должен

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

вести, или же количество цифр, которые нужно вывести справа от десятич-ной точки в значениях типа float или double;

- символ длины l, указывающий, что соответствующий аргумент имеет тип long.

Далее записывается один из следующих символов преобразования: d – значением аргумента является десятичное целое число; o – значением аргумента является восьмеричное целое число; x – значением аргумента является шестнадцатеричное целое число; c – значением аргумента является символ; s – значением аргумента является строка символов; e – значением аргумента является вещественное десятичное число в

экспоненциальной форме; f – значением аргумента является вещественное десятичное число с

плавающей точкой; g – используется как %e или %f и исключает вывод незначащих нулей; u – значением аргумента является беззнаковое целое число; p – значением аргумента является указатель (адрес).

Если после знака % записан не символ преобразования, то он выводит-ся на экран. Функция printf использует управляющую строку, чтобы опреде-лить, сколько всего аргументов и каковы их типы.

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

Среди управляющих символов констант могут использоваться управ-ляющие знаки, рассмотренные ранее (см. таблицу 3.7).

Если в управляющей строке встретиться формат, начинающийся со знака %, то из списка аргументов берется соответствующий ему аргумент, значение которого преобразуется в соответствии с типом формата и выво-диться на экран. Число форматов в управляющей строке должно быть равно числу аргументов.

Page 82: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

82

Например, в результате записи оператора вызова функции

printf("\tЭВМ\n%d\n",i);

сначала выполняется горизонтальная табуляция (\t), т.е. курсор сместится от края экрана, затем на экран будет выведено слово ЭВМ, после этого курсор переместится в начало следующей строки (\n), затем будет выведено целое значение переменной i по формату d, и окончательно курсор перейдет в на-чало новой строки (\n). Результат вывода показан на рис. 3.6.

→ЭВМ¶ 1234¶

Рис. 3.6. Результаты вывода на экран дисплея

Для вывода данных могут использоваться две возможные модификации функции printf: cprintf, sprintf, которые имеют подобные форматы и пред-назначены:

- функция cprintf для вывода форматированных данных в текстовое окно;

- функция sprintf для вывода форматированных данных в строку. Для вывода символьных данных могут использоваться функции puts,

которая записывает символьную строку в стандартный поток данных, и put-char, которая записывает символ в стандартный поток вывода.

Функции ввода. Для ввода исходных данных с клавиатуры предназна-чена функция scanf. Функция scanf формально описывается следующим об-разом:

scanf ("управляющая строка", аргумент 1, аргумент 2, …); Аргументы scanf должны быть указателями на соответствующие зна-

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

Управляющая строка содержит спецификации преобразования и ис-пользуется для установления количества и типов аргументов. В нее могут включаться:

- пробелы, - символы табуляции и перехода на новую строку (все они игнориру-

ются);

Page 83: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

83

- спецификации преобразования, состоящие из знака %, возможно сим-вола * (запрещение присваивания), возможно числа, задающего размер поля, и самого символа преобразования;

- обычные символы (считается, что они должны совпадать с очередны-ми неизвестными символами во входном потоке).

В функции scanf допустимы многие из символов преобразования функции printf. Например:

d – на входе ожидается десятичное целое число; o – на входе ожидается восьмеричное целое число; x – на входе ожидается шестнадцатеричное целое число; c – на входе ожидается появление одиночного символа; s – на входе ожидается появление строки символов; f – на входе ожидается появление вещественного числа; u – на входе ожидается появление беззнакового числа; p – на входе ожидается появление указателя (адреса) в виде шестна-

дцатеричного числа. Перед символами d, o, x, f может стоять буква l. В первых трех случаях

переменные должны иметь тип long, а последнем – double. Пример:

scanf (“%d %f %c”, &I,&j,&k);

В результате выполнения данного оператора необходимо ввести с кла-виатуры значения переменных I (десятичное целое число), j вещественное число), k (одиночный символ) которые будут помещены в память по адресам соответствующих переменных. Например I=21, j=4.5, k=П.

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

Для ввода символьных данных в языке Си предусмотрены также две та-кие функции, как gets и getchar. Функция gets предназначена для считывания символьной строки стандартного входного потока и размещения ее по адре-су, заданному указателем. Функция getchar предназначена для считывания символа из входного потока.

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

Пример:

ch=getchar ();

Page 84: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

84

позволяет присвоить переменной ch очередной вводимый символ. Пример:

putchar (ch);

выдает значение переменной ch (а этим значением является тоже символ) в стандартный выходной поток (на экран дисплея). Переменная ch должна иметь тип int или char (типы int и char в языке Си можно использовать в од-ном выражении).

Функция gets считывает символьную строку стандартного входного потока и помещает ее по адресу, заданному указателем buffer. Прием строки заканчивается, если функция обнаруживает символ '\n'. Данный символ уда-ляется и заменяется нуль-терминатором '\0'. Синтаксис:

char *gets(char *buffer);

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

Синтаксис:

int getchar(void);

Функция возвращает считанный символ. Функция putchar записывает символ в стандартный поток вывода.

Синтаксис:

int putchar(int character);

Функция возвращает записанный в поток символ. Функция puts записывает символьную строку в стандартный поток

данных. Нуль-терминатор (\0) строки заменяется символом новой строки (\n). Синтаксис:

int puts(const char *string);

Функция возвращает код переданного символа.

3.7 Выражения и операции

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

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

Операнд – это константная или переменная величина.

Page 85: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

85

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

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

В языке Си существуют следующие виды операций: - арифметические операции; - логические операции; - операции отношений; - операции присваивания; - побитовые операции; - операции адресации/разадресации.

Арифметические операции предназначены для выполнения обычных арифметических действий над операндами и представлены в таблице 3.10

Таблица 3.10. Арифметические операции.

Знак операции Наименование Пример + Сложение a=b+c; если b=6, c=5, то a=11 - Вычитание a=b-c; если b=6, c=5, то a=1 - Арифметическое

отрицание a=-b; если b=6, то a=-6

* Умножение a=b*c; если b=6, c=5, то a=30 / Деление a=b/c; если b=10, c=5, то a=2

% Остаток от деления a=b%c; если b=8, c=5, то a=3

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

Если в выражении появляются операнды различных типов, то они пре-образуются к некоторому общему типу, при этом каждый арифметический операнд подчиняется следующим правилам:

1) операнды типа char и short преобразуются к типу int; 2) операнды типа float преобразуются к типу double; 3) если один из операндов типа double, то второй операнд тоже преоб-

разуется к типу double, и результат будет двойной точности;

Page 86: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

86

4) если один из операндов типа long, то второй операнд преобразуется к типу long, и результат будет long;

5) если один из операндов имеет тип unsigned char или unsigned short преобразуются к типу unsigned int, и результат будет unsigned int;

6) если один из операндов типа unsigned long, то второй операнд преоб-разуется к типу unsigned long, и результат будет unsigned long;

7) если один операнд типа unsigned int, то второй операнд преобразует-ся к unsigned int, и результат будет unsigned int;

8) при использовании модификатора signed имеют место следующие преобразования: char – int (со знаком); unsigned char – int (старший байт всегда нулевой); signed char – – int (в знаковый разряд int передается знак из char); short – int (знаковый или беззнаковый); float – double;

9) если все операнды имеют тип int, то результат будет int.

Логические операции. Логические операции предназначены для выпол-нения логических преобразований над операндами. Перечень логических операций приведен в таблице 3.11

Таблица 3.11. Логические операции

Знак операции Наименование Пример && Логическое "И"

(конъюнкция) а= b && с; если b и с не равны нулю, то а=1, в противном случае а=0

|| Логическое "ИЛИ"

(дизъюнкция)

а= b || с; если b и с равны нулю, то а=0, в противном случае а=1

! Логическое от-рицание

(инверсия)

а= ! b; если b равно нулю, то а=1, ес-ли b не равно нулю, то а=0

Логические операции выполняют следующие действия: логическое от-рицание (!), логическое И (&&) и логическое ИЛИ (||). Операнды логических операций могут быть целого, вещественного или адресного типа. Типы пер-вого и второго операндов могут быть различными. Операнды логических вы-ражений вычисляются слева направо. Если значения первого операнда доста-точно, чтобы определить результат операции (значение первого операнда равно нулю для логического И и единице для логического ИЛИ), то второй операнд не вычисляется.

Логические операции не выполняют стандартные арифметические пре-образования. Вместо этого они вычисляют каждый операнд с точки зрения

Page 87: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

87

его эквивалентности нулю. Результатом логической операции является 0 или 1. Тип результата есть int.

Операции отношений. Операции отношений являются бинарными опе-рациями (таблица 3.12).

Таблица 3.12. Операции отношений

Знак операции Наименование Пример == Сравнение на равенство а == b; вырабатывает 1, если а рав-

но b, и 0 – в противном случае > Больше а > b; вырабатывает 1, если а

больше b, и 0 – в противном случае >= Больше или равно а >= b; вырабатывает 1, если а

больше или равно b, и 0 – в про-тивном случае

< Меньше а < b; вырабатывает 1, если а меньше b, и 0 – в противном случае

<= Меньше или равно а <= b; вырабатывает 1, если а меньше или равно b, и 0 – в про-тивном случае

!= Не равно а != b; вырабатывает 1, если а не равно b, и 0 – в противном случае

Бинарные операции отношений сравнивают значение первого операнда со значением второго. Результатом сравнения является значение переменной равное 1 (true) или 0 (false). Типом результата всегда является int. Операнды могут быть целого, вещественного или адресного типов. Типы первого и вто-рого операндов могут различаться.

Побитовые операции. Побитовые операции выполняются с операндами, представленными в двоичном коде, поразрядно (таблица 3.13).

Таблица 3.13. Побитовые операции

Знак операции Наименование Пример & Поразрядная

конъюнкция а= b & с; если оба сравниваемых би-та единицы, то бит результата равен 1, в противном случае – 0; если b=1010, с=0110, то а=0010

Page 88: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

88

| Поразрядная дизъюнкция

а= b | с; если любой (или оба) из сравниваемых битов равен(ы) 1, то бит результата устанавливается в 1, в противном случае – в нуль; если b=1010, с=0110, то а=1110

^ Поразрядное "Исключающее

ИЛИ"

а= b ^ с; если один из сравниваемых битов равен 0, а второй бит равен 1, то бит результата равен 1, в против-ном случае (оба бита равны 1 или 0) бит результата равен 0; если b=1010, с=0110, то а=1100

~ Поразрядная ин-версия

а= ~ b; если бит единица, то бит ре-зультата равен 0, в противном слу-чае – 1; если b=1010, то а=0101

<< Сдвиг влево а= b << с; осуществляется сдвиг зна-чения b влево на с разрядов; в осво-бодившееся разряды заносятся нули; если b=1011, с=2, то а=101100

>> Сдвиг вправо а= b >> с; осуществляется сдвиг зна-чения b вправо на с разрядов; в ос-вободившееся разряды заносятся ну-ли, (если b имеет тип unsigned) и копия знакового бита в противном случае; если b=1011, с=2, то а=0010

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

Результат операции сдвига не определен, если второй операнд отрица-тельный. Преобразования, выполняемые операторами сдвига, не поддержи-вают левого и правого переполнения. Информация теряется, если результат сдвига не может быть представлен типом первого операнда после преобразо-вания.

Операции присваивания. Операции присваивания в Си могут вычислять и присваивать значения в одной операции (таблица 3.14)

Page 89: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

89

Таблица 3.14. Операции присваивания

Знак операции Наименование Пример = Простое присваивание а = b; а присваивается значение b

++ Унарный инкремент

а++ (++а); значение а увеличивается на единицу

-- Унарный декремент

а-- (--а); значение а уменьшается на единицу

znak= Составная операция присваивания:

znakÎ(*,/,%,+,-,<<, >>,&, |, ^)

a znak= b; понимается как а = a znak b; где znak символ операции; например, а += b, если а=3, b=4, то а=7; если выполняется операция a -=b, то a=-1

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

Унарные операции инкремента (++) и декремента (--) предназначены соответственно для увеличения и уменьшения значения операнда на едини-цу. Операции (++) и (--) можно записывать как после операнда, так и перед ним. В первом случае (a++ и a--) значение операнда a изменяется после его использования в соответствующем выражении, а во втором случае (++a и --a) – перед его использованием.

Пример:

a=b + c++; a1=b1 + (++c1);

Предположим, что b=b1=2, c=c1=4. В первом случае суммируются зна-чения b и c, результат присваивается a, и только после этого значение c уве-личивается на единицу. Поэтому в результате будем иметь: a=6, b=2, c=5. Во втором случае сначала значение c1 увеличивается на единицу, а потом сум-мируются значения b1 и c1, и результат присваивается a1. Таким образом: a1=7, b1=2, c1=5.

Рассмотрим составную операцию присвоения (znak=). В языке Си выра-жение вида

a=a+b;

можно записать в другой форме:

a+=b;

Page 90: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

90

В общем случае последнее выражение понимается как приращение величины a на значение b. Если a=7, b=5, то после выполнения операции a=12. Вместо знака + в составной операции присвоения используются также сим-волы других бинарных операций (*,/,%,+,-,<<, >>,&, |, ^).

Пример:

a<<=b; /*сдвинуть двоичный код числа a на b разрядов влево*/ a%=b; /*присвоить a значение остатка от деления a на b*/

Другие операции. Рассмотрим некоторые другие ( специальные) опера-ции, которые могут использоваться при составлении выражений (таблица 3.15).

Таблица 3.15. Специальные операции

Знак операции Наименование Пример Операции адресации и разадресации

& Адресация p= &b; p присваивается адрес операнда b * Разадресация а= *p; а присваивается значение, нахо-

дящееся по адресу p Операция последовательного вычисления

, Запятая а = (с-- , ++b); знак "," вычисляет два своих операнда слева направо; результат операции имеет значение и тип второго операнда; если с=2, b=3, в результате операции: а=4, с=1, b=4

Операция условного выражения ?: Тернарная

(условная) операция

а= (b<0) ? (-b) : (b); а присваивается аб-солютное значение b

size-операция sizeof Определение

размера в байтах а= sizeof (int); определяет размер памяти, которая соответствует идентификатору переменной или типу; а присваивается размер типа int

Тернарная операция имеет следующее синтаксическое представление:

y=x ? a :b;

Page 91: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

91

Выражение y вычисляется с точки зрения эквивалентности нулю операнда x, при этом y=a, если x не равно нулю, и y=b, если x равно нулю. Выражение может быть целого, вещественного или адресного типа.

Пример:

i=2; j=3; k= i>j?i:j; // k присваивается максимальное из i и j

Операция sizeof определяет размер памяти, который соответствует идентификатору переменной или типу. Выражение sizeof имеет форму:

sizeof(<name>);

где <name> – идентификатор переменной или имя типа. Имя типа не может быть void. Значением выражения sizeof является размер памяти в байтах, со-ответствующий поименованному идентификатору переменной или типу.

Когда операция sizeof применяется к идентификатору массива, то ре-зультатом является размер всего массива в байтах, а не размер указателя, со-ответствующего идентификатору массива.

Пример:

int i, j, k, n, m; float x; char c_ch; i=sizeof(i); j=sizeof(c_ch); k=sizeof(x); n=sizeof(double); m=sizeof(long double);

В результате выполнения операций будут получены следующие значения: - для идентификаторов переменных: i=2 (целый int), j=1 (символьный

char), k=4 (вещественный float); - для имен типа: n=8 (вещественный с двойной точностью double),

m=10 (длинный вещественный с двойной точностью long double).

3.8 Последовательность выполнения операций

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

Page 92: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

92

Таблица 3.16 Приоритеты выполнения операций

Знак операции Название операции Категория операции

Порядок выполнения

() Вызов функции Выражение Слева направо [] Выделение элемента массива . Выделение элемента записи

-> Выделение элемента записи ! Логическое отрицание Унарная Справа налево ~ Поразрядное отрицание - Изменение знака

++ Увеличение на единицу -- Уменьшение на единицу & Взятие адреса * Обращение по адресу

(тип) Преобразование типа sizeof Определение размера в байтах

* Умножение Мультиплика- Слева направо / Деление тивная

% Определение остатка от деле-ния

+ Сложение Аддитивная Слева направо - Вычитание

<< Сдвиг влево Сдвиг Слева направо >> Сдвиг вправо < Меньше, чем Отношение Слева направо

<= Меньше или равно > Больше, чем

>= Больше или равно = = Равно Отношение Слева направо != Не равно & Поразрядное логическое «И» Побитовое И Слева направо ^ Поразрядное «Исключающее

ИЛИ» Побитовое

исключающее ИЛИ Слева направо

| Поразрядное логическое «ИЛИ»

Побитовое включающее ИЛИ

Слева направо

&& Логическое «И» Логическое И Слева направо || Логическое «ИЛИ» Логическое ИЛИ Слева направо ?: Условная (тернарная) опера-

ция Условная Справа налево

= Присвоение Присвоения Справа налево znak= Составная операция присваи-

вания: znakÎ(*,/,%,+,-,<<, >>,&, |, ^)

, Операция запятая Последовательного вычисления

Слева направо

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

Page 93: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

93

слева направо или справа налево. Когда несколько операций одной категории появляются в выражении, то они отрабатываются в соответствии с этим пра-вилом ассоциативности.

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

Пример. Рассмотрим выражения:

i=3; j=4; a= i*j + (++j) + (--i);

Значение a зависит от того, в каком порядке вычисляются операнды опера-ции сложения: сначала i*j, а потом (++j) и (--i), (в этом случае a= 19) или сна-чала (++j) и (--i), а затем i*j (в этом случае a=17). По правилам приоритета операций верным является второй результат.

Для того, чтобы принудительно задать порядок вычислений в выра-жении используются круглые скобки. Например, изменённое следующим об-разом предыдущее выражение

a= i*j + ((++j) + (--i));

вызывает сначала вычисление ((++j) + (--i)), а затем уже сложение результата с i*j.

Пример демонстрации последовательности вычисления.

i=2; j=5; k=8; n=2; m=0; n= i*j >> 1 > k/n +n && ++j || ! m++;

Данное выражение группируется следующим образом:

((((i*j)>>1)>((k/n)+n) && (++j))||(!(m++))

Рассмотрим порядок вычисления для данного выражения. Находим операцию с самым низким приоритетом – это логическое ИЛИ (||). Эта опе-рация вычисляет свои операнды слева направо. Левым операндом является выражение

(i*j>>1>k/n+n&&++j).

В этом выражении находим операцию с наименьшим приоритетом – это ло-гическое «И» (&&). Эта операция также вычисляет операнды слева направо. Левым операндом является выражение

(i*j>>1>k/n+n).

Page 94: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

94

На основании последовательности подобных выкладок левый операнд можно сгруппировать следующим образом:

((i*j)>>1)>((k/n)+n).

Это выражение имеет результат 0, так как

((i*j)>>1) = ((2*5)>>1) = (10102>>1) = 01012 = 5,

а значение

((k/n)+n) = ((8/2)+2) = 6,

и условие 5>6 не выполняется. Из этого следует, что второй операнд опера-ции логического И (&&) – это (++j) – не вычисляется, и выражение

((i*j>>1>k/n+n)&&(++j)) = (0&&(++5)) = 0

Правый операнд операции логического ИЛИ (||) равен 0, а второй операнд группируется в

(!m++) = (!0++) = (1++) = 2

результатом является 1, так как m=0 и оно инкрементируется только после того, как берётся его логическое отрицание. В результате операции логиче-ского ИЛИ (||) получаем:

0||2 = 1,

что и является результатом всего выражения.

3.9 Указатели и операции с адресами

Указатель – особый вид переменной, которая хранит адрес элемента памяти, где может быть записано значение другой переменной. Так как ука-затель – это адрес некоторого объекта, то через него можно обращаться к этому объекту.

Формально указатель можно определить следующим образом:

тип данных *имя переменной;

где тип данных – определяет тип переменной указателя; имя переменной – имя, присвоенное переменной, определяющей указатель; символ * – указывает, что данная переменная является указателем.

Пример:

int var, *point;

здесь var – целочисленная переменная, point указатель на целый тип данных. Существует две унарные операции, неразрывно связанные с указате-

лями:

Page 95: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

95

- операция взятия адреса (адресация – &): - операция обращения по адресу (разадресация – *). Результатом операции взятия адреса (&) является адрес, по которому

значение переменной размещено в памяти. Так, оператору

y=&x;

присваивается адрес переменной x переменной y (рис. 3.7,а).

Рис. 3.7. Иллюстрация унарных операций & и *

Операция & может использоваться практически со всеми типами дан-ных, кроме констант и битовых полей.

Унитарная операция * воспринимает свой операнд как адрес некоторо-го объекта и использует этот адрес для выборки содержимого, поэтому опе-ратор

z=*y;

присваивает z значение переменной, записанной по адресу y (рис. 3.7,б). Ес-ли у=&x; z=*y, то z=x (рис. 3.8)

Page 96: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

96

Рис. 3.8. Иллюстрация операций с указателями

Объекты, состоящие из знака * и адреса (например, a*), необходимо объявлять.

Пример:

int var=2, *a,*b, *point; char *d; point = &var;

Объявление типа char *d; говорит о том, что значение, записанное по адресу d, имеет тип char.

Операции с указателями. Указатели могут встречаться и в выраже-ниях. Если y – указатель на целое значение, т.е. имеет место объявление int *y; то *у может появиться там же, где и любая другая переменная, не яв-ляющаяся указателем.

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

Пример:

int *y, *x, *z; *y=7; *x=*=5; (*z)++;

В данном примере первое из выражений заносит число 7 в ячейку по адресу y; второе увеличивает значение по адресу x в пять раз; третье добав-ляет единицу к содержимому ячейки памяти с адресом z. В последнем случае круглые скобки необходимы, так как операции * и ++ имеют одинаковый приоритет и выполняются справа налево. В результате, если, например, *z=5, то (*z)++ приведет к тому, что *z=6, а *z++ всего лишь изменит сам адрес z (операция ++ выполняется над адресом z, а не над значением *z по этому ад-ресу).

Page 97: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

97

С указателями можно производить следующие операции: Операцию присваивания, которая аналогична соответствующей опера-

ции для других типов данных. Если используются указатели на разные типы данных, то необходимо применять операцию приведения.

Операцию увеличения (уменьшения) указателя (point+i; point-i; где point – переменная типа указатель, i – значение целочисленного типа). Ре-зультат операции (point+i) – “указатель”, определяющий адрес i-го элемента после данного, а (point-i) – на i-ый элемент перед данным.

Операции сложного присваивания (point+=i, point-=i, где point – пере-менная типа указатель, i – значение целочисленного типа). Эти операции аналогичны выражениям point = point + i; point = point - i;

Операцию инкремента (декремента): point++; point--; ++point; --point. Указатель будет смещаться (увеличиваться или уменьшаться в зави-симости от операции) на один элемент. Фактически указатель (адрес) изме-ниться на количество байт, занимаемых этим элементом в памяти. Для опе-раций увеличения (уменьшения) указателя справедливо, если объявлен:

type1 *pointer; где type1 – некоторый тип, то операция pointer=pointer+i, где i – значение целочисленного типа, изменит pointer на sizeof(type1)*i байт.

Пример:

int a, *pi=&a; float f, *pf=&f; pi++; //смещение на 2 байта pf++; //смещение на 4 байта

Операцию индексирования: point [i]. Эта операция полностью анало-гична выражению *(point+i), т.е. извлекается из памяти и используется в вы-ражении значение i-го элемента массива, адрес которого присвоен указателю point.

Операцию вычитания: point1-point2 (операция имеет смысл только в том случае, если point1 и point2 указатели на один и тот же набор данных). Результат имеет тип int и равен количеству элементов, которые можно рас-положить между ячейками памяти, на которые указывают point1 и point2.

Операции отношения:

point1==point1; point1>=point2; point1>point2; point1<=point2; point1<point2; point1!=point1;

Результат всех операций имеет тип int. Результат операции "==" будет равен единице (true), если point1 и point2 указывают на один и тот же элемент в

Page 98: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

98

оперативной памяти. В противном случае результат будет равен нулю (false). Результат операции ">=" – единица (true), если объект *point1 расположен в памяти по более старшим адресам, чем объект *point2. Результатом опера-ции "<" будет единица (true), если объект *point1 расположен по более младшим адресам, чем объект *point2.

Любой указатель (адрес) может быть проверен на равенство (==) или неравенство (!=) со специальным значением NULL, которое записывается вместо нуля, т.е. производиться сравнение с нулем. Функции выделения па-мяти возвращают NULL при появлении каких-либо ошибок. Поэтому срав-нение с NULL часто используется для определения ошибок выделения памя-ти.

Пример:

int *p; p=new int[10]; //Выделяем память под массив из 10 элементов if (p==NULL) printf("\nОшибка выделения памяти! ");

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

Указатель типа void указывает на место в оперативной памяти (адрес не-которого байта), но не содержит информации о типе объекта. До использова-ния значения находящегося по этому адресу обязательно должна быть вы-полнена операция приведения указателя к некоторому типу. В противном случае компилятору будет неизвестна длина поля памяти, используемого в операции. К указателю типа void применяются следующие операции: = – присваивания; = =, !=, =>, >, <=, < – операции сравнения.

3.10 Управляющие структуры

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

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

Page 99: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

99

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

- структура выбора единичного решения из двух возможных, в зависи-мости от выполнения условий, и продолжение вычислений только по одной из двух возможных ветвей решения задачи (оператор if);

- структура выбора одного из двух возможных вариантов решения, в зависимости от выполнения условий, и возможность произвести вычисления одной из ветвей вычислений в рамках данного оператора (оператор if …else),

- структура выбора одного из определенного множества вариантов решений, в зависимости от полученных результатов и выполнения условий, и выполнение вычислений по одному из указанных вариантов продолжения вычислений (оператор switch);

- структура безусловного выбора единственного варианта продолже-ния вычислений (оператор goto);

- структура повторения вычислений с предусловием, которая позволяет организовать повторение заданного участка программы в соответствии с за-данным условием (оператор while);

- структура повторения вычислений с постусловием (оператор do … while);

- структура повторения вычислений, когда известно количество по-вторений (оператор for).

Составной и пустой операторы. Составной оператор – это несколь-ко операторов собранных в блок с помощью фигурных скобок {}, или разде-ленных запятой. Такой блок можно рассматривать как один оператор.

Пример: #include<stdio.h> void main() // Это составной оператор { int a =2; a++;

printf("Число а = %d\n", a); }

Пример: #include<stdio.h> void main() {

int a=-5, b; a+=13, b=15-a, b++; // Второй вариант составного оператора

Page 100: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

100

}

Пустой оператор – это знак "; ". Им можно заменить оператор там, где не нужно выполнять никакого действия.

Пример:

#include<stdio.h> void main() { int a=10; ; /*Это пустой оператор*/ if (a!=10)

; /*Это пустой оператор*/ else

puts(“a=10”); }

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

Выбор выполняется в зависимости от результатов анализа значения не-которого выражения. В языке Си для этих целей используются три оператора ветвления: if (если)…else (иначе), switch (переключить) и goto (перейти).

Оператор if…else имеет следующие две общие формы записи: if (проверка условия) оператор 1; if (проверка условия) оператор 1; [else оператор 2;]

Возможные конструкции с оператором if показаны на рис 3.9.

Рис. 3.9. Конструкции условных переходов с операторами if (а) и if…else (б)

Page 101: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

101

При выполнении оператора if сначала вычисляется условие. Если ре-зультат – истина (любое отличное от нуля значение), то выполняется опера-тор 1. Если результат анализа условия – ложь (равен 0), то выполняется опе-ратор 2 (рис. 3.9, б). Если слово else отсутствует, то оператор 1 пропускается, а управление передается на следующий после if оператор (рис. 3.9,а).

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

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

Пример. Найти минимум из двух чисел х и у.

#include<stdio.h> #include<conio.h> void main() {

float x, y, min; printf("Введите два числа\n"); scanf(“%f%f”, &x, &y); if (x<y) min=x; else min= y; printf("min = %e ", min); //вывод числа в экспоненциальной форме getch (); /*задерживает выполнение программы до нажатия клавиши*/

} Пример. Проверка правильности ввода переменной, которая может содер-

жать числа от 1 до 31.

#include<stdio.h> #include<conio.h> void main() { int den; printf("Введите день месяца\n"); scanf(“%d”, &den); if (den < 1 || den > 31 ) printf("Ошибка ввода\n"); else printf("den = %d ", den); getch (); /*задерживает выполнение программы до нажатия клавиши*/ }

Page 102: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

102

В операторе if…else непосредственно после ключевых слов должны следовать другие операторы. Если хотя бы один из них содержит в свою оче-редь оператор if, то его называют вложенным. Таким образом, при помощи операторов if…else можно составлять сложные конструкции else … if, кото-рые позволяют осуществлять проверку нескольких условий. Слово else все-гда относится к ближайшему предшествующему ему if. Формально данная конструкция может быть представлена в следующем виде:

if (проверка условия) operator1; else if (проверка условия) operator2;

else if (проверка условия) operator3; else operator4;

Рассмотрим простейшие программы, реализующие данную конструк-цию.

Пример. Отыскание максимального значения из трех целых чисел а, b и с.

#include<stdio.h> #include<conio.h> void main() {

int a, b, c, max; printf("Введите три числа\n"); scanf(“%d%d%d”, &a, &b, &c); if (a > b && a > c) max=a; else if (b > c) max=b; else max=c; printf("max = %d\n", max); getch (); /*задерживает выполнение программы до нажатия клавиши*/

} Пример. Ввести целое число и определить его значение больше, меньше или

равно нулю.

#include<stdio.h> #include<conio.h> void main() {

int n; printf("Введите n\n"); scanf(“%d”, &n); if (n>0) printf("n>0\n");

else if (n<0) printf("n<0\n"); else printf("n=0\n");

getch (); /*задерживает выполнение программы до нажатия клавиши*/ }

Свойства конструкций условных переходов оператора if…else заклю-чаются в следующем:

Page 103: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

103

1) условия проверяются в том порядке, в котором они перечислены в тексте программы;

2) если, в результате проверки, одно из условий – "истинно", то вы-полняется оператор соответствующий этому условию; проверка оставшихся условий не производиться;

3) если, в результате проверки, ни одно из проверенных условий не да-ло результата – "истинно", то выполняются операторы, относящиеся к по-следнему else;

4) последний else является необязательным, следовательно, он и отно-сящийся к нему операторы могут отсутствовать.

Оператор switch. Рассмотренный выше оператор ветвления if…else позволяет легко осуществить выбор между двумя вариантами продолжения вычислительного процесса. Однако, иногда возникает необходимость осуще-ствить выбор одного варианта из множества возможных вариантов продол-жения вычислений. Эту задачу можно реализовать, используя вложенные операторы if…else. Для облегчения процедуры многовариантного разветвле-ния в языке Си предусмотрен более удобный способ с использованием опе-ратора switch. Конструкция оператора switch имеет следующую форму пред-ставления:

switch (выражение) {

case константа1: оператор1; break; case константа2: оператор2; break; ………………………………………. case константа n: операторы; break; default: операторn+1; break;

}

Графическая иллюстрация конструкции оператора switch представлена на рис. 3.10.

Page 104: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

104

Рис. 3.10. Использование оператора switch

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

Пример. Требуется проанализировать значение переменной rez, которая яв-ляется оценкой знаний по пятибалльной шкале.

#include<stdio.h> #include<conio.h> void main()

Page 105: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

105

{ int rez; printf(" Введите оценку.\n"); scanf("%d", &rez); switch (rez) {

case 5: printf("Оценка — отлично.\n"); break; case 4: printf("Оценка — хорошо.\n"); break; case 3: printf("Оценка — удовлетворительно.\n"); break; case 2: printf("Оценка — неудовлетворительно.\n"); break; default: printf("Heвернoe значение.\n");

} getch (); /*задерживает выполнение программы до нажатия клавиши*/

}

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

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

2) символьные константы, используемые в операторе switch, автома-тически преобразуются в целочисленные;

3) метка default может отсутствовать или быть записана в любом мес-те оператора switch;

4) константы сравниваются с выражением в той последовательности, в какой они перечислены в тексте программы;

5) не может быть двух констант в одном операторе switch, имеющих одинаковое значение;

6) оператор break передает управление за пределы переключателя switch;

7) если после какого-либо из операторов в ветви case отсутствует клю-чевое слово break, то константа в следующем операторе case считается удов-летворяющей условию, и выполняются операторы данной ветви;

8) ключевые слова case и default не могут находиться за пределами блока switch;

9) оператор switch отличается от оператора if тем, что он может вы-полнять только операции строгого равенства, в то время как оператор if мо-жет вычислять логические выражения и отношения.

Пример. Проведем подсчет количества различных буквенных оценок, полу-ченных студентами на экзамене.

#include <stdio.h> void main ()

Page 106: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

106

{ int grade; int aCount = 0, bCount = 0, cCount = 0, dCount = 0, fCount = 0; printf("Enter the letter grades. \n"); printf("Enter the EOF character to end input. \n"); while ( ( grade = getchar() ) != EOF) {

switch (grade) { case 'A': case 'a':

++aCount; break; case 'В': case 'b':

++bCount; break; case 'C': case 'c':

++cCount; break; case 'D': case 'd':

++dCount; break; case 'F': case 'f':

++fCount; break; case '\n': case ' ': break; default:

printf("Incorrect letter grade entered."); printf (" Enter a new grade. \n"); break;

} } printf("\nTotals for each letter grade are:\n"); printf("A: %d\n", aCount); printf("B: %d\n", bCount); printf("C: %d\n", cCount); printf("D: %d\n", dCount); printf("F: %d\n", fCount);

}

Оператор goto. Предназначен для выполнения безусловного перехода. Конструкция оператора goto имеет следующую форму представления:

goto метка;

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

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

Page 107: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

107

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

Цикл представляет собой оператор или группу операторов, повторяю-щихся некоторое количество раз. Каждый проход по телу цикла называется итерацией.

Для организации циклов в Cи используются следующие три оператора: while, for и do … while.

Оператор while. Позволяет организовать цикл с предусловием (про-верка условия организации циклических вычислений осуществляется перед входом в цикл). Данный оператор используется в случаях:

- когда неизвестно точное число повторений цикла; - нет необходимости, чтобы цикл непременно был выполнен хотя бы

один раз. Оператор while формально записывается в следующем виде:

while (условие) оператор(ы);

где условие – выражение, предназначенное для проверки условия продолже-ния цикла; оператор(ы) – операторы программы, включенные в цикл.

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

Пример. Пользователю дается 10 попыток для угадывания заданного в про-грамме числа.

#include <stdio.h> void main () {

int i=1, rez=1; while ( i++<=10 && rez!=25) {

printf("\nВведите число: \n"); scanf(“%d”, &rez);

} if (i==11)

printf("\nBы не угадали."); else

printf("\nПоздравляю! Вы угадали число.\n");

Page 108: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

108

} Пример. Программа считывает с клавиатуры буквы, до тех пор, пока не бу-

дет введена буква ‘R’ и определяет порядковый номер данной буквы в последова-тельности символов

#include <stdio.h> void main () {

int i=0; char letter; while (1) {

printf("\nВведите букву: \n"); fflush(stdin); // очистка буфера scanf(“%c”, &letter); i++; if (letter==’R’) break;

} printf("Символ R %d-й\n", i);

}

В данном примере проверяемое условие всегда истинно, поэтому для выхода из цикла используется оператор break.

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

Пример. Программа считывает числа, суммирует их до тех пор, пока не бу-дет введено число нуль.

#include <stdio.h> void main () {

int res=0, n; printf(" Число?\n"); scanf(“%d”,&n); while (n!=0) { res+=n; printf(" Число?\n"); scanf(“%d”,&n); } printf("Сумма = %d\n", res);

}

Структура оператора while аналогична структуре оператора if. Основ-ное отличие заключается в том, что в операторе if проверка условия и воз-можное выполнение оператора осуществляется только один раз, а в цикле while эти действия повторяются неоднократно.

Page 109: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

109

Оператор do … while. Позволяет организовать цикл с постусловием (проверка условия организации циклических вычислений осуществляется по-сле выполнения цикла хотя бы один раз). Данный оператор используется в случаях:

- когда неизвестно точное число повторений цикла; - цикл необходимо выполнить по меньшей мере хотя бы один раз. Построение цикла с помощью оператора do … while очень похоже на

построение цикла с использованием оператора while. Отличительная особен-ность состоит только в том, что проверка условия истинности выражения (условие) в цикле do … while происходит после выполнения тела цикла (опе-ратор(ы) цикла).

Оператор do …while формально записывается в следующем виде:

do оператор(ы); while ( условное выражение )

где оператор(ы) – операторы программы, включенные в цикл; условное вы-ражение – выражение, предназначенное для проверки условия продолжения цикла.

Пример. Требуется составить программу, позволяющую пользователю уга-дывать заданное в программе число.

#include <stdio.h> void main () {

int r; printf("\nВведите число.\n"); do scanf(“%d”, &r); while ( r!=13); printf("\nПоздравляю! Вы угадали число.");

} В данном примере числа вводятся до тех пор, пока не будет введено чис-

ло 13, после этого выдается сообщение об успешном угадывании числа. Пример. Программа считывает числа, суммирует их до тех пор, пока не бу-

дет введено число нуль. #include <stdio.h> void main () {

int res=0, n; do { printf(" Число?\n"); scanf(“%d”,&n); res+=n; } while (n!=0); printf("Сумма = %d\n", res);

}

Page 110: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

110

Различие выполнения циклов приведенных в примерах вычисления сум-мы чисел до пояления нуля заключается в том, что в цикле, организованном оператором while, суммируются все числа до появления нуля, а в цикле, ор-ганизованном оператором do … while, суммируются все числа, включая и число 0.

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

Оператор for формально записывается в следующем виде:

for (инициализация; условное выражение; изменение параметров) оператор(ы);

где инициализация – выражение, предназначенное для присвоения начально-го значения управляющей переменной; условное выражение – выражение, предназначенное для проверки выполне-ния условия продолжения цикла; изменение параметров – выражение, предназначенное для изменения пара-метров управляющей переменной.

Структура цикла с параметрами показана на рис. 3.11.

Рис. 3.11. Структура оператора for

Процесс выполнения цикла for состоит из следующих шагов:

Page 111: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

111

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

2. Проверяется значение условного выражения (условие), если резуль-татом является значение Ложь, то выполнение цикла завершается.

3. Если результатом проверки значение условного выражения является "истина", то выполняется тело цикла.

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

5. Осуществляется переход к пункту 2. Пример. Требуется вычислить значение y10. Возможный вариант решения

имеет вид:

#include <stdio.h> void main () { int i;

float rez, y; printf("Введите значение y\n"); scanf("%f", &y); for ( i=1, rez=1; i<=10; i++ )

rez=rez*y; printf("%f в степени 10 =%f\n", y, rez);

}

Такие поля, как инициализация, так и коррекция переменных цикла мо-гут содержать любую последовательность простых операторов, разделенных запятыми. Любое поле в операторе if может отсутствовать, но знак точка с запятой (;) ставиться независимо от присутствия определенного поля. Если отсутствуют поля инициализация и коррекция переменных цикла, то управ-ляющая переменная просто не используется. Если отсутствует поле условие, то считается, что оно истинно, и цикл не заканчивается (бесконечный цикл). При отсутствии всех полей, также получиться бесконечный цикл. Выход из бесконечного цикла может быть организован другими способами.

Пример. Пример бесконечного цикла:

for (;;) printf("Это бесконечно повторяющаяся строка");

Рассмотрим примеры использования оператора for для решения неко-торых часто встречающихся задач:

1) Можно применять операцию уменьшения для счета в порядке убы-вания.

Page 112: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

112

Пример. Счет в порядке убывания. Требуется вычислить у5. Возможное ре-шение имеет вид:

for ( i=5, r=1; i>=1; i-- ) r=r*y;

2) При желании можно организовать счет двойками, тройками, десят-ками и т.д.

Пример. Приращение при счете, отличное от 1.

for ( n=5; n<61; n+=15) printf("%d\n", n);

3) Можно в качестве счетчика использовать не только цифры, но и символы.

Пример. Использование символов в качестве счетчика. Требуется напечатать алфавит. Возможное решение имеет вид:

for ( chr='A'; chr<='Z'; chr++) printf("Код символа = %d, символ = %c\n", chr, chr);

4) Можно проверять любое другое условие, отличное от числа итера-ций.

5) Можно задать возрастание значений счетчика не в арифметической, а в геометрической прогрессии.

Пример. Изменение счетчика в геометрической прогрессии. Требуется под-считать долг. Возможное решение имеет вид:

for ( k=100; k<185; k*=1.1) printf("Долг равен = %d\n", k);

6) В качестве третьего выражения в операторе for можно использовать любое правильно составленное выражение. Оно будет вычисляться в конце каждой итерации.

Пример. Использование в качестве счетчика выражения.

for (k=1; z<=196; z=5*k+23 ) printf("%d\n", z);

7) Можно пропускать одно или несколько выражений. При этом нельзя пропускать символы «точка с запятой».

Пример. Неполный список выражений в заголовке тела цикла.

for (p=2; p<=202;) p=p+n/k;

8) Первое выражение не обязательно должно инициализировать пере-менные, оно может быть любого типа.

Пример. Произвольное первое выражение в заголовке цикла.

for ( printf("Вводите числа."); р<=30;) scanf("%d", &p);

Page 113: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

113

9) Переменные, входящие в выражения спецификации цикла, можно изменять в теле цикла.

Пример. Изменение управляющих переменных в теле цикла.

delta=0.1; for (k=1; k<500; k+=delta) if (a>b) delta=0.5;

10) Использование операции «запятая» в спецификации цикла позволя-ет включать несколько инициализирующих и корректирующих выражений.

Пример. Использование операции «запятая» в спецификации цикла.

for ( i=1, r=1; i<=10; i++, r*=y ) printf("y в степени %d равен %d", i, r);

Вложенные циклы. В языке Си допускается вложенность одних цик-лов в другие, т.е. в теле любого цикла могут появиться операторы for, while, do…while.

Вложенным циклом называют конструкцию, в которой один цикл вы-полняется внутри другого. Внутренний цикл выполняется полностью во вре-мя каждой итерации внешнего цикла.

Пример. Вложенные циклы. Требуется заполнить весь экран символами '#'. Возможный вариант решения имеет вид:

#include <stdio.h> void main () { int i, k; for ( i=1; i<=25; i++ )

for (k=1; k<=80; k++ ) printf(“#”);

}

В данной программе 25 раз осуществляется вывод символа '#' по 80 сим-волов в строке.

Пример. Осуществить ввод десяти значений дней месяца с проверкой пра-вильности ввода.

#include <stdio.h> void main () {

int i, den; for ( i=1; i<=10; i++ ) { printf(“Введите день месяца \n”); do scanf(“%d”, &den); while (den<1||den>31); printf(“День месяца %d\n”, den); }

}

Page 114: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

114

В данном примере внешний цикл выполняется 10 раз, а внутренний бу-дет выполняться до тех пор, пока не будет введено правильное значение.

Управляющие операторы в циклах. Операторы ветвления и операто-ры циклов являются важнейшими средствами управления порядком выпол-нения программы на языке Си. Существует еще два оператора, предназна-ченных для этих целей: break и continue. Они применяются реже, поскольку частое их использование ухудшает наглядность программы и увеличивает вероятность ошибок.

Оператор break может использоваться в циклах всех трех типов. Вы-полнение оператора break приводит к немедленному выходу из цикла, в ко-тором он содержится, и переходу к следующему за циклом оператору. Если оператор break находиться внутри вложенного цикла, то его действие рас-пространяется только на тот цикл, непосредственно в котором он находиться.

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

Использование операторов break и continue показано на рис. 3.12.

Рис. 3.12. Использование операторов break и continue

Пример. Использование оператора break. Требуется определить задуманное число (в данном примере 15) с 10 попыток.

#include <stdio.h> void main () {

int i=0, rez; while ( i++<10) {

printf("\nПопытка %d. Введите число: \n", i); scanf(“%d”, &rez); if (rez==15) break;

Page 115: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

115

printf("\nBы не угадали."); } if (i!=11)

printf("\nПоздравляю! Вы угадали число.\n"); }

Пример. Использование оператора continue. Вводятся числа месяца для об-работки. Необходимо осуществить проверку правильности ввода. Число 31 обо-значает конец обработки.

#include <stdio.h> void main () {

int i, den; while (den!=31) {

printf(“Введите день месяца \n”); scanf(“%d”, &den); if (den<1|| den>31) continue; printf(“День месяца %d \n”, den); // обработка числа den

} }

Тема 4 СЛОЖНЫЕ ТИПЫ ДАННЫХ 4.1 Массивы

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

Для создания массива используется оператор объявления. Объявление массива должно содержать три аргумента:

­ тип каждого элемента; ­ название массива; ­ число элементов в массиве. Общая форма для объявления массива имеет вид (т.е. массив объявля-

ется так же, как и обычные переменные, но после имени следуют квадратные скобки, в которых указывается размер массива):

тип имя_массива[размер];

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

Page 116: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

116

Примеры объявления массива:

int mas1[492]; //внешний массив из 492 элементов void main(void) {

double mas2[250]; //массив из 250 чисел типа double static char mas3[20]; // статическая строка из 20 символов extern mas1[ ]; // внешний массив, размер указан выше int mas4[2][4]; // двумерный массив из чисел типа int int n=15; int bad[n]; // ошибочное объявление, //т.к. переменная не может задавать размер массива int array[0]; // ошибочное объявление, //т.к. размер не может быть нулевым

}

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

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

Примеры инициализации массивов при объявлении:

int array[5]={4,6,7,8,9}; // объявлен массив из 5-ти элементов //и все они инициализированы int buffer[15]={1,1,1,1}; // объявлен массив из 15-ти элементов, // четыре первых инициализированы заданными значениями, // одиннадцать будут равны 0 int a[]={35,56,78,90}; // объявлен массив из четырех элементов int b[3]={1,1,10,10}; // ошибка //кол-во инициализаторов больше размерности массива

Описанную выше форму инициализации массива можно использовать только при объявлении массива. Ее нельзя использовать позже в программе и так же нельзя присвоить один массив целиком другому.

Page 117: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

117

Если же массив явно не проинициализирован, то внешние и статиче-ские массивы инициализируются нулями. Автоматические же массивы после объявления не инициализируются и содержат неизвестную информацию.

Элементы массива занимают один непрерывный участок памяти ком-пьютера и располагаются последовательно друг за другом. Нумерация эле-ментов массива начинается с 0 и заканчивается n-1, где n – число элементов массива. Пример массив целых чисел из восьми элементов, объявление кото-рого int d[8]; ,представлен на рисунке 3.13.

d[0] d[1] d[2] d[3] d[4] d[5] d[6] d[7] -45 6 0 72 1543 -89 0 62

Рис. 3.13. Пример массива с из 8 элементов

Чтобы получить доступ к отдельному элементу массива необходимо указать его порядковый номер в массиве, заключенный в квадратные скобки, который называется индексом. Самый первый элемент массива имеет поряд-ковый номер 0. Индекс элемента может быть целым числом или целочислен-ным выражением. В остальном можно работать с элементом массива как с обычной переменной.

Примеры обращения к элементам массива:

array[3]=125; // присвоение значение 125 четвертому элементу массива tmp=array[3]; // присвоение значение элемента массива переменной tmp array[0]=array[2]; // присвоение значение эл-та массива другому эл-ту массиву index=2; array[index]=5; // использование целочисленной переменной index для // обращения к третьему элементу массива // в качестве индекса может использоваться целочисленный эл-т массива array[3]=4; buffer[array[3]]=7; // присвоение значение пятому элементу массива

В языке Си отсутствует проверка на выход за пределы массива, пре-дотвращающая ссылку на несуществующий элемент.

Пример:

int array[4]; tmp=array[8]; //значение переменной tmp не определено

Пример: Программа инициализирует нулями элементы целочисленного массива n из десяти элементов и выводит его в табличной форме.

Page 118: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

118

#include <stdio.h> void main () { int n [10], i; for (i = 0; i <= 9; i++) n[i] = 0; printf("%s%13s\n", "Element", "Value"); for (i = 0; i <= 9; i++) printf("%7d%13d\n", i, n[i]); }

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

#include <stdio.h> #include <conio.h> void main () { int array[10], i; printf("Vvedite 10 chisel\n"); for (i = 0; i<10; i++) { printf("chislo %d: ", i+1); scanf("%d", &array[i]); } for (i = 9; i>=0; i--) printf("%d ", array[i]); printf("\n"); getch(); }

Пример. Программа инициализирует элементы десятиэлементного массива s значениями 2, 4, 6, …, 20 и выводит массив в табличной форме. Эти значения генерируются путем умножения счетчика цикла на 2 и прибавления 2.

#include <stdio.h> #include <conio.h> #define SIZE 10 void main () { int s [SIZE], i; for (i = 0; i <= SIZE-1; i++) s[i] = 2+2*i; printf("%s%13s\n", "Element", "Value"); for (i = 0; i <= SIZE-1; i++) printf("%7d%13d\n", i, s[i]); getch(); }

Пример. Программа суммирует значения, содержащиеся в целочисленном массиве s из двенадцати элементов.

#include <stdio.h> #include <conio.h> #define SIZE 10

Page 119: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

119

void main () { int s [SIZE]={1,2,3,4,5,6,7,8,9,0}; int i, total=0; for (i = 0; i <= SIZE-1; i++) total+=s[i]; printf("Total of array element values is %d\n", total); getch(); }

4.2 Многомерные массивы

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

Многомерные массивы объявляются точно так же, как и одномерные, только после имени массива ставится более одной пары квадратных скобок.

Пример объявления многомерных массивов:

double array[30][10]; // матрица с 30 строками и 10 столбцами int buffer[1][7]; // матрица с 1 строкой и 7 столбцами int bad1[0][5]; // ошибка: размерность не может быть нулевой int bad2[0][3][0]; // ошибка: размерность не может быть нулевой

Пример двухмерного массива приведен на рис. 3.14:

Столбец 0

Столбец 1

Столбец 2

Столбец 3

Строка 0 a[0][0] a[0][1] a[0][2] a[0][3] Строка 1 a[1][0] a[1][1] a[1][2] a[1][3] Строка 2 a[2][0] a[2][1] a[2][2] a[2][3]

Рис. 3.14. Двумерный массив с тремя строками и четырьмя столбцами

Многомерные массивы можно инициализировать как и одномерные. Причем инициализация происходит построчно, т.е. в порядке возрастания самого правого индекса. Именно в таком порядке элементы многомерных массивов располагаются в памяти компьютера.

Примеры инициализации многомерных массивов:

int array[2][2][2]={20,21,22,23,24,25,26,27}

/* Массив array будет проинициализирован следующими значения array[0][0][0]=20; array[0][0][1]=21; array[0][1][0]=22; array[0][1][1]=23; array[1][0][0]=24; array[1][0][1]=25; array[1][1][0]=26; array[1][1][0]=27; */

Page 120: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

120

int mas[3][3] = { 34, 23, 67, 38, 56, 73, 37, 94, 28 }; // так записывают инициализацию для наглядности

При инициализации многомерного массива можно не указывать одну (самую левую) из размерностей массива. Размерность будет определена по количеству членов в списке инициализации.

Пример инициализации многомерного массива:

int buffer[][3]= { 34, 23, 67, 38, 56, 73, 37, 94, 28 };

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

Пример инициализации многомерного массива:

int buffer[][3]= { {0}, {11, 10} {15, 17, 18} };

При обращении к элементам многомерного массива необходимо ука-зать все его индексы.

Пример:

array[0][2][1]=5+10; mas[0][0]= array[0][2][1]; if (buffer[1][3]!=0) scanf(«%d», & buffer[1][3]);

Особых отличий работы с многомерными массивами от одномерных нет.

Пример. Транспонировать квадратную матрицу на том же месте. Примечание. Понятие транспонирования матрицы: Если A=[aik] – произволь-

ная матрица, размера m*n, то транспонированная матрица по отношению к A есть матрица A1=[aki], размера n*m.

Текст программы выглядит следующим образом:

#include <stdio.h> #include <conio.h> void main () { int A[20][20]; // Объявление массива A int i, j, temp, size; // Объявление переменных

// Цикл do … while для ввода размерности матрицы do { printf("\nВведите размерность матрицы: "); scanf("%d", &size);

Page 121: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

121

} while(size>20); //Вложенные циклы for для ввода элементов матрицы for (i = 0; i < size; i++) for (j = 0; j < size; j++) { printf("A[%d][%d] = ",i+1,j+1); scanf("%d", &A[i][j]); } // Печать исходной матрицы printf("Исходная матрица: \n"); for (i = 0; i < size; i++) { for (j = 0; j < size; j++) printf("%d ",A[i][j]); printf("\n"); } // Циклы for и do … while для транспонирования матрицы for (i = 1; i < size; i++) { j=0; do { temp=A[i][j]; A[i][j]=A[j][i]; A[j++][i]=temp; }while(j<i); } // Печать транспонированной матрицы printf("Транспонированная матрица: \n"); for (i = 0; i < size; i++) { for (j = 0; j < size; j++) printf("%d ",A[i][j]); printf("\n"); } // Задержка выполнения программы до нажатия клавиши getch(); return 0; }

Пример. Перемножить матрицы вещественных чисел, используя оператор while.

Примечание. Произведение матрицы A=[aik] размера m*n на матрицу B=[bjk] размера n*r есть матрица C=[cik] размера m*r: C=A*B=[aij]*[bik]=[cik],

где 1

n

ij ij jkj

c a b=

= å. Таким образом, элемент cik матрицы C=A*B есть сумма произве-

дений элементов i-той строки матрицы A на соответствующие элементы k-го столбца матрицы B.

Текст программы выглядит следующим образом:

#include <stdio.h> #include <conio.h> void main () { double A[3][4], B[4][5], C[3][5]; // Объявление массивов A, B, C int i, j, k; // Объявление переменных цикла // Цикл для ввода элементов матрицы A

Page 122: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

122

for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { printf("A[%d][%d] = ",i+1,j+1); scanf("%lf", &A[i][j]); } // Цикл для ввода элементов матрицы B for (i = 0; i < 4; i++) for (j = 0; j < 5; j++){ printf("B[%d][%d] = ",i+1,j+1); scanf("%lf", &B[i][j]); } /* Вложенные циклы while по переменным i, j, k для вычисления произве-

дения матриц */ i=0; while (i<3) { j=0; while (j<5) { C[i][j]=0; // Очистка элемента [i,j] матрицы C k=0; while (k<4) { C[i][j]+=A[i][k]*B[k][j]; // Вычисление произведения k++; } j++; } i++; } // Печать исходной матрицы A printf("Матрица A: \n"); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) printf("%.2f ",A[i][j]); printf("\n"); } // Печать исходной матрицы B printf("Matrica B: \n"); for (i = 0; i < 4; i++) { for (j = 0; j < 5; j++) printf("%.2f ",B[i][j]); printf("\n"); } // Печать результирующей матрицы C printf("Матрица C: \n"); for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) printf("%.2f ",C[i][j]); printf("\n"); } getch(); }

Page 123: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

123

4.3 Строковые литералы (строки)

Строковым литералом (или просто строкой) называется последова-тельность символов, заключенная в двойные кавычки. В Си отсутствует спе-циальный строковый тип. Строки представляются в Си как массив элементов типа char, в конце которого помещается символ '\0' (нуль-терминатор). Нуле-вой символ (\0') служит для обозначения конца строки.

Пример объявления:

char str1[7] = { 'H', 'E', 'L', 'L', 'O', '!', '\0'}; char str2[9] = "HELLO!"; char str3[] = "HELLO!"; // Строки str1, str2 и str3 тождественно равны char str4="HELLO"; //Ошибка char str5="H"; //Ошибка char str6='H';

Пример объявления:

char str[10]= "HELLO!";

Объявление массива символов str показанн на рисунке 3.15. Седьмой символ (str[6]) – автоматически добавленный конец строки. Оставшимся эле-ментам так же присваивается значение \0.

str[0] str[1] str[2] str[3] str[4] str[5] str[6] str[7] str[8] str[9] H E L L O ! \0 \0 \0 \0

Рис. 3.15. Присвоение строки массиву

Пример. Программа запрашивает сроку и выводит на экран саму строку и ее длину:

#include<stdio.h> void main() { char string[20]; char q; printf("Vvedite stroku: "); scanf("%s",string); printf("Stroka: %s\n",string); for(q=0;string[q];q++); printf("Dlina = %d \n",q); } Пример. Программа запрашивает сроку и выводит на экран саму строку, ее

длину и количество пробелов в строке:

Page 124: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

124

#include<stdio.h> void main() { char string[80]; char q,w=0; puts("Vvedite stroku: "); gets(string); printf("Stroka: %s \n",string); for(q=0;string[q];q++) if(string[q]==32) w++; printf("Dlina = %d \n",q); printf("Kolichestvo = %d\n",w); }

Библиотечные функции работы со строками и символами. Функции обработки символов из библиотеки ctype.h (табл.получают в качестве аргу-мента символ — представляемый типом int — или индикатор EOF (конец файла). EOF обычно имеет значение -1.

Таблица 3.17 Функции обработки символов

Прототип функции

Описание функции

int isdigit (int c) Возвращает значение true, если с является цифрой, и false (0) в других случаях.

int isalpha (int c) Возвращает значение true, если с является буквой, и 0 в других случаях.

int isalnum (int c) Возвращает значение true, если с является цифрой или бу-квой, и false (0) в других случаях.

int isxdigit (int c) Возвращает значение true, если с является одним из сим-волов шестнадцатеричного формата, и false (0) в других случаях.

int islower (int c) Возвращает значения true, если с является буквой нижнего регистра, и false (0) в других случаях.

int isupper (int c) Возвращает значение true, если с является буквой верхнего регистра, и false (0) в других случаях.

int tolower (int c) Если с является буковой верхнего регистра, то tolower воз-вращает с как букву верхнего регистра. В других случаях tolower возвращает аргумент без изменений.

int toupper (int c) Если с является буквой нижнего регистра, то toupper воз-вращает с как букву верхнего регистра. В других случаях toupper возвращает аргумент без изменений.

int isspace (int c) Возвращает значение true, если с является пробельным

Page 125: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

125

Прототип функции

Описание функции

символом – пробел (' '), новая страница ('\f'), новая ('\n'), возврат каретки ('\r'), горизонтальная табуляция ('\t') или вертикальная табуляция ('\v'), - и false (0) в других случаях.

int iscntrl (int c) Возвращает значение true, если с является управляющим символом, и false (0) в других случаях.

int ispunct (int c) Возвращает значение true, если с является отображаемым при печати символом, но не относится к пробельным сим-волам, цифрам или буквам. В других случаях функция воз-вращает значение false (0).

int isprint (int c) Возвращает значение true, если с является отображаемым при печати символом, включая символ пробела (' '), и false (0) в других случаях.

int isgraph (int c) Возвращает значение true, если с является отображаемым при печати символом, исключая символ пробела (' '), и false (0) в других случаях.

Пример. Программа демонстрирует применение функций isdigit, isalpha, isalnum и isxdigit.

#include<stdio.h> #include<ctype.h> void main() { printf("\nAccording to isdigit: \n"); printf("%s%s\n", isdigit('8') ? "8 is a " : "8 is not a ", "digit"); printf("%s%s\n", isdigit('#') ? "# is a " : "# is not a ", "digit"); printf("\nAccording to isalpha: \n"); printf("%s%s\n", isalpha('A') ? "A is a" : "A is not a ", "letter"); printf("%s%s\n", isalpha('b') ? "b is a" : "b is not a ", "letter"); printf("%s%s\n", isalpha('$') ? "$ is a" : "$ is not a ", "letter"); printf("%s%s\n", isalpha('4') ? "4 is a" : "4 is not a ", "letter"); printf("\nAccording to isalnum: \n"); printf("%s%s\n", isalnum('A') ? "A is a " : "A is not a ", "digit or a letter"); printf("%s%s\n", isalnum('8') ? "8 is a " : "8 is not a ", "digit or a letter"); printf("%s%s\n", isalnum('#') ? "# is a " : "# is not a ", "digit or a letter"); printf("\nAccording to isxdigit: \n"); printf("%s%s\n", isxdigit('F') ? "F is a " : "F is not a ", "hexadecimal digit"); printf("%s%s\n", isxdigit('J') ? "J is a " : "J is not a ", "hexadecimal digit"); printf("%s%s\n", isxdigit('7') ? "7 is a " : "7 is not a ", "hexadecimal digit"); printf("%s%s\n", isxdigit('$') ? "$ is a " : "$ is not a ", "hexadecimal digit");

Page 126: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

126

printf("%s%s\n", isxdigit('f') ? "f is a " : "f is not a ", "hexadecimal digit"); }

Функция isdigit определяет, является ли ее аргумент цифрой (0-9). Функция isalpha определяет, попадает ли ее аргумент в список букв верхнего (A-Z) или нижнего (a-z) регистров. Функция isalnum определяет принадлеж-ность аргумента буквам верхнего и нижнего регистров или цифрам. Функция isxdigit определяет, является ли аргумент шестнадцатеричной цифрой (A-F, a-f, 0-9).

Программа использует с каждой функцией условную операцию (?:), чтобы определить, какую из строк « is а » (это) или « is not a » (это не) сле-дует вывести на печать для каждого проверяемого символа. Например, вы-ражение

isdigit ('8') ? "8 is a" : "8 is not a"

означает, что если '8' является цифрой, т.е. функция isdigit возвращает ис-тинное значение, то печатается строка « 8 is a », и, если '8' не является циф-рой, т.е. isdigit возвращает 0, печатается строка « 8 is not a ».

Результат работы программы имеет следующий вид:

According to isdigit: 8 is a digit # is not a digit According to isalpha: A is a letter b is a letter $ is not a letter 4 is not a letter According to isalnum: A is a digit or a letter 8 is a digit or a letter # is not a digit or a letter According to isxdigit: F is a hexadecimal digit J is not a hexadecimal digit 7 is a hexadecimal digit $ is not a hexadecimal digit f is a hexadecimal digit

Пример. Программа демонстрирует применение функций islower, isupper, tolower и toupper.

#include<stdio.h> #include<ctype.h> void main() { printf("\nAccording to islower: \n"); printf("%s%s\n", islower('p') ? "p is a " : "p is not a ", "lowercase letter");

Page 127: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

127

printf("%s%s\n", islower('P') ? "P is a " : "P is not a ", "lowercase letter"); printf("%s%s\n", islower('5') ? "5 is a " : "5 is not a ", "lowercase letter"); printf("%s%s\n", islower('!') ? "! is a " : "! is not a ", "lowercase letter"); printf("\nAccording to isupper: \n"); printf("%s%s\n", isalpha('D') ? "D is an " : "D is not an ", "uppercase letter"); printf("%s%s\n", isalpha('d') ? "d is an " : "d is not an ", "uppercase letter"); printf("%s%s\n", isalpha('8') ? "8 is an " : "8 is not an ", "uppercase letter"); printf("%s%s\n", isalpha('$') ? "$ is an " : "$ is not an ", "uppercase letter"); printf("%s%c\n", "u converted to uppercase is ", toupper('u')); printf("%s%c\n", "7 converted to uppercase is ", toupper('7')); printf("%s%c\n", "$ converted to uppercase is ", toupper('$')); printf("%s%c\n", "L converted to lowercase is ", tolower('L')); }

Функция islower определяет, является ли ее аргумент буквой нижнего ре-гистра (a—z). Функция isupper определяет, является ли ее аргумент буквой верхнего регистра (A—Z). Функция tolower преобразует регистр буквы из верхнего регистра в ниж-

ний и возвращает букву нижнего регистра. Если аргумент не является буквой верхнего регистра, то функция tolower возвращает аргумент без изменений. Функция toupper преобразует регистр буквы из нижнего регистра в верх-

ний и возвращает букву верхнего регистра. Если аргумент не является буквой нижнего регистра, то функция toupper возвращает аргумент без изменений.

Результат работы программы имеет следующий вид:

According to islower: p is a lowercase letter P is not a lowercase letter 5 is not a lowercase letter ! is not a lowercase letter According to isupper: D is an uppercase letter d is not an uppercase letter 8 is not an uppercase letter $ is not an uppercase letter u converted to uppercase is U 7 converted to uppercase is 7 $ converted to uppercase is $ L converted to lowercase is l

Функции преобразования строк из библиотеки утилит общего назначе-ния (stdlib.h) преобразуют строки цифр в целые значения и значения с пла-вающей точкой. В таблице 3.18 приведен перечень функций преобразования строк. Обратите внимание на модификатор const в описании переменной nPtr в заголовке функции (читается справа налево: «nPtr является указате-

Page 128: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

128

лем на символьную константу»); const объявляет, что значение аргумента не будет изменяться.

Таблица 3.18 Функции преобразования строк

Прототип функции Описание функции double atof (const char *nPtr) Преобразует строку nPtr в тип double. int atoi (const char *nPtr) Преобразует строку nPrt в тип int. long atol (const char *nPtr) Преобразует строку nPrt в тип long int double strtod (const char *nPtr, char **endPtr)

Преобразует строку nPrt в тип double. Указателю **endPtr присваивается ад-рес символа, который является первым символом строки-остатка после преоб-разования части строки.

long strtol (const char *nPtr, char **endPtr, int base)

Преобразует строку nPrt в тип long. Указателю **endPtr присваивается ад-рес символа, который является первым символом строки-остатка после преоб-разования части строки. Целое число base определяет основание, по которо-му производится преобразование.

unsigned long strtoul (const char *nPtr, char **endPtr, int base)

Преобразует строку nPrt в тип un-signed long.

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

#include<stdio.h> #include<stdlib.h> #include <conio.h> void main() { double d; d=atof("99.0"); printf("\nThe string \"99.0\" converted to double is %.3f\n", d); printf("The converted value divided by 2 is %.3f\n", d/2.0); d=atof("99.0string"); printf("\nThe string \"99.0string\" converted to double is %.3f\n", d); printf("The converted value divided by 2 is %.3f\n", d/2.0);

Page 129: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

129

d=atof("string99.0string"); printf("\nThe string \"string99.0string\" converted to double is %.3f\n", d); printf("The converted value divided by 2 is %.3f\n", d/2.0); getch(); }

Результат работы программы имеет следующий вид:

The string "99.0" converted to double is 99.000 The converted value divided by 2 is 49.500 The string "99.0string" converted to double is 99.000 The converted value divided by 2 is 49.500 The string "string99.0string" converted to double is 0.000 The converted value divided by 2 is 0.000

Пример. Программа демонстрирует применение функции atoi, которая пре-образует аргумент — строку цифр, которая представляет целое число, — в зна-чение типа int и возвращает значение типа int. Если аргумент функции не может быть преобразован, то поведение функции atoi не определено.

#include<stdio.h> #include<stdlib.h> #include <conio.h> void main() { int i; i=atoi("2593"); printf("\nThe string \"2593\" converted to int is %d\n", i); printf("The converted value minus 593 is %d\n", i-593); i=atoi("2593string"); printf("\nThe string \"2593string \" converted to int is %d\n", i); printf("The converted value minus 593 is %d\n", i-593); i=atoi("string2593string"); printf("\nThe string \"string2593string\" converted to int is %d\n", i); printf("The converted value minus 593 is %d\n", i-593); getch(); }

Результат работы программы имеет следующий вид:

The string "2593" converted to int is 2593 The converted value minus 593 is 2000 The string "2593string" converted to int is 2593 The converted value minus 593 is 2000 The string "string2593string" converted to int is 0 The converted value minus 593 is -593

Пример. Программа демонстрирует применение функции atol, которая пре-образует аргумент — строку цифр, которая представляет число типа длинное це-

Page 130: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

130

лое, — в значение типа long и возвращает значение типа long. Если аргумент функции не может быть преобразован, то поведение функции atol не определено. Если для хранения типа int и типа long используются 4 байта, то функции atoi и atol работают идентично.

#include<stdio.h> #include<stdlib.h> #include <conio.h> void main() { long l; l=atol("1000000"); l=atol("1000000"); printf("\nThe string \"1000000\" converted to long int is %ld\n", l); printf("The converted value divided by 2 is %d\n", l/2); l=atol("1000000string"); printf("\nThe string \"1000000string\" converted to long int is %ld\n", l); printf("The converted value divided by 2 is %d\n", l/2); l=atol("string1000000string"); printf("\nThe string \"string1000000string\" converted to long int is %ld\n", l); printf("The converted value divided by 2 is %d\n", l/2); getch(); }

Результат работы программы имеет следующий вид:

The string "1000000" converted to long int is 1000000 The converted value divided by 2 is 500000 The string "1000000string" converted to long int is 1000000 The converted value divided by 2 is 500000 The string "string1000000string" converted to long int is 0 The converted value divided by 2 is 0

Пример, Программа демонстрирует применение функции strtol, которая преобразует последовательность символов, представляющих целое число, в зна-чение типа long. Эта функция имеет три аргумента: строку (char *), указатель строки и целое число. Строка содержит последовательность символов, которые должны быть преобразованы. Указателю присваивается адрес символа, который является первым символом строки-остатка после преобразования части строки. Целое число определяет основание, по которому производится преобразование.

#include <stdio.h> #include <stdlib.h> #include <conio.h> void main() { long x; char *string = "-1234567abc";

Page 131: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

131

char *remainderPtr; x=strtol(string, &remainderPtr, 0); printf("The original string is %s\n", string); printf("The converted value is %ld\n", x); printf("The remainder of the original string is %s\n", remainderPtr); printf("Theconverted value plus 567 is %ld\n", x + 567); x=strtol(string, &remainderPtr, 16); printf("\nThe original string is %s\n", string); printf("The converted value is %ld\n", x); printf("The remainder of the original string is %s\n", remainderPtr); printf("Theconverted value plus 567 is %ld\n", x + 567); getch(); }

Оператор

х = strtol (string, &remainderPtr, 0);

из программы означает, что х присваивается значение типа long, полученное после преобразования строки string. Второй аргумент — SremainderPtr — после преобразования будет указывать на остаток строки. Если для второго аргумента использовать значение NULL, то строка-остаток будет проигно-рирована. Третий аргумент — 0 — показывает, что преобразуемое значение может иметь восьмеричный (основание 8), десятичный (основание 10) или шестнадцатеричный формат (основание 16). Основание может иметь значе-ние 0 или может быть любым значением в диапазоне от 2 до 36. Для числен-ного представления целых значений от 11 до 35 в диапазоне оснований от 11 до 36 используются символы A-Z. Например, шестнадцатеричное число мо-жет содержать цифры 0-9 и символы A-F. Целые по основанию 11 могут со-держать цифры 0-9 и символ А. Целые по основанию 24 могут содержать цифры 0-9 и символы A-N. Целые по основанию 36 могут содержать цифры 0-9 и символы A-Z.

Результат работы программы имеет следующий вид:

The original string is "-1234567abc" The converted value is -1234567 The remainder of the original string is "abc" The converted value plus 567 is -1234000 The original string is "-1234567abc" The converted value is -2147483648 The remainder of the original string is "abc" The converted value plus 567 is -2147483081

Функции операций над строками. Библиотека обработки строк string.h содержит множество полезных функций для выполнения операций со стро-

Page 132: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

132

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

Таблица 3.19 Функции операций над строками

Прототип функции Описание функции char *strcpy (char *sl, const char *s2) Копирует строку s2 в массив s1. Воз-

вращает значение s1. char *strncpy (char *sl, const char *s2, int n)

Копирует не более чем n символов строки s2 в массив s1. Возвращает значение s1.

char *strcat (char *sl, const char *s2) Объединяет строку s2 со строкой массива s1. Первый символ строки s2 переписывает символ NULL строки s1. возвращает значение s1.

char *strncat (char *sl, const char *s2, int n)

Объединяет не более чем n символов строки s2 со строкой массива s1. Первый символ строки s2 переписы-вает символ NULL строки s1 cтроки s1. Возвращает значение s1.

int strlen (const char *s) Определяет длину строки s. Возвра-щает число символов, предшествую-щих ограничивающему символу NULL.

int strcmp (const char *s1, const char *s2)

Сравнивает строку s1 со строкой s2. Функция возвращает 0, значение меньше 0 или больше 0, если s1 соот-ветственно равна, меньше или боль-ше s2.

int strтcmp (const char *s1, const char *s2, int n)

Сравнивает до n символов строки s1 со строкой s2. Функция возвращает 0, значения меньше 0 или больше 0, ес-ли s1 соответственно равна, меньше или больше чем s2

Функция strcpy копирует второй аргумент (строку) в первый аргумент (массив символов), который должен иметь достаточный размер, чтобы за-помнить строку и ограничивающий символ NULL, который также копирует-

Page 133: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

133

ся. Функция strncpy эквивалентна strcpy за исключением того, что strncpy задает число символов, которые необходимо скопировать из строки в массив. Следует отметить, что функция strncpy не копирует ограничивающий сим-вол NULL второго аргумента, если не выполнено следующее условие: число копируемых символов превышает длину строки, по меньшей мере, на едини-цу. Например, если вторым аргументом является строка "test", то ограничи-вающий символ NULL записывается, только если значение третьего аргу-мента функции составляет не менее 5 (4 символа в строке "test" плюс 1 сим-вол NULL). Если значение третьего аргумента больше 5, то символы NULL добавляются в массив до тех пор, пока общее число записанных символов не станет равным числу, заданному в третьем аргументе.

Пример. Программа демонстрирует применение функции strcpy. #include<stdio.h> #include<string.h> #include <conio.h> void main () { char x[]= "Happy Birthday to You"; char y[25], z[15]; printf("The string in array x is: %s\n",x); printf("The string in array y is: %s\n", strcpy(y,x)); strncpy(z, x, 14); z[14]='\0'; printf ("The string in array z is: %s\n", z); getch(); }

Программа вызывает функцию strcpy для копирования всей строки из массива х в массив у и первых 14 символов из массива х в массив z. Символ NULL ('\0') добавляется в массив z в отдельном операторе, поскольку обра-щение программы к функции strncpy не копирует нулевой символ (третий аргумент меньше длины строки второго аргумента).

Результат работы программы имеет следующий вид:

The string in array x: Happy Birthday to You The string in array y: Happy Birthday to You The string in array z: Happy Birthday

Пример. Программа демонстрирует применение функций strcat и strncat.

#include<stdio.h> #include<string.h> #include <conio.h> void main ()

Page 134: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

134

{ char s1[20]="Happy "; char s2[]="New Year "; char s3[40]=""; printf("s1 = %s\ns2 = %s\n", s1, s2); printf("strcat(s1, s2) = %s\n", strcat(s1,s2)); printf("strncat(s3, s1, 6) = %s\n", strncat (s3, s1, 6)); printf ("strcat(s3, s1) = %s\n", strcat(s3, s1)); getch(); }

Программа вызывает функцию strcat, которая выполняет объединение строк (конкатенацию): второго аргумента — строки — с первым аргументом — массивом символов, содержащим строку. Первый символ второго аргу-мента заменяет последний символ NULL строки первого аргумента. Про-граммист должен убедиться, что массив, содержащий первую строку, доста-точен по размерам для хранения обеих строк и ограничивающего символа NULL, который копируется из второй строки. Функция strncat выполняет объединение определенного числа символов из второй строки с первой стро-кой. Ограничивающий символ NULL добавляется к строке результата авто-матически.

Результат работы программы имеет следующий вид:

s1 = Happy s2 = New Year strncat(s1, s2) = Happy New Year strncat(s3, s1, 6) = Happy strcat(s3, si) = Happy Happy New Year

Пример. Программа подсчитывает длину трех строк и демонстрирует приме-нение функции strlen.

#include<stdio.h> #include<string.h> #include <conio.h> void main () { char *string1 = "abcdefghijklmnopqrstuvwxyz"; char *string2 = "four"; char *string3 = "Boston"; printf("The length of \"%s\" is %lu\n", string1, strlen (string1)); printf("The length of \"%s\" is %lu\n", string2, strlen (string2)); printf("The length of \"%s\" is %lu\n", string3, strlen (string3)); getch(); } Результат работы программы имеет следующий вид:

Page 135: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

135

The length of "abcdefghijklmnopqrstuvwxyz" is 26 The length of "four" is 4 The length of "Boston" is 6

4.4 Связь между указателями и массивами

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

Объявление int a[5]; определяет массив из 5 элементов: a[0], a[1], a[2], [3], a[4]. Если объект *y объявлен как int *y; то оператор y=&a[0]; присваи-вает переменной y адрес элемента a[0] (рис. 3.16).

Рис. 3.16. Взаимосвязь указателей и массивов

Если переменная y указывает на очередной элемент массива a, то y+1 указывает на следующий элемент, причем здесь выполняется соответствую-щее масштабирование для приращения адреса с учетом длины объекта (для типа int – 2 байта, long – 4 байта и т.п.). Поскольку само имя массива есть адрес его нулевого элемента, инструкцию y=&a[0]; можно записать в виде y=a;. Тогда элемент a[i] можно представить как *(a+i). С другой стороны, ес-ли y – указатель, то следующие две записи: y[i] и *y(+i) – эквивалентны. Та-ким образом, любой массив и индексное выражение можно представить по-средством указателей. В то же время между именем массива и соответст-вующим указателем есть одно различие. Указатель – это переменная и y=a; или y++; – допустимые операции. Имя же массива – это константа. Поэтому

Page 136: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

136

конструкции вида a=y; a++; z=&a; использовать нельзя, так как значение кон-станты (в примере это a) постоянно и не может быть изменено.

Пример:

int *p1, *p2, x; p1=&m[0]; x=*(p1+1); //x=m[1] p2=m; //p1==p2

Если существуют два указателя p1 и p2, ссылающихся на один и тот же массив, то к ним можно применить операции, показанные в таблице 3.20.

Таблица 3.20. Операции с указателями.

p1++ устанавливает указатель p1 на следующий элемент массива mas; p2-- устанавливает указатель p2 на предыдущий элемент массива mas; p1+=i устанавливает указатель p1 на i элемент после p1; p2-=i устанавливает указатель p2 на i элемент после p2; p2-p1 дает число элементов между p1 и p2; p1==p2; p1!=p2; p1<p2; сравнение указателей p1>p2; p1<=p2; p1>=p2; сравнение указателей

Указатели в многомерных массивах. При определении многомерного массива компилятор использует несколько каскадно-связанных между собой объектов. Например, при объявлении массива

float fmas[2][3] = {{ 0.0, 0.1, 0.2} { 1.0, 1.1, 1.2}};

определяется значение указателя-константы fmas (рис. 3.17). Выражения fmas[0] и fmas[1] в свою очередь также являются указателями. Значениями этих двух указателей являются адреса первого элемента каждой строки мат-рицы, т.е. адреса fmas[0][0] и fmas[1][0]. Эти указатели определяют началь-ный адрес размещения в памяти двух массивов, каждый из которых предна-значен для записи трех элементов типа float. Следует отметить, что фактиче-ски в памяти никакого массива указателей с элементами fmas[0] и fmas[1] компилятор не создаёт.

Рис. 3.17. Указатели в многомерных массивах

Page 137: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

137

Для установки указателя на некоторую строку матрицы используются выражения вида fmas[i] или *(fmas+i). Выборка самих значений элементов матрицы реализуется выражениями fmas[i][j] или *(*(fmas+i)+j) или (*(fmas+i))[j].

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

Пример. Некоторые способы адресации элементов массивов.

#include <stdio.h> #include <conio.h> void main() {

float x[2][3]={1,2,3,4,5,6,},*px1, **px2, y, y1, y2, y3; printf("\n %p %p %p !!!",x,x[0],x[1]); px1=x[0]; y1=*(px1+1*3+2); y2=px1[1*3+2]; y3=px1[5]; printf("\n %f %f %f %f---",x[1][2],y1,y2,y3); px1=x[1]; y2=px1[2]; y3=*(px1+2); printf("\n %f %f %f+++",x[1][2],y2,y3); y1=*(px1=x[0]); px2=&px1; y2=*(*px2+1*3+2); y3=(*px2)[5]; printf("\n %f %f %f===",y1,y2,y3); getch();

}

Выше использовался оператор y=px1[5], где px1 был указателем на од-номерный (линейный) массив, из которого извлекался элемент с индексом 5 (т.е. последний элемент массива x: х[2][3]). Однако нельзя использовать за-пись y=x[5], так как y – это переменная типа float, а x[i] – это указатель на одномерный массив типа float; кроме того, есть только два указателя вида x[i]: x[0] и x[1], а x[5] к тому же нет.

Выше встретился оператор px2++. Так как px2 – переменная, то такая операция правильная, но нельзя выполнить x++; либо x[0]++; или x[1]++; ввиду того, что x, x[0], x[1] являются константными указателями, задающими месторасположение соответствующих объектов, адреса которых после за-грузки программы на выполнение не изменяются.

Page 138: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

138

Указатели в строковых литералах. Так как язык Си не поддерживает элементы типа строка, то для работы со строками обычно используется ука-затель типа char*.

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

Пример:

char *str="МИУ";

Здесь описывается только указатель str, и указатель получает начальное значение, равное адресу первого элемента (символа 'М') строковой констан-ты. Компилятор выделит память как для строки (четыре байта), так и для размещения значения указателя.

Если строковая константа используется в тех местах выражения, где разрешается применять указатель, компилятор подставляет в выражение вме-сто константы адрес ее первого символа.

Использование указателей и массива символов показано в таблице 3.21.

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

Работа со строками через указатель

Работами со строками через массив символов

char *str=”cat”, *st; char st[]=”cat”, s[10]; scanf (“%s”, st); scanf (“%s”, s); scanf (“%s”, &st[0]); scanf (“%s”, &s[0]);

Создать массив указателей типа char можно также и следующим обра-зом:

char *str1[10]; // массив из 10-ти указателей

Инициализацию массива строк и массива указателей можно выполнить следующим образом:

char *strm[2]={“DELTA”, “23435”}; Ввод строк можно осуществить следующими способами:

char sd[4][7]; for (int i=0; i<4; i++) scanf(“%s”, sd[i]); char *jk[5]; for (int i=0; i<5; i++) scanf(“%s”, jk[i]);

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

Page 139: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

139

Примеры использования указателей:

char *s; s=”cat”; char *p[3] ={“123”, “234”, “345”}; printf(“%s”, p[i]); //вывод строки printf(“%s”, (p+i)); //ошибка, попытка вывести адрес printf(“%s”, s); //вывод строки printf(“%s”, *s); //ошибка, попытка вывести один знак

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

Пример. Рассмотрим программу сортировки срок в алфавитном порядке.

#include<stdio.h> #include<conio.h> #include<string.h> void main() { char lines[10][50], *pc[10], *uk, s_string[]=" "; int i, k, j; puts("Введите 10 строк или ENTER");

for(k=0; k<10; k++) { gets(lines[k]);

if (!strcmp(lines[k],s_string)) break; pc[k]=lines[k];

} puts("Сортировка\n"); for(i=0; i<k-1; i++)

for(j=i+1; j<k; j++) if(strcmp(pc[i], pc[j])>0) {

uk=pc[i]; pc[i]=pc[j]; pc[j]=uk; }

for(i=0; i<k; i++) puts(pc[i]);

getch(); }

При решении задачи мы использовали как двумерный массив lines[10][50], так и массив указателей на строки *pc[10]. Сравнение строк происходит в функции strcmp, которой передаются указатели на эти строки. Для того чтобы поменять строки местами, достаточно поменять местами ука-затели на эти строки в массиве указателей *pc. Массив указателей сортирует-ся так, чтобы первый элемент указывал на самую "младшую" по алфавиту строку, а самый последний – на самую "старшую" строку. При вводе строк

Page 140: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

140

каждая строка сравнивается с нулевой строкой для проверки условия окон-чания ввода.

Функция strcmp посимвольно сравнивает строки, и возвращает резуль-тат в виде целого числа: большего, меньшего или равного 0, что является признаком того, какая из строк больше, или же они равны (см. табл. 3.20).

4.5 Структуры

Языки программирования C/C++ поддерживает определяемые пользо-вателем структуры – структурированный тип данных. Он является собранием одного или более объектов (переменных, массивов, указателей, других структур и т.д.), которые для удобства работы с ними сгруппированы под од-ним именем.

Структуры имеют следующие достоинства: - облегчают написание и понимание программ. - помогают сгруппировать данные, объединяемые каким-либо общим

понятием. - позволяют группу связанных между собой переменных использовать

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

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

Определение структуры состоит из двух шагов: - объявление шаблона структуры (задание нового типа данных, опре-

деленного пользователем); - определение переменных типа объявленного шаблона.

Объявление шаблонов структур. Общий синтаксис объявления шаб-лона структуры:

struct имя_шаблона { тип1 имя_переменной1; тип1 имя_переменной1; //другие члены данных; };

Пример объявления структур:

struct DateBase { char fam[20];

Page 141: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

141

char name[15]; long TelNumber; char *Adress; double w; };

Имена шаблонов должны быть уникальными в пределах их области оп-ределения для того, чтобы компилятор мог различать различные типы шаб-лонов. Задание шаблона осуществляется с помощью ключевого слова struct, за которым следует имя шаблона структуры и список элементов, заключен-ных в фигурные скобки.

Имена элементов в одном шаблоне также должны быть уникальными. Однако в разных шаблонах можно использовать одинаковые имена элемен-тов.

Задание только шаблона не влечет резервирования памяти компилято-ром. Шаблон представляет компилятору необходимую информацию об эле-ментах структурной переменной для резервирования места в оперативной памяти и организации доступа к ней при определении структурной переме-ной и использовании отдельных элементов структурной переменной.

Среди членов данных структуры могут также присутствовать, кроме стандартных типов данных (int, float, char и т.д.), ранее определенные типы.

Пример:

/* объявление шаблона структуры типа date */ struct date { int day, month, year; };

/* шаблон структуры person */ struct person {

char fam[30], im[20], otch[15]; float weight; int height; struct date birthday;

};

Структура date имеет три поля типа int. Шаблон структуры person в качестве элемента включает поле birthday, которое, в свою очередь, имеет ранее объявленный тип данных: struct date. Этот элемент (birthday) содержит в себе все компоненты шаблона struct date.

Определение структур-переменных. Определение структуры-переменной ничем не отличается от объявления обычной переменной с пре-допределенным типом. Общий синтаксис:

struct имя_шаблона имя_переменной;

Page 142: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

142

Пример:

struct person stud[10];

Компилятор выделит под каждую переменную количество байтов па-мяти, необходимое для хранения всех ее элементов.

Разрешается совмещать описание шаблона и определение структурной переменной.

Пример:

struct book {

char title[20]; char autor[30]; double cast;

} book1, book2, *ptr_bk=&book1; Пример:

struct date {int day, month, year;} date1[5]; // объявление массив из 15 структур

Доступ к компонентам структуры. Доступ к полям осуществляется с помощью оператора "." при непосредственной работе со структурой или "->" - при использовании указателей на структуру. Эти операторы называют-ся селекторами членов класса. Общий синтаксис для доступа к компонентам структуры следующий:

имя_переменной_структуры.член_данных; имя_указателя->имя_поля; (*имя_указателя).имя_поля;

Пример. Прямой доступ к элементам:

1) date1[5].day=10; 2) date1[5].year=1991; 3) strcpy(book1.title, «Война и мир»);

/* Используя прямое обращение к элементу, присваиваем значение выбран-ной переменной. Текст помещается в переменную, используя функцию копи-рования – strcpy(); */

4) stud[3].birthday.month=1; 5) stud[3].birthday.year=1980;

Доступ по указателю:

1) (date1+5)->day=10; 2) (date1+5)->year=1991; 3) (stud+3)->birthday.month=1; 4) (stud+3)->birthday.year=1980;

Page 143: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

143

// Используя доступ по указателю на структуру, присваиваем значение соот-ветствующей переменной. Указатель можно использовать и так:

5) (*(date1+5)).day=10; 6) (*(date1+5)).year=1991; 7) (*(stud+3)).birthday.month=1; 8) (*(stud+3)).birthday.year=1980;

Инициализация структур. При определении структурных перемен-ных можно инициализировать их поля. Эта возможность подобна инициали-зации массива и следует тем же правилам:

имя_шаблона имя_переменной_структуры = {значение1, значение2, …}; Компилятор присваивает значение1 первой переменной в структуре,

значение2 – второй переменной структуры и т.д.. При этом необходимо сле-довать следующим правилам:

- присваиваемые значения должны совпадать по типу с соответствую-щими полями структуры;

- можно объявлять меньшее количество присваиваемых значений, чем количество полей; компилятор присвоит нули остальными полями структу-ры;

- список инициализации последовательно присваивает значения полям структуры, вложенных структур и массивов.

Пример: struct date { int day,month,year; }d[5] = { {1,3,1980}, {5,1,1990}, {1,1,1983} };

Копирование структур-переменных. Язык С(С++) позволяет опера-тору присваивания копировать значения одной структуры-переменной в дру-гую переменную, при условии, что обе структуры-переменные относятся к одному и тому же типу. Таким образом, единственный оператор может ско-пировать несколько членов данных, которые включают массивы и вложен-ные структуры.

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

Структуры как параметры функций. В функцию можно наряду со стандартными типами данных передавать и структуры. Компилятор передаст

Page 144: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

144

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

// объявление шаблона структуры Men struct Men {

char *String; int Number; int Marks[10];

};

struct Men Summa (struct Men); - прототип функции, в которую преда-ется копия переменной типа структуры Men, которая, в свою очередь, воз-вратит в основную программу значение того же типа.

void Summa (struct Men*); - другой вариант прототипа функции, но с использованием указателя типа структура. В функцию передается указатель на структуру, функция выполнит свою задачу и запишет преобразованную структуру в память по указателю, который в нее передан; в основном модуле преобразованная структура будет находиться по тому же адресу, что и до пе-ресылки в функцию, поэтому функция ничего не возвращает. Этот вариант функции совершеннее первого: он будет работать быстрее и требует мень-шей памяти.

Пример. Пример программы ввода данных структуры, в которой будут реали-зованы обе выше упомянутые функции:

#include<stdio.h> struct Men {char Name[20]; int Tel;}; struct Men Func1 (struct Men); void Func2 (struct Men *); struct Men Func3 (void); void main( ) { struct Men Student;

puts(" Запуск первой или второй функции-?"); fflush(stdin); switch (getchar())

{ case '1': Student=Func1(Student); break; case '2': Func2(&Student); break; case '3': Student=Func3(); break; }

printf("Сотрудник - %s Телефон- %d\n", Student.Name, Student.Tel); } struct Men Func1 (struct Men Student) { puts (" Введи данные о сотруднике ");

fflush(stdin); gets(Student.Name);

Page 145: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

145

scanf("%d",&Student.Tel); return Student;

} void Func2 (struct Men *Student) { puts (" Введи данные о сотруднике ");

fflush(stdin); gets(Student->Name); scanf("%d", &Student->Tel);

} struct Men Func3 (void) { struct Men student;

puts("Введите данные:"); fflush(stdin); gets(student.Name); scanf("%d",&student.Tel); return student;

}

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

Выделение памяти под структурную переменную осуществляется по шаблону, в последовательности объявления ее элементов.

При размещении структурной переменной в памяти для выравнивания на границу слова компилятор оставляет между ее элементами и элементами массива структурных переменных пустые байты для соблюдения следующих правил:

- структурная переменная (элемент массива структур) начинается на границе слова, т.е. с четного адреса;

- любой элемент, кроме элементов типа char, так же располагается с четного адреса и соответственно имеет четное смещение от начала структур-ной переменной;

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

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

Рассмотрим примеры программ работы со структурами. Пример. Ввести массив структур. Рассортировать массив в алфавитном по-

рядке фамилий, входящих в стуктуру.

Page 146: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

146

#include <stdio.h> int strcmp(char *s1 ,char *s2); struct st {char name[80]; int age;}; void main() { struct st m[100], t;

int i, j, k; printf("\nk-?"); scanf("%d", &k); for(i=0; i < k; i++) { fflush(stdin); gets( m[i].name); scanf("%d", &m[i].age);

} for(i=0;i<k;i++)

for(j=i+1 ;j<k;j++) if (strcmp(m[i].name,m[j].name)>0) { t=m[i]; m[i]=m[j]; m[j]=t;} printf("Sorted:\n"); for(i=0;i<k; i++) { puts(m[i].name); printf("%d years\n", m[i].age); } } int strcmp(char *s1 ,char*s2) { for(; *s1 == *s2; s1++, s2++) if( !*s1 ) return 0; return *s1-*s2; } Пример. Создать массив структур о студентах группы. О каждом студенте за-

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

#include<stdio.h> #include<conio.h> struct student { char name[20]; char fam[30]; int year; int mark[5]; int average; }; struct student students[30]; struct student buffer; int records; int i, j; void main() {

Page 147: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

147

records=0; do { printf("Student №%d\n", records+1); puts("Vvedite familiu: "); fflush(stdin); fgets(students[records].fam,30,stdin); puts("Vvedite imya: "); fflush(stdin); fgets(students[records].name,20,stdin); puts("Vvedite vozrast: "); scanf("%d", &students[records].year); for(i=0; i<5; i++) { printf("Vvedite ocenku po ekzamenu №%d ", i+1); scanf("%d", &students[records].mark[i]); } records++; puts("Prekratit' rabotu? (1/0)"); scanf("%d", &i); } while(i); for (i=0; i<records; i++) { students[i].average=0; for (j=0; j<5; j++) students[i].average+=students[i].mark[j]; } for (i=0; i<records-1; i++) for (j=i; j<records; j++) if (students[i].average>students[j].average) { buffer=students[i]; students[i]=students[j]; students[j]=buffer; } for (i=0; i<records; i++) { printf("Student %s%s ", students[i].name, students[i].fam); printf(" Vosrast %d ", students[i].year); printf(" Sr. ball %d \n", students[i].average); } getch(); } Пример. Ввести массив структур со списком студентов и оценками. Рассор-

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

#include<stdio.h> #include<conio.h> #include<string.h> struct student

Page 148: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

148

{ char fio[80]; int mark[5]; }; void main() { int i,j,size; struct student st[100], *stp[100], *tmp; do { printf("Vvedite kol-vo studentov: "); scanf("%d", &size); } while (size>100); for (i=0; i<size; i++) { puts("Vvedite FIO studenta: "); fflush(stdin); fgets(st[i].fio,80,stdin); puts("Vvedite ego ocenki: "); for(j=0; j<5; j++) scanf("%d", &st[i].mark[j]); stp[i]=&st[i]; } for (i=0; i<size-1; i++) for (j=i+1; j<size; j++) if (strcmp(stp[i]->fio, stp[j]->fio)>0) { tmp=stp[i]; stp[i]=stp[j]; stp[j]=tmp; } printf("\n\nRezultat: "); for (i=0; i<size; i++) { printf("\n\n"); puts(stp[i]->fio); printf("Ego ocenki: "); for (j=0; j<5; j++) printf("%d ", stp[i]->mark[j]); } getch(); } Пример. Ввести массив структур. Рассортировать массив в алфавитном по-

рядке фамилий, входящих в структуру, перемещая сами структуры.

#include<stdio.h> #include<conio.h> int strcomp(struct stud s1, struct stud s2);

Page 149: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

149

struct stud { char r[64]; int a,b,c; }; void main() { int i,j,k; struct stud s[10], t; do { puts("k-?"); scanf("%d", &k); for (i=0; i<k; i++) scanf("%s%d%d%d", s[i].r, &s[i].a, &s[i].b, &s[i].c); for (i=0; i<k-1; i++) for (j=i+1; j<k; j++) if (strcomp(s[i], s[j])>0) { t=s[i]; s[i]=s[j]; s[j]=t; } puts("0 - exit; 1 - continue"); scanf("%d", &i); }while (i); printf("\n\nRezultat: "); for (i=0; i<k; i++) printf("\n\n Name: %s a=%d b=%d c=%d", s[i].r, s[i].a, s[i].b, s[i].c); getch(); } int strcomp(struct stud s1, struct stud s2) { int i; for(i=0; s1.r[i]==s2.r[i]; i++) //Ошибка: for(; *s1.r==*s2.r; s1.r++, s2.r++) - нельзя наращивать константу if(s2.r[i]=='\0') return 0; return *s1.r-*s2.r; }

Тема 5 ФУНКЦИИ (ПОДПРОГРАММЫ) 5.1 Общие сведения о функциях

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

Page 150: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

150

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

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

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

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

return (выражение);

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

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

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

Рассмотрим, как соответствуют друг другу параметры в вызове и в списке функции (рис. 3.18). Пусть вызывающая программа обращается к функции следующим образом:

a=fun(b,c);

Здесь b и c – аргументы, значения которых передаются в вызываемую под-программу. Если описание функции начинается так:

fun(b,c)

Page 151: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

151

то имена передаваемых аргументов в вызове и в программе fun будут одина-ковыми (рис. 3.18, а).

а) б) с)

Рис. 3.18. Установление соответствия между параметрами в вызове и списке

функции

Если же описание функции начинается, например, строкой

fun(i,j)

то вместо имени b в вызвавшей функции fun будет использовано имя i, а вме-сто c – j (рис. 3.18,б). Еще более интересное соответствие показано на рис. 3.18,в. Здесь обращение к функции имеет вид:

a=fun(&b,&c);

В результате идентификатор b в вызванной функции будет указателем на значение b (адресом значения b), а идентификатор c в подпрограмме – указа-телем на значение c в вызвавшей функции. Если в вызове используются те же имена, что и в списке параметров, но они записаны в другом порядке (на-пример, для рис. 3.18,а fun(c,b)), то все равно устанавливается соответствие между i-м именем в списке и i-м именем в вызове. После указанного выше изменения на рис. 3.18, а идентификатор b в программе будет соответство-вать c в подпрограмме и c в программе – b в подпрограмме.

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

В языке Си следует различать "прототип функции" и "определение функции".

Page 152: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

152

5.2 Прототип функции

Прототип функции – это ее имя с указанием типа возвращаемого ре-зультата и перечислением в круглых скобках (через запятую) типов посту-пающих параметров:

[тип_результата] имя_функции (список_формальных_параметров);

Пример:

double sum(double, double); int max(int a, int b);

Прототип функции завершается точкой запятой. Прототип является предварительным объявлением данных функции: имени функции, а также количества и типов параметров, типа результата. Тело функции, заключенное в фигурные скобки {}, в прототипе отсутствует. В том случае, когда в функ-цию не передаются аргументы, в прототипе в круглых скобках вместо списка параметров записывается слово void либо ничего не указывается.

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

5.3 Определение функции

Определение функции – это код, описывающий, что делает функция, т.е. ее полная реализация. Формально это выглядит так:

[тип_результата] имя_функции (список_формальных_параметров) {

тело функции; }

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

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

5.4 Вызов функции

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

Page 153: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

153

скобки обязательны. В круглых скобках могут быть записаны как перемен-ные и/или константы, так и вычисляемые выражения, разделенные запятыми.

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

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

ся в круглых скобках после имени функции), называются фактическими па-раметрами или аргументами.

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

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

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

Последовательность записи аргументов должна соответствовать после-довательности параметров. Типы аргументов должны быть совместимы с ти-пами соответствующих им параметров.

Пример:

#include <iostream.h> int add(int a, int b); // прототип функции add void main() { int a, b, res;

a=1; b=3; res=add(a,b); // вызов функции add printf (“rezalt= %d”, res);

}

Page 154: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

154

int add(int a, int b) // определение функции add { return a+b;}

5.5 Возвращаемые значения

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

Оператор имеет следующий формат:

return [(выражение)];

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

Примеры:

return; return 0; return obj; return (i*j+5);

Значение выражения, вычисленное в операторе return, возвращается в вызывающую функцию в качестве результата выполнения функции. Если функция возвращает результат, то ее вызов можно использовать в качестве операнда в выражении.

Пример:

y = add(a,b)*2;

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

Допускается реализация функций, не возвращающих никаких значе-ний. Если в операторе return отсутствует выражение, то вызывающей функ-ции никакое значение явно не возвращается.

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

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

Page 155: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

155

Функция также не может вернуть функцию, но может передать резуль-тат – указатель на функцию.

Если функция определена как возвращающая результат, а в операторе return выражение отсутствует, то выдается сообщение об ошибке.

5.6 Передача аргументов в функцию

Функции могут обмениваться информацией тремя способами: 1) используя глобальные переменные; 2) передавая копию; 3) передавая адрес, по которым записаны значения переменных (аргу-

ментов). При реализации первого способа глобальные переменные объявляются

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

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

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

Механизм передачи значения некоторого аргумента заключается в сле-дующем:

– в случае, если аргумент есть имя некоторой переменной или является выражением, то осуществляется копирование значения аргумента в стек на

Page 156: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

156

место соответствующего параметра, т.е. реализуется второй способ обмена данными – передача аргумента по значению;

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

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

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

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

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

Можно использовать три варианта описания массива, поступающего в функцию, в качестве параметра.

1) Параметр в функции может быть объявлен как массив соответст-вующего типа с указанием его размера.

Пример:

// Тело функции #include <stdio.h> int sum(int x[5]) // Определение функции, размер массива указан { int res=0; for(int i=0; i<5; i++) res+=x[i]; // Вычисление суммы элементов массива x return res; } // // Тело программы void main() { int mas[3][5], i, j; for(i=0; i<3; i++) for(j=0; j<5; j++) mas[i][j]=i*j; // Вычисление произведения индексов for(i=0; i<3; i++) printf(“\n res=%d”, sum(mas[i])); //Вызов функции sum }

Page 157: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

157

В этом случае Си автоматически преобразует mas[i] к указателю на це-лый тип, и в функцию передается адрес первого элемента каждой строки матрицы, т.е. адрес элемента mas[i][0]. В функции вычисляется сумма эле-ментов каждой строки матрицы и сумма выводится на экран.

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

Пример:

// Тело функции int sum(int x[]) // Определение функции, размер не указан { int res=0; for(int i=0; i<5; i++) // i<5 – размер известен программисту res+=x[i]; return res; } // Вызов функции остается тем же

3) Наиболее распространенный способ, обычно используемый при на-писании профессиональных программ – объявление параметра «массив» ука-зателем на соответствующий тип данных. Функцию можно вызывать так, как было проиллюстрировано выше, но можно и так:

Пример:

// Тело функции #include <stdio.h> int sum(int *x) //Определение функции, используется указатель { int res=0; for(int i=0; i<5; i++) res+=*x++; // можно записать и res+=x[i] return res; } // Тело программы void main() { int mas[3][5], i, j; for(i=0; i<3; i++) for(j=0; j<5; j++) mas[i][j]=i*j; for(i=0; i<3; i++) printf(“\n res=%d”, sum(&mas[i][0])); }

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

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

Page 158: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

158

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

5.8 Рекурсия

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

1) при каждом вызове такой функции в вызываемую функцию должны передаваться модифицированные данные;

2) на каком-то этапе должен быть прекращен дальнейший вызов дан-ной функции. Рекурсивный процесс должен шаг за шагом так упрощать зада-чу, чтобы в конце концов для нее появилось не рекурсивное решение. Здесь легко допустить ошибку, заключающуюся в том, что функция будет после-довательно вызывать саму себя бесконечно долго;

3) после завершения каждого экземпляра рекурсивной функции в вы-зывающую должен возвращаться некоторый результат для дальнейшего ис-пользования.

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

Page 159: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

159

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

Для иллюстрации работы этой концепции мы создадим рекурсивную программу, выполняющую распространенный вид математических вычисле-ний.

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

n! = n * (n - 1) * (n - 2)*…*1

Факториал целого number, большего или равного 0, может быть вычис-лен итеративно (не рекурсивно) с помощью цикла for:

fact = 1; for (counter = number; counter>=1; counter--)

fact *= counter;

Рекурсивное определение функции для вычисления факториала осно-вано на следующем соотношении:

n! = n*(n-1)!

Например, очевидно, 5! равен 5 * 4!, как показано ниже:

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

Вычисление 5! могло бы выполняться по схеме, приведенной на рис 3.19:

Page 160: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

160

Рис. 3.19. Схема рекурсивного вычисления факториала

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

Пример. Рекурсивная функция factorial для вычисления факториала.

#include <stdio.h> long factorial(long); void main () {

int i; for (i = 1; i <= 10; i++) printf ("%2d != %ld\n", i, factorial (i));

} /* Рекурсивное определение функции factorial */ long factorial(long number) {

if (number <= 1) return 1;

else return (number * factorial(number - 1));

}

Программа, приведенная в примере, использует рекурсию для вычис-ления и вывода на печать факториалов целых чисел от 0 до 10. Рекурсивная функция factorial сначала проверяет, выполняется ли условие завершения: переменная number меньше или равна 1. Если number действительно мень-

Page 161: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

161

ше или равна 1, factorial возвращает 1; в дальнейшей рекурсии необходимо-сти нет и программа завершается. Если number больше 1, оператор

return number*factorial(number-1);

представляет задачу как вычисление произведения number на рекурсивный вызов factorial, возвращающий факториал от number - 1. Обратите внима-ние, что факториал от (number - 1) — немного более простая задача, чем ис-ходная задача factorial (number).

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

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

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

Page 162: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

162

Любая проблема, которая может быть решена рекурсивно, может также быть решена итеративно (не рекурсивно). Рекурсивный подход обычно пред-почитается итеративному в тех случаях, когда рекурсия более естественно отражает математическую сторону задачи и приводит к программе, которая проще для понимания и отладки. Другой причиной для выбора рекурсивного решения является то, что итеративное решение может не быть очевидным.

Тема 6 ФАЙЛЫ 6.1 Понятие файла

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

d:spis.fio

задает спецификацию файла, размещенного на диске d:, имеющего имя spis и тип, или расширение имени, fio.

Файлы широко применяются при решении различных задач. Основные отличия файла от массива: 1) Файлы в отличие от массивов располагаются не в оперативной памя-

ти, а на жестких дисках или на внешних носителях, хотя файл может распо-лагаться на так называемом электронном диске (в оперативной памяти).

2) Файл не имеет фиксированной длины, т.е. может увеличиваться и уменьшаться.

3) Перед работой с файлом его необходимо открыть, а после работы – закрыть.

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

Имена файлов состоят из двух частей, разделенных точкой: имя файла и расширение. Файлы хранятся в каталогах (папках, директориях). Каталоги могут иметь такие же имена, что и файлы. Допускаются вложенные каталоги (подкаталоги).

При работе с файлами в языке Си различают два основных вида фай-лов: текстовые и бинарные.

Текстовые файлы могут быть просмотрены и отредактированы с кла-виатуры любым текстовым редактором и имеют очень простую структуру:

Page 163: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

163

последовательность ASCII-символов. Эта последовательность символов раз-бивается на строки, каждая из которых заканчивается двумя кодами: 13, 10 (0xD, 0xA). Примеры известных текстовых фалов: *.bat, *.c, *.asm, *.срр.

Бинарные файлы – это файлы, которые не имеют структуры текстовых файлов. Каждая прикладная программа для своих бинарных файлов опреде-ляет собственную структуру.

Библиотеки языка C/С++ содержат функции для работы как с тексто-выми, так и с бинарными файлами.

6.2 Открытие и закрытие файла

Прежде чем получить возможность чтения или записи информации в файл, он должен быть открыт. Это можно сделать с помощью библиотечной функции fopen. Она берет внешнее представление – физическое имя файла (например, b:p42.c) и ставит ему в соответствие внутреннее логическое имя, которое используется далее в программах.

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

Функция открытия файла fopen() в общем случае имеет два параметра, оба являются строковыми литералами:

FILE *fopen(char *filename, char *mode);

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

char *filename – задает физическое местонахождение (путь) и имя от-крываемого файла;

char *mode – тип доступа к файлу.

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

Тип доступа к файлу принимает значения, показанные в таблице 3.22.

Page 164: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

164

Таблица 3.22. Тип доступа к файлам

Тип доступа Назначение "r" Открыть файл для чтения. "w" Открыть файл для записи. Если файл существует, то его со-

держимое теряется. "a" Открыть файл для записи в конец файла. Если файл не су-

ществует, то он создается. "r+" Открыть файл для чтения и записи. Файл должен существо-

вать. "w+" Открыть файл для чтения и записи. Если файл существует,

то его содержимое теряется. "a+" Открыть файл для чтения и записи в конец файла. Если

файл не существует, то он создается. "t" Открыть файл в текстовом режиме. "b" Открыть файл в бинарном режиме.

С добавлением литералов "t" либо "b" возможны следующие режимы доступа: "w+b", "wb+", "rw+", "w+t", "rt+" и др. Если режим не указан, то файл открывается в текстовом режиме.

После работы с файлом он должен быть закрыт функцией fclose(). Для этого необходимо в указанную функцию передать указатель на

FILE, который был получен при открытии функцией fopen(). При заверше-нии программы незакрытые файлы автоматически закрываются системой.

Стандартная последовательность операторов, необходимая для откры-тия и закрытия файла:

#include <stdio.h> .......... FILE *f; if(!(f = fopen(“readme.txt”, ”r+t”))) { printf(“Невозможно открыть файл \n”); return; } …….. // Работа с файлом fclose(f); // Закрытие файла ……….

6.3 Запись и чтение информации

Для работы с текстовыми файлами используются такие функции, как: fprintf(), fscanf(), fgets(), fputs(). Формат параметров этих функций очень по-хож на формат функций printf(), scanf(), gets() и puts(). Схожи не только па-

Page 165: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

165

раметры, но и действия. Отличие лишь в том, что printf(), scanf() и другие работают по умолчанию с консолью (экран, клавиатура), а fprintf(), fscanf() – с файлами (в том числе и со стандартными потоками stdin, stdout и др.), по-этому у них добавлен параметр f, являющийся указателем на структуру FILE.

Рассмотрим на примерах запись текстовой информации в файл с ис-пользованием функции fprintf( ) – форматированного вывода в файл.

Пример. Программа записывает в текстовый файл числа от 0 до 100 крат-ные 3.

#include <stdio.h> void main( ) { int a; FILE *f; if(!(f = fopen("test.txt", "w+t"))) { printf("Невозможно создать файл\n"); return; } for(a=0;a<1000;a+=3) { fprintf(f, "%d, ",a); } fclose(f); }

Для записи и считывания строк из файла используются следующие библиотечные функции:

char *fgets(char *string, int n, FILE *stream) – считывает строку из файла stream до тех пор, пока не будут считаны (n-1) символ, либо символ перевода строки, либо достигнут конец файла. Возвращает указатель на string, а в случае ошибки или при достижении конца файла – NULL-указатель.

int fputs(char *string, FILE *stream) – копирует в файл символьную строку (до нуль-терминатора) из памяти, на которую указывает string. Воз-вращает код последнего записанного в файл символа, при ошибке – EOF.

Функции для работы с текстовыми файлами удобно использовать при создании текстовых файлов, ведении файлов-протоколов (log-файлов) и т.п. Но при создании баз данных целесообразно использовать функции для рабо-ты с бинарными файлами: fwrite() и fread(). Эти функции без каких-либо из-менений копируют блок данных из оперативной памяти в файл и соответст-венно из файла – в память. Такой способ обмена данными требует меньше времени. Прототипы функций для чтения и записи из/в бинарный файл име-ют следующий вид:

Page 166: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

166

unsigned fread (void *ptr, unsigned size, unsigned n, FILE *stream); unsigned fwrite(void *ptr, unsigned size, unsigned n, FILE*stream);

где *ptr – указатель на буфер; size – размер блока; n – количество блоков; *stream – указатель на структуру FILE открытого файла. В функциях первым параметром передается указатель на буфер, в ко-

торый будут помещены данные из файла функцией fread() или из которого данные будут прочитаны функцией fwrite(). Следующие два параметра зада-ют размер блока и, соответственно, количество читаемых или записываемых блоков. Последний параметр – указатель на структуру FILE.

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

6.4 Позиционирование в файле

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

int fseek(FILE *stream, long offset, int whence);

Параметр offset задает количество байт, на которое необходимо сме-стить указатель соответственно параметру whence. Параметр whence может принимать следующие значения:

- SEEK_SET - Смещение выполняется от начала файла. - SEEK_CUR - Смещение выполняется от текущей позиции указателя.

Page 167: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

167

- SEEK_END - Смещение выполняется от конца файла. Величина смещения может быть как положительной, так и отрицатель-

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

Пример. Имеется файл inf.dat, который содержит фамилию абитуриента и 3 его оценки. Прочитать из файла данные об абитуриенте по введенному его поряд-ковому номеру в списке.

#include <stdio.h> struct abitur { char name[32]; // ФИО абитуриента int mark[3]; // Оценки абитуриента }; void main( ) { struct abitur inf; int n; FILE *f; if(!(f=fopen("inf.dat","r"))) { printf("Ошибка создания файла\n"); return; } while(1) { printf("Введите номер записи (0 - выход): "); scanf("%d", &n); if(!n) break; // выход по нулю fseek(f, sizeof(struct abitur)*(n-1), SEEK_SET); /* Смещение к необходимой записи от начала файла */ if(sizeof(inf) != fread(&inf, 1, sizeof(inf), f)) /* Чтение блока данных. Если запись не прочитана, то достигнут конец файла */ printf("Конец списка\n"); else // Иначе, вывод записи на печать printf(“%s%d%d%d”, inf.name, inf.mark[0], inf.mark[1], inf.mark[2]); } fclose(f); }

Иногда необходимо определить позицию указателя. Для этого можно воспользоваться функцией ftell():

long ftell(FILE *stream);

Данная функция возвращает значение указателя на текущую позицию файла. В случае ошибки возвращает число (-1).

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

Page 168: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

168

int fsetpos(FILE *stream, const long *pos) – устанавливает значение указателя чтения-записи (указатель на текущую позицию) файла в позицию заданную значением по указателю pos.

int fgetpos(FILE *stream, long *pos) – помещает в переменную, на ко-торую указывает pos, значение указателя на текущую позицию в файле.

Обе эти функции при корректном выполнении возвращают нуль, и лю-бое не нулевое значение при ошибке.

Пример. С клавиатуры запрашивается пять строк и они записываются в файл 111.txt. Затем указатель позиции чтения файла устанавливается на начало файла, считываются строки и выводятся на экран.

#include<stdio.h> #include<conio.h> void main (void) { FILE*fp; char s[80]; int i=0; puts(" STRING"); fp = fopen("111.txt","w"); // файл открыт для записи for(i=0;i<5;i++) { fgets(s, 80, stdin); fputs(s,fp); } rewind(fp); // указатель файла установлен на начало fclose(fp); fp=fopen("111.txt","r+"); // файл открыт для чтения while(1) // печать файла с начала { if(! fgets(s,80,fp)) { fclose(fp); puts("EXIT"); break; } fputs(s, stdout); } } Пример. Программа создает простой файл последовательного доступа, ко-

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

Page 169: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

169

вольном порядке. В этом случае записи должны сначала упорядочиваться, а за-тем уже записываться в файл.

#include <stdio.h> void main () { int account; char name[30]; float balance; FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "w")) == NULL) printf ("File could not be opened\n"); else { printf("Enter the account, name, and balance.\n"); printf ("Enter EOF to end input.\n"); printf("? "); scanf("%d%s%f", &account, name, &balance); while ( !feof(stdin)) { fprintf(cfPtr, "%d %s %.2f\n", account, name, balance); printf("? "); scanf("%d%s%f", &account, name, &balance); } fclose (cfPtr); } }

Пример. Чтение и распечатка последовательного файла, созданного в пре-дыдущем примере.

#include <stdio.h> void main () { int account; char name[30]; float balance; FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "r")) == NULL) printf("File could not be openedXn") ; else { printf("%-10s%-13s%s\n", "Account", "Name", "Balance"); fscanf(cfPtr, "%d%s%f", &account, name, &balance); while (!feof(cfPtr)) { printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } fclose(cfPtr); } }

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

Page 170: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

170

#include <stdio.h> void main () { int request, account; float balance; char name[30]; FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "r")) == NULL) printf("File could not be opened\n"); else { printf("Enter request\n"); printf(" 1 - List accounts with zero balances\n"); printf(" 2 - List accounts with credit balances\n"); printf(" 3 - List accounts with debit balances\n"); printf(" 4 - End of run\n? "); scanf("%d", &request); while (request != 4) { fscanf(cfPtr, "%d%s%f", &account, name, &balance); switch (request) { case 1: printf("\nAccounts with zero balances:\n"); while(!feof(cfPtr)) { if (balance ==0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf (cfPtr, "%d%s%f", &account, name, &balance); } break; case 2: printf("\nAccounts with credit balances : \n") ; while (!feof(cfPtr)) { if (balance < 0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } break; case 3: printf("\nAccounts with debit balances: \n"); while (!feof(cfPtr)) { if (balance >0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } break; } rewind(cfPtr); printf("\n? "); scanf("%d", &request);

Page 171: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

171

} printf("End of run.\n"); fclose(cfPtr); } }

Тема 7. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ 7.1 Динамическое распределение памяти

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

Так как память выделяется по мере необходимости и освобождается, когда её использование завершилось, то можно использовать ту же самую память в другой момент времени и для других целей в другой части про-граммы. Динамическое выделение памяти даёт возможность создания дина-мических структур данных: списков, деревьев и др.

Ядром динамического выделения памяти в Си являются функции, объ-явленные в стандартной библиотеке в заголовочном файле stdlib.h – malloc(), calloc(), realloc() и free().

Рассмотрим каждую из названных функций. Функция malloc(). Сиснтаксис функции malloc имеет следующий вид:

void *malloc(unsigned size) Функция malloc выделяет из хипа область памяти размером size байт. В

случае успеха, функция malloc возвращает указатель на начало выделенного блока памяти. Если для выделения блока в хипе не хватает памяти, возвра-щается NULL. Содержимое памяти блока оставляется неизменным. Если размер аргумента равен нулю, malloc возвращает NULL.

Пример использования функции malloc: void main() { int *ptr; ......................... if(!(ptr=(int*)malloc(5*sizeof(int)))) //Необходимо всегда { puts("Not enough memory"); // проверять выделилась getch(); return; // ли память } //ptr указывает на массив из 5 элементов .......................... }

Page 172: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

172

Функция calloc(). Cиснтаксис функции calloc имеет следующий вид:

void *calloc(unsigned num, unsigned size)

Функция calloc выделяет блок памяти и возвращает указатель на пер-вый байт блока. Размер выделяемой памяти равен величине num*size, т.е. функция выделяет память, необходимую для хранения массива из num эле-ментов по size байт каждый. В случае нехватки памяти для удовлетворения запроса функция calloc возвращает NULL. Выделяемая память инициализи-руется нулями.

Пример использования фукнкции calloc:

void main() { int *ptr; ....................... if (!(ptr=(int*)calloc(5,sizeof(int)))) // ptr указывает {puts("Not enough memory"); //на массив из 5 getch(); return; //элементов, заполненный нулями } ....................... }

Функция realloc(). Cиснтаксис функции realloc имеет следующий вид:

void *realloc(void *ptr, unsigned size)

Эта функция изменяет размер динамически выделяемой области памя-ти, на которую указывает *ptr, на size (новый размер). Если указатель не яв-ляется значением, которое ранее было определено функциями malloc, calloc или realloc, то поведение функции не определено. Это же справедливо, если ptr указывает на область памяти, ранее освобождённую функцией free. Зна-чение size является абсолютным, а не относительным, т.е. задаёт новый раз-мер блока, а не приращение старого. Если size больше, чем размер ранее су-ществовавшего блока, то новое, неинициализированное, пространство памя-ти будет выделено в конце блока и предыдущее содержимое пространства сохраняется. Если функция realloc не может выделить память требуемого размера, то возвращаемое значение равно NULL и содержимое пространства, на которое указывает ptr, остаётся нетронутым. Если ptr – не NULL, а значе-ние size равно нулю, то функция realloc действует как функция free.

Из вышесказанного следует сделать вывод о том, что когда бы размер блока памяти ни подвергся изменению под воздействием функции realloc, новое пространство может начинаться с адреса, отличного от исходного, да-же если realloc «усекает» память. Следовательно, если используется функция realloc, возникает необходимость следить за указателями на изменяемое про-странство. Например, если создается связный список и выделяется при по-

Page 173: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

173

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

if(p2 = = realloc(p1,new_size)) p1=p2;

Действуя подобным образом, программисту не придётся заботиться о том, выделялось ли для объекта новое пространство, т.к. p1 обновляется при каждом новом вызове функции, которая указывает на область памяти (воз-можно, новую).

Пример использования функции realloc:

void main() { int *ptr, tmp; ..................... if(!(ptr=(int*)calloc(5,sizeof(int)))) //ptr указывает на { puts("Not enough memory"); // массив из 5 элементов, getch(); return; // заполненный нулями } ....................... if (tmp=realloc(ptr,10*sizeof(int))) ptr=tmp; // ptr указывает на массив else //из 10 элементов { puts("Not enough memory"); getch(); return; } ..................... }

Функция free(). Cиснтаксис функции free имеет следующий вид: void free(void *ptr)

Функция освобождает область памяти, ранее выделенную при помощи функций malloc, calloc или realloc, на которую указывает ptr. Если ptr – NULL, то функция free ничего не выполняет. Если ptr не является указате-лем, проинициализированным ранее одной из функций выделения памяти, то поведение функции не определено. Заметим, что функция free не располагает средствами передачи ошибки, возможно возникающей при её выполнении, равно как возвращаемым значением.

Пример использования функции free:

void main() { int *ptr; ..................... if (!(ptr=(int*)calloc(5,sizeof(int)))) // ptr указывает

Page 174: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

174

{ puts("Not enough memory"); // на массив из 5 getch(); return; //элементов, заполненный нулями } ....................... free(ptr); //ptr указывает на область памяти, ранее //занимаемую массивом ..................... }

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

В языке С++ для выделения и освобождения динамической памяти ис-пользуются следующие два оператора new и delete. Данные операторы явля-ются стандартом языка С++ и не требуют подключение какой-либо библио-теки. Синтаксис операций выделения и освобождения памяти для одной пе-ременной определенного типа выглядит следующим образом:

указатель_на_тип = new тип; delete указатель_на_тип;

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

указатель_на_тип = new тип [размерность]; delete [] указатель_на_тип;

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

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

Page 175: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

175

др.), т.е. структур данных, для которых заранее не определён необходимый объём памяти. В языке Си были разработаны три динамические структуры, объединённые под общим именем списки.

7.2 Связанные списки, очереди, стеки, кольца

Список – это набор элементов (чаще всего структурных переменных) размещаемых в динамической памяти и связанных между собой с использо-ванием указателей на эти элементы. Применяемый способ связывания эле-ментов определяет тип списка.

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

Графическое изображение списков показано на рис. 3.19.

Односвязный линей-ный список

Двусвязный линейный список

Односвязный кольцевой список

Рис. 3.19. Графическое изображение списков

Самыми распространёнными случаями линейного односвязного списка служат стек и очередь.

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

Стек – это список с таким способом связи между элементами, при ко-тором новые элементы добавляются строго в начало списка и извлекаются для обработки также строго из начала списка, т.е. первый занесённый в стек элемент будет обработан последним).

Page 176: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

176

Кольцо – это список, элементы которого образуют замкнутую круго-вую систему, т.е. последний созданный элемент должен содержать указатель на первый элемент.

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

Структуры, ссылающиеся на себя, содержат в качестве элемента ука-затель, который ссылается на структуру того же типа. Например, определе-ние

struct node {

int data; struct node *nextPtr;

};

описывает тип struct node. Структура типа struct node состоит из двух элемен-тов — целого data и указателя nextPtr. Элемент nextPtr указывает на структу-ру типа struct node — структуру того же самого типа, что и только что объяв-ленная, отсюда и термин «структура, ссылающаяся на себя». Элемент nextPtr иногда называют связкой, т.е. nextPtr можно использовать для того, чтобы связать структуру типа struct node с другой структурой того же типа. Струк-туры, ссылающиеся на себя, могут связываться вместе для образования дру-гих структур данных, таких как списки, очереди, стеки и деревья.

Рис. 3.20. Графическая иллюстрация двух, ссылающихся на себя структур,

связанных друг с другом

Графическая иллюстрация двух структур, ссылающиеся на себя, свя-занных друг с другом и образующих список приведена на рис. 3.20. На рис. 3.20 в связывающем элементе второй структуры нарисована, представляю-щая указатель NULL, косая черта, чтобы показать, что этот элемент не ука-зывает на другую структуру. Косая черта используется исключительно для иллюстрации и не имеет никакого отношения к символу обратной дробной черты языка Си. Указатель NULL обычно обозначает конец структуры дан-ных, так же как символ NULL обозначает конец строки.

Page 177: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

177

Связанный список — это линейный набор ссылающихся на себя структур, называемых узлами, и объединенных указателем-связкой, отсюда и название — «связанный» список. Доступ к связанному списку обеспечивает-ся указателем на первый узел списка. Доступ к следующим узлам произво-дится через связывающий указатель, хранящийся в каждом узле. По общему соглашению связывающий указатель в последнем узле списка устанавлива-ется в NULL, отмечая конец списка. Данные хранятся в связанном списке динамически — каждый узел создается по мере необходимости. Узел может содержать данные любого типа, включая другие структуры. Стеки и очереди также принадлежат к линейным структурам данных, и являются специаль-ными вариантами связанных списков. Деревья же являются нелинейными структурами данных.

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

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

Узлы связанных списков, как правило, не располагаются в памяти в ви-де одной сплошной области. Логически связанный список представляется непрерывным. Графическая иллюстрация иллюстрирует связанного списока с несколькими узлами приведена на рис. 3.21.

Рис. 3.21. Графическая иллюстрация связанного списка

с несколькими узлами.

Page 178: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

178

Пример. Программа управляет списком символов. Программа обеспечивает две возможности: 1) вставить символ в список в алфавитном порядке (функция insert) и 2) удалить символ из списка (функция delete).

#include <stdio.h> #include <stdlib.h> struct listNode { /* структура со ссылкой на себя */

char data; struct listNode *nextPtr;

}; typedef struct listNode LISTNODE; typedef LISTNODE *LISTNODEPTR; void insert (LISTNODEPTR *, char); char delete(LISTNODEPTR *, char); int isEmpty(LISTNODEPTR) ; void printList(LISTNODEPTR); void instructions(void); void main () {

LISTNODEPTR startPtr = NULL; int choice; char item; instructions(); /* вывести меню */ printf("? "); scanf("%d", $choice); while (choice !=3) {

switch (choice) {

case 1: printf("Enter a character: "); scanf("\n%c", $item); insert($startPtr, item); printList(startPtr); break;

case 2: if (lisEmpty(startPtr)) {

printf ("Enter character to be deleted: "); scanf ("\n%c", $item); if (delete($startPtr, item)) {

printf("%c deleted.\n", item); printList(startPtr);

} else

printf("%c not found.\n\n",item);

Page 179: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

179

} else

printf("List is empty.\n\n"); break;

default: printf("Invalid choice.\n\n"); instructions (); break;

} printf("? "); scanf("%d", $choice);

} printf("End of run.\n"); return 0;

} /* Распечатка инструкции */ void instructions(void) {

printf("Enter your choice:\n"); printf(" 1 to insert an element into the list.\n"); printf(" 2 to delete an element from the list.\n"); printf(" 3 to end.\n");

} /* Вставка нового значения в упорядоченный список */ void insert(LISTNODEPTR *sPtr, char value) {

LISTNODEPTR newPtr, previousPtr, currentPtr; newPtr = malloc (sizeof (LISTNODE)); if (newPtr != NULL) /* доступна ли память? */ {

newPtr->data = value; newPtr->nextPtr = NULL; previousPtr = NULL; currentPtr = *sPtr; while (currentPtr != NULL && value >currentPtr->data) {

previousPtr = currentPtr; /* перейти ... */ currentPtr = currentPtr->nextPtr; /* ... к следующему */

} if (previousPtr == NULL) {

newPtr->nextPtr = *sPtr; *sPtr = newPtr;

} else {

previousPtr->nextPtr = newPtr; newPtr->nextPtr = currentPtr;

} } else

printf("%c not inserted. No memory available.\n", value);

Page 180: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

180

} /* Удаление элемента списка */ char delete(LISTNODEPTR *sPtr, char value) {

LISTNODEPTR previousPtr, currentPtr, tempPtr; if (value == (*sPtr)->data) {

tempPtr = *sPtr; *sPtr = (*sPtr)->nextPtr; /* отсоединить узел */ free(tempPtr); /* освободить узел */ return value;

} else {

previousPtr = *sPtr; currentPtr = (*sPtr)->nextPtr; while (currentPtr != NULL && currentPtr->data != value) {

previousPtr = currentPtr; /* перейти ... */ currentPtr = currentPtr->nextPtr; /* к следующему */

} if (currentPtr != NULL) {

tempPtr = currentPtr; previousPtr->nextPtr = currentPtr->nextPtr; free (tempPtr); return value;

} }

} /* Возвратить 1, если список пуст, в противном случае - 0 */ int isEmpty(LISTNODEPTR sPtr) {

return sPtr == NULL; } /* Печать списка */ void printList(LISTNODEPTR currentPtr) {

if (currentPtr == NULL) printf("List is empty.\n\n");

else {

printf("The list is:\n"); while (currentPtr != NULL) {

printf("%c-> ", currentPtr->data); currentPtr = currentPtr->nextPtr;

} printf ("NULL\n\n");

} }

Page 181: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

181

В данном примере две основных функции связанных списков — insert и delete. Функция isEmpty называется предикатной функцией — она никак не меняет список, а всего лишь определяет, является ли список пустым (т.е. ука-затель на первый узел списка равен NULL). Если список пуст, возвращается значение 1, в противном случае 0. Функция printList распечатывает список.

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

1. Вызвать функцию malloc, и с ее помощью создать узел, присвоив newPtr адрес выделенного блока памяти, а также присвоить newPtr->data символ, который необходимо вставить, a newPtr->nextPtr — значение NULL.

2. Инициализировать previousPtr как NULL, и currentPtr как *sPtr (ука-затель на начало списка). Указатели previousPtr и currentPtr используются для хранения положений узла, предшествующего точке вставки и узла после точ-ки вставки.

3. Если currentPtr не NULL, и вставляемое значение больше, чем cur-rentPtr->data, значение currentPtr присваивается previousPtr, a currentPtr пере-мещается в следующий узел списка. Так определяется точка в списке, в кото-рую будет вставлено значение.

4. Если previousPtr равен NULL, то новый узел вставляется как первый узел списка, присвоив newPtr->nextPtr значение *sPtr (предыдущий первый узел — указателю-связке нового узла), и присвоив *sPtr значение newPtr (*sPtr теперь указывает на новый узел). Если previousPtr не NULL, то новый узел устанавливается на свое место. Для этого значение newPtr присваивается previousPtr->nextPtr (указатель нового узла — связке предыдущего), a newPtr->nextPtr присваивается значение currentPtr (указатель текущего узла — связ-ке нового).

Графическая иллюстрация вставки узла, содержащего символ 'c', в упо-рядоченный список показана на рис. 3.22.

Page 182: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

182

а)

б)

Рис. 3.22. Графическая иллюстрация вставки узла на нужное место в списке

Упорядоченный список и новый узел перед вставкой показаны на рис. 3.22, а. Результат вставки нового узла – на рис.3.22, б, где модифицирован-ные указатели изабражены пунктиром.

Функция delete получает адрес указателя на начало списка и символ, который нужно удалить. Удаление символа из списка происходит следую-щим образом:

1. Если выясняется, что символ, который требуется удалить, находится в первом узле списка, то tempPtr присваивается значение *sPtr (tempPtr будет использован, чтобы освободить ненужную более память), *sPtr присваивает-ся значение (*sPtr)->nexPtr (*sPtr теперь указывает на второй узел списка), блок памяти, на которую указывает tempPtr, освобождается, и функция воз-вращает символ, который был удален.

2. В противном случае происходит инициализация previousPtr значени-ем *sPtr и currentPtr значением (*sPtr)->nextPtr.

3. Если currentPtr не NULL и значение, которое необходимо исклю-чить, не равно currentPtr->data, то previousPtr присваивается значение cur-

Page 183: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

183

rentPtr, a currentPtr — значение currentPtr->nexPtr. Таким образом определя-ется местоположение символа, который требуется удалить, если он содер-жится в списке.

4. Если currentPtr не NULL, то tempPtr присваивается значение cur-rentPtr, previousPtr->nextPtr — значение currentPtr->nextPtr, узел, на который указывает tempPtr, освобождается, и возвращается символ, который был уда-лен из списка. Если currentPtr равен NULL, возвращается NULL (символ '\0') показывающий, что символ, который предлагается удалить, в списке не най-ден.

Графическая иллюстрация удаления узла из связанного списка приве-дена на рис. 3.23. На рис. 3.23,а показан связанный список после выполнения последней операции вставки, а на рис. 3.23, б показана модификация связы-вающего элемента previousPtr и присваивание tempPtr значения currentPtr. Указатель tempPtr используется для освобождения блока памяти, выделенно-го для хранения 'c'.

а)

a b dc e

*sPtr previoustPtr currentPtr

б)

Рис. 3.23. Графическая иллюстрация исключения узла из списка

Функция printList принимает в качестве аргумента указатель на начало списка и обращается к указателю currentPtr. Сначала функция определяет, не является ли список пустым. Если да, то printList выводит сообщение "The list is empty." и заканчивает работу. В противном случае она выводит данные списка. До тех пор, пока currentPtr не NULL, функция выводит на печать cur-rentPtr->data, a currentPtr присваивает значение currentPtr->nexPtr. Если свя-

Page 184: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

184

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

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

Графическое представление стека с несколькими узлами показано на рис. 3.24. Следует отметить, что стеки и связанные списки представляются идентично. Разница между стеком и связанными списками в том, что вставку и удаление в связанных списках можно выполнять в любом месте, а в стеке только сверху.

Рис. 3.24. Графическая иллюстрация стека

Примеры. Программа работает с простым стеком целых чисел. Про-грамма выполняет три действия на выбор: 1) помещает значение в стек (функция push), 2) извлекает значение из стека (функция pop), и 3) завершает работу.

#include<stdlib.h> #include<malloc.h> #include<stdio.h> struct stackNode { int data; struct stackNode *nextPrt; }; typedef struct stackNode STACKNODE; typedef STACKNODE * STACKNODEPTR; void push(STACKNODEPTR *, int); int pop(STACKNODEPTR *); int isEmpty(STACKNODEPTR); void printStack(STACKNODEPTR); void instruc(void); void main() {

Page 185: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

185

STACKNODEPTR stackPtr = NULL; int choice, value; instruc(); printf("? "); scanf("%d", &choice); while (choice !=3) { switch (choice) { case 1: printf("Enter an integer >> "); scanf("%d", &value); push (&stackPtr, value); printStack(stackPtr); break; case 2: if (!isEmpty(stackPtr)) printf("the popped value is %d \n", pop(&stackPtr)); printStack(stackPtr); break; default: printf("Error enter\n"); instruc(); break; } printf("? "); scanf("%d", &choice); } printf("End \n"); return 0; } void instruc(void) { printf("1 - dobavit\n"); printf("2 - delete\n"); printf("3 - exit\n"); } void push(STACKNODEPTR *topPtr, int info) { STACKNODEPTR newPtr; newPtr = new STACKNODE; if (newPtr != NULL) { newPtr ->data = info; newPtr ->nextPrt = * topPtr; *topPtr = newPtr; } else printf("%d Error not memori\n", info); }

Page 186: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

186

int pop(STACKNODEPTR *topPtr) { STACKNODEPTR tempPtr; int popValue; tempPtr = *topPtr; popValue = (*topPtr) ->data; *topPtr = (*topPtr) ->nextPrt; free(tempPtr); return popValue; } void printStack(STACKNODEPTR currentPtr) { if (currentPtr == NULL) printf("Error not stack\n\n"); else { printf("Stack is :>> \n"); while (currentPtr != NULL ) { printf("%d -> ", currentPtr ->data); currentPtr = currentPtr ->nextPrt; } printf("\n"); } } int isEmpty (STACKNODEPTR topPtr) { return topPtr == NULL; }

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

Программа работает с простым стеком целых чисел. Программа вы-полняет три действия на выбор: 1) помещает значение в стек (функция push), 2) изымает значение из стека (функция pop), и 3) завершает работу.

Функция push помещает новый узел на вершину стека. В выполнении функции можно выделить три этапа:

1. Создание нового узла посредством вызова malloc, при этом указате-лю newPtr присваивается адрес блока выделенной памяти; переменной newPtr -> data присваивается значение, которое необходимо поместить в стек; и указателю newPtr->nextPtr присваивается NULL.

Page 187: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

187

2. Указателю newPtr->nextPtr присваивается *topPtr (указатель на вер-шину стека); связывающий элемент newPtr теперь указывает на узел, кото-рый был верхним до этого.

3. *topPtr присваивается значение newPtr; *topPtr теперь указывает на новую вершину стека. Операции, включающие в себя *topPtr, меняют значе-ние stackPtr в main.

а)

б)

Рис. 3.25. Графическая иллюстрация выполнения функции push

Наглядное представление о том, как происходит выполнение функции push показано на рис. 3.25. На рис. 3.25, а изображен стек и новый узел перед выполнением функции push. Пунктирные линии на рис. 3.25, б иллюстриру-ют шаги 2 и 3 выполнения функции push, в результате которых узел, содер-жащий 12, становится новой вершиной стека.

Функция pop удаляет верхний узел стека. Отметим, что перед тем как вызвать функцию pop, функция main определяет, не пуст ли стек. В выполне-нии функции pop можно выделить пять основных этапов:

1. Указателю tempPtr присваивается *topPtr (tempPtr будет использован для освобождения ненужной памяти).

2. Переменной popValue присваивается значение (*topPtr)->data (сохра-няется значение, находившееся в верхнем узле).

3. *topPtr присваивается (*topPtr)->nextPtr (*topPtr присваивается адрес нового верхнего узла).

4. Освобождается память, на которую указывает tempPtr. 5. Вызывающей функции возвращается значение popValue (в примере

программы это функция — main). Выполнение функции pop проиллюстрировано на рис. 3.26. На рис.

3.26, а показано состояния стека после предыдущей операции push. На рис. 3.26, б выделены указатели tempPtr, указывающий на первый узел стека, и

Page 188: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

188

*topPtr, указывающий на второй узел. Для освобождения указанной tempPtr памяти вызывается функция free.

а)

б)

Рис. 3.26. Графическая иллюстрация выполнения функции pop

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

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

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

Другой распространенной структурой данных является очередь. Оче-редь сходна с людьми у кассы в магазине: тот, кто ближе всех к кассе, об-служивается в первую очередь, другие покупатели пристраиваются в конец и ждут, пока их обслужат. В очереди узлы удаляются только с головы, а добав-ляются только в хвост очереди. По этой причине очереди часто называют структурами данных типа первым пришел — первым ушел (FIFO). Операции постановки в очередь и удаления из очереди носят названия enqueue (поста-вить в очередь) и dequeue (исключить из очереди).

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

Page 189: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

189

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

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

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

Рис. 3.27. Графическое представление очереди

Примеры. Программа показывает пример работы с очередью. Програм-ма предлагает выполнить следующие действия на выбор: поставить узел в оче-редь (функция enqueue), удалить узел из очереди (функция dequeue), и выйти из программы.

#include <stdio.h> #include <stdlib.h> struct queueNode { char data; struct queueNode *nextPtr; }; typedef struct queueNode QUEUENODE; typedef QUEUENODE *QUEUENODEPTR; void printQueue(QUEUENODEPTR); int isEmpty(QUEUENODEPTR); char dequeue(QUEUENODEPTR *, QUEUENODEPTR *); void enqueue (QUEUENODEPTR *, QUEUENODEPTR *, char); void instructions (void);

Page 190: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

190

void main () { QUEUENODEPTR headPtr = NULL, tailPtr = NULL; int choice; char item; instructions (); printf ("? "); scanf("%d", &choice); while (choice !=3) { switch(choice) { case 1 : printf("Enter a character: "); scanf("\n%c", &item); enqueue(&headPtr, &tailPtr, item); printQueue(headPtr); break; case 2 : if (! isEmpty(headPtr)) { item = dequeue(&headPtr, &tailPtr); printf("%c has been dequeued.\n", item); } printQueue(headPtr); break; default: printf ("Invalid choice.\n\n"); instructions(); break; } printf ("?"); scanf("%d", &choice); } printf("End of run.\n"); return 0; } void instructions(void) { printf ("Enter your choice:\n"); printf (" 1 to add an item to the queue\n"); printf (" 2 to remove an item from the queue\n"); printf (" 3 to end\n"); } void enqueue(QUEUENODEPTR *headPtr, QUEUENODEPTR *tailPtr, char value) { QUEUENODEPTR newPtr; newPtr =new QUEUENODE; if (newPtr != NULL) { newPtr->data = value; newPtr->nextPtr = NULL; if (isEmpty(*headPtr)) *headPtr = newPtr;

Page 191: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

191

else (*tailPtr)->nextPtr = newPtr; *tailPtr = newPtr; } else printf("%c not inserted. No memory available.\n", value); } char dequeue(QUEUENODEPTR *headPtr, QUEUENODEPTR *tailPtr) { char value; QUEUENODEPTR tempPtr; value = (*headPtr)->data; tempPtr = *headPtr; *headPtr = (*headPtr)->nextPtr; if (*headPtr == NULL) *tailPtr = NULL; free(tempPtr); return value; } int isEmpty(QUEUENODEPTR headPtr) { return headPtr == NULL; } void printQueue(QUEUENODEPTR currentPtr) { if (currentPtr == NULL) printf("Queue is empty.\n\n"); else { printf("The queue is ;\n"); while (currentPtr != NULL) { printf("%c --> ", currentPtr->data); currentPtr = currentPtr->nextPtr; } printf("NULL\n\n"); } }

Функция enqueue получает от функции main три аргумента: адрес ука-зателя на голову очереди, адрес указателя на хвост очереди и значение, кото-рое необходимо поставить в очередь. Выполнение функции состоит из трех шагов:

1. Создание нового узла: вызвать функцию malloc, присвоить адрес вы-деленного блока памяти newPtr, присвоить newPtr->data значение, которое необходимо поставить в очередь, a newPtr->nextPtr присвоить NULL.

2. Если очередь пуста, то присвоить *headPtr указатель newPtr; в про-

Page 192: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

192

тивном случае присвоить этот указатель (*tailPtr)->nextPtr. 3. Присвоить *tailPtr указатель newPtr. Выполнение функции enqueue иллюстрирует рис. 3.28. Очередь и но-

вый узел перед выполнением операции добавления элемента в очередь пока-заны рис. 3.28. Пунктирные линии в части на рис. 3.28, б показывают шаги 2 и 3 функции enqueue, которые позволяют добавить новый узел в конец не-пустой очереди.

а)

б)

Рис. 3.28. Графическая иллюстрация выполнения функции enqueue

Функция dequeue получает в качестве аргументов адрес указателя на голову очереди и адрес указателя хвоста и удаляет первый узел очереди. Вы-полнение функции dequeue складывается из шести шагов:

1. Переменной value присвоить значение (*headPtr)->data (сохранить данные).

2. Присвоить указателю tempPtr значение *headPtr (tempPtr использует-ся для освобождения ненужной памяти).

3. Присвоить указателю *headPtr значение (*headPtr)->nextPtr. (*headPtr теперь указывает на новый первый узел очереди).

4. Если указатель *headPtr указывает на NULL, то установить указа-тель *tailPtr также указывающим на NULL.

5. Освободить блок памяти, на который указывает tempPtr. 6. Передать значение value вызывающей функции (в примере програм-

мы функция dequeue вызывалась из функции main). Графическая иллюстрация выполнения функции dequeue приведены на

рис. 3.29. Очередь после выполнения операции enqueue показана на рис. 3.29, а, а на рис. 3.29, б изображен указатель tempPtr, указывающий на исключен-ный узел, и указатель headPtr, указывающий на новый первый узел очереди.

Page 193: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

193

Для возвращения системе блока памяти, на который указывает tempPtr, вы-зывается функция free.

а)

r a nd

*haedPtr *tailPtr

б)

r a nd

*haedPtr *tailPtr

Рис 3.29. Графическая иллюстрация выполнения функции dequeue

7.3 Бинарные деревья

Связанные списки, стеки и очереди — все это примеры линейных структур данных. Дерево же — нелинейная, двумерная структура данных с особыми свойствами. Узлы дерева содержат две или более связей. В этом разделе рассматриваются только двоичные деревья (рис. 3.30) — деревья, уз-лы которых содержат две связки (при этом как одна, так и обе связки могут быть NULL).

Рис. 3.30. Графическое представление двоичного дерева

Первый узел дерева называется корневым. Каждая связь корневого узла ссылается на потомка. Левый потомок — первый узел левого поддерева, а правый потомок — первый узел правого поддерева. Потомки одного узла на-зываются узлами-сиблингами. Узел, не имеющий потомков, называется лис-

Page 194: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

194

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

Рассмотрим специальное двоичное дерево, называемое двоичным дере-вом поиска. Двоичное дерево поиска (с неповторяющимися значениями в уз-лах) устроено так, что значения в любом левом поддереве меньше, чем зна-чение в родительском узле, а значения в любом правом поддереве больше, чем значение в родительском узле. На рис. 3.31 изображено двоичное дерево поиска с 12 значениями. Форма двоичного дерева поиска для одного и того же набора данных может быть разной, в зависимости от порядка, в котором значения вставлялись в дерево.

Рис. 3.31. Двоичное дерево поиска

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

/* Создание двоичного дерева и его обход с порядковой, предваритель-ной и отложенной выборкой */

#include <stdio.h> #include <stdlib.h> #include <time.h> struct treeNode {

struct treeNode *leftPtr; int data; struct treeNode *rightPtr;

}; typedef struct treeNode TREENODE; typedef TREENODE *TREENODEPTR; void insertNode(TREENODEPTR *, int);

Page 195: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

195

void inOrder(TREENODEPTR); void preOrder(TREENODEPTR); void postOrder(TREENODEPTR); void main () {

int i, item; TREENODEPTR rootPtr = NULL; srand(time(NULL)); /* попытаться разместить в дереве 10 случайных чисел

в диапазоне от 0 до 14 */ printf("The numbers being placed in the tree are:\n"); for (i = 1; i <= 10; i ++.) {

item = rand() % 15; printf("%3d", item); insertNode(&rootPtr, item);

} /* обойти дерево с предварительной выборкой */ printf("\n\nThe preOrder traversal is:\n"); preOrder(rootPtr); /* обойти дерево с порядковой выборкой */ printf("\n\nThe inOrder traversal is:\n"); inOrder(rootPtr); /* обойти дерево с отложенной выборкой */ printf("\n\nThe postOrder traversal is:\n"); postOrder(rootPtr); return 0;

} void insertNode(TREENODEPTR *treePtr, int value) {

if (*treePtr == NULL) /* *treePtr равен NULL */ {

*treePtr = malloc(sizeof(TREENODE)); if (*treePtr != NULL) {

(*treePtr)->data = value; (*treePtr)->leftPtr = NULL; (*treePtr)->rightPtr = NULL;

} else

printf("%d not inserted. No memory available . \n", value); } else

if (value < (*treePtr)->data) insertNode(&((*treePtr)->leftPtr), value);

Page 196: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

196

else if (value > (*treePtr)->data)

insertNode(&((*treePtr)->rightPtr), value); else

printf("dup"); } void inOrder(TREENODEPTR treePtr) {

if (treePtr != NULL) {

inOrder(treePtr->leftPtr); printf("%3d", treePtr->data); inOrder(treePtr->rightPtr);

} } void preOrder(TREENODEPTR treePtr) {

if (treePtr != NULL) {

printf("%3d", treePtr->data); preOrder(treePtr->leftPtr); preOrder(treePtr->rightPtr);

} } void postOrder(TREENODEPTR treePtr) {

if (treePtr != NULL) {

postOrder(treePtr->leftPtr); postOrder(treePtr->rightPtr); printf("%3d", treePtr->data);

} }

Функции, использованные в программе для создания двоичного дерева поиска и его обхода, являются рекурсивными. Функции insertNode передают-ся два аргумента: адрес дерева и целое значение, которое необходимо сохра-нить в дереве. В двоичном дереве поиска узел можно вставлять только в ка-честве листа. Чтобы вставить узел в двоичное дерево поиска, необходимо выполнить следующие операции:

1. Если указатель *treePtr равен NULL, то нужно создать новый узел. Вызвать функцию malloc, присвоить выделенную память *treePtr, присвоить (*treePtr)->data целое значение, которое необходимо сохранить, присвоить (*treePtr)->leftPtr и (*treePtr)->rightPtr значение NULL, и вернуть управление вызывающей функции (либо main, либо предыдущему вызову insertNode).

Page 197: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

197

2. Если значение *treePtr не NULL и значение, которое необходимо вставить меньше, чем (*treePtr)->data, то функция insertNode вызывается с адресом (*treePtr)->leftPtr. В противном случае функция insertNode вызывает-ся с адресом (*treePtr)->rightPtr. Рекурсивные шаги продолжаются до тех пор, пока не будет обнаружен указатель NULL, после чего выполняется пункт 1, т.е. осуществляется вставка нового узла.

Функции inOrder, preOrder и postOrder получают дерево (т.е. указатель на корневой узел) и проходят по нему.

В функции inOrder (порядковая выборка) выполняются следующие ша-ги:

1) Обойти с помощью функции inOrder левое поддерево. 2) Обработать значение в узле. 3) Обойти с помощью функции inOrder правое поддерево. Значение в узле не обрабатывается до тех пор, пока не будут обработа-

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

6 13 17 27 33 42 48

Рис. 3.32. Пример прохода двоичному дерева поиска

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

В функции preOrder (предварительная выборка) выполняются следую-щие шаги:

1) Обработать значение в узле. 2) Обойти с помощью функции preOrder левое поддерево. 3) Обойти с помощью функции preOrder правое поддерево. Значение в каждом узле обрабатывается при остановке в этом узле. По-

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

Page 198: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

198

preOrder по дереву, изображенному на рис. 3.32, выглядит следующим обра-зом:

27 13 6 17 42 33 48

В функции postOrder (отложенная выборка) выполняются следующие шаги:

1) Обойти с помощью функции postOrder левое поддерево. 2) Обойти с помощью функции postOrder правое поддерево. 3) Обработать значение в узле. Значение в каждом узле не распечатывается до тех пор, пока не будут

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

6 17 13 33 48 42 27

Двоичное дерево поиска упрощает удаление повторяющихся значений. Когда дерево создано, попытка вставить в него повторяющееся значение бу-дет обнаружена, поскольку это значение будет следовать тем же самым ре-шениям «поверни налево» или «поверни направо» при каждом сравнении, как и значение, введенное первым. Таким образом, повторяющееся значение будет в конце концов сравниваться с узлом, содержащим первое значение. И в этом месте его можно просто отбросить.

Также очень быстро можно провести в двоичном дереве поиск значе-ния, совпадающего с заданным. Если дерево упаковано плотно, то каждый уровень содержит примерно в два раза больше элементов, чем предыдущий. Поэтому двоичное дерево поиска с n элементами должно содержать макси-мум log2n уровней и, таким образом, необходимо будет сделать максимум log2n сравнений, чтобы найти нужное значение, или же определить, что тако-го значения нет. Это означает, что когда, например, производится поиск в 1000-элемнтном двоичном дереве поиска (плотно упакованном), то необхо-димо сделать не более десяти сравнений, так как 210> 1000. Для поиска же в двоичном дереве (плотно упакованном), содержащем 1000000 элементов, по-требуется не больше двадцати сравнений, поскольку 220 > 1000000.

Page 199: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

199

Тема 8 ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ ЯЗЫКА С/С++

8.1 Классы памяти

Каждая переменная и функция в программе на языке С/C++ принадле-жит к какому-либо классу памяти. Класс памяти переменной определяет время ее существования (время жизни) и область видимости (область опре-деления), связанные с понятием блока программы (сколько времени и где существует).

Блоком программы называется часть программы, заключенная в фи-гурные скобки.

Существует два типа блоков: - составной оператор; - определение функции, состоящее из: заголовка и тела функции - {...}. Различают четыре класса памяти: auto, register, extern и static. Большинство переменных в программе на языке Си имеют класс памя-

ти auto. По умолчанию принято, что для любой переменной объявленной внутри функции (локальная переменная) или блока, для которой класс памя-ти явно не указан, подразумевается как класс auto.

Автоматическая переменная (auto) - это всегда локальная переменная, но не наоборот, т.е. она видима (существует) от точки ее объявления и до конца блока, в котором она объявлена, кроме вложенных блоков, в которых эта переменная определяется повторно.

Память для нее выделяется при входе в блок (автоматически) и осво-бождается (автоматически) при выходе из блока. При повторном входе в блок этой переменной может быть выделено другое место в памяти.

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

Регистровая переменная (register) - это автоматическая переменная. Ключевое слово register - лишь указывает компилятору, что такую перемен-

Page 200: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

200

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

Внешняя переменная (extern) имеет область существования от точки ее объявления и до конца файла, где она объявлена. Если внутри блока опреде-лена автоматическая переменная с таким же именем (т.е. локальная перемен-ная), то внешняя переменная здесь недоступна. Предполагается, что память под переменную, объявленную с классом памяти extern, выделяется в другом модуле в месте её определения, а в данном модуле только используется ее значение.

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

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

Любой объект данных может быть явно отнесен к классу памяти static. При этом объект может оставаться локальным. Другими словами, любая гло-бальная переменная имеет класс памяти static, но не обязательно любая ста-тическая переменная - это глобальная. По умолчанию все статические объ-екты инициализируются нулевыми значениями.

Функция, объявленная как static, "видима" в пределах файла, в котором она объявлена. Любая функция в том же файле может вызвать функцию с классом static, а функции из других файлов - нет. Функция с классом памяти static и с тем же именем может быть объявлена в другом файле, и это не при-ведет к конфликту. По умолчанию функция имеет класс памяти extern.

Page 201: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

201

Пример. Программа, иллюстрирующая работу с классами памяти.

int k, x[20]; /* Глобальные переменные, класс памяти – static, видимы по умолчанию во всем файле. */ void fun1() // Список параметров отсутствует. { extern long l[10]; /* Объявление массива, определение расположено ниже по тексту P1.CPP*/ auto int s; long r; // Локальные переменные. static int j; //Статическая переменная, видима только в fun1, инициализируется нулем */ j++; s+= x[i++] r+= l[n]; } void fun2(void) // Список параметров пустой. { static int *ptr =&x[0]; // ptr = x; extern int imas[]; // Объявление массива, определён в другом файле. static int j=1; int res=0; j*=2; k=1; { static *pj = &j; // Сейчас *pj=2. static j=0; // Ниже в этом блоке предыдущее j не видимо. j++; } res += x[i]*2; cout<< "j*2=" << j <<endl; // Видимо предыдущее j. res=0; res += imas[i]; } void main () { void fun4(void); // Прототип функции. extern long l[]; /* Объявить массив можно и так, определение его расположено ниже. */ for(int i=0; i<5;i++) cin>> l[i]; // Ввод массива. fun4(); // Вызов функции из другого файла. } long l[20]; // Определение массива, класс памяти static по умолчанию. void fun3() // Нет списка параметров. { int s; long r; k=0; for(int i=0, s=0,r=0; i<7;i++)

Page 202: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

202

{ s += x[i]; r += l[i]; // Здесь массив l уже известен. } cout<< "s=" << s << " r= " << r; } /* Файл Р2.СРР */ int k; // Объявление видимо во всем файле Р2.СРР extern long b[]; // Объявление видимо во всем файле Р2.СРР extern long l[20]; // Объявление видимо во всем файле Р2.СРР void fun4() { extern imas[]; // По умолчанию тип int auto int i=0, j; long z, r=0; // Локальные переменные for(; i<15; i++) cin>>imas[i]; r+=l[j]; z=+b[i]; } int imas[15]; // Определение массива void fun5() { int j; long r=1; // Массив l[20] не видим. r=r*b[j]; /* Массив b видим, т.к. выше было объявление: extern long b[];*/ } static long b[20];

Таким образом, глобальные переменные видимы от точки определения (объявления) и до конца данного файла.

Разрешается определить несколько статических переменных (j), и они существуют до конца выполнения программы, но каждая видима только в своём блоке определения. Определения

static int j=0; static int j;

эквивалентны. Спецификаторы static и extern определяют объекты с глобальным вре-

менем жизни. Спецификатор extern применяется для того, чтобы сделать ви-димым в блоке, определение, расположенное по тексту ниже или в другом файле. Объявлений переменной с классом extern может быть несколько (ex-tern long l[]; ,extem imas[]; ), а определение (выделение памяти), должно быть только одно.

Глобальные переменные k имеют класс памяти static, но каждая ви-дима только в своём файле.

Page 203: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

203

Для объектов с классом памяти extern компилятор создаёт в объектном файле таблицу внешних ссылок, которая на этапе сборки используется редак-тором связей (компановщиком) для установления связей между модулями.

Пример. Программа с использованием статических переменных (ло-кальных):

#include <stdio.h> void Fun(int); /* прототип */ void main(void) /* головная */ { int k; for (k=9;k>=5;k-=2) Fun(k); } void Fun(int с) { int j=1; static int st=1; }

Здесь значение статической переменной st после выхода из функции Fun не теряется, а для j теряется, т.к. j - автоматическая переменная, ей при каждом вхождении в Fun присваивается значение равное единице.

8.2 Методы и алгоритмы оптимизации

Любой программист сталкивался с необходимостью рассортировать данные, то есть упорядочить их определённым образом. Сортировка приме-няется во многих, если не во всех, областях программистской деятельности, будь то базы данных или математические программы. Цель сортировки об-легчить в дальнейшем поиск требуемых данных. Многие программисты пользуются специально предназначенными для сортировки библиотечными функциями (например, qsort() в Турбо Си), особо не задумываясь над тем, а как же на самом деле работают эти функции. В действительности существует много методов сортировки данных. Причём для разных типов данных иногда целесообразно применять разные методы сортировки.

Практически каждый алгоритм сортировки можно разбить на три час-ти:

- сравнение двух элементов, определяющее упорядоченность этой па-ры;

- перестановку, меняющую местами неупорядоченную пару элементов; - сортирующий алгоритм, определяющий выбор элементов для сравне-

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

сортировка данных в файлах называется внешней. Ниже будут рассматри-ваться методы сортировки данных в оперативной памяти.

Page 204: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

204

Метод пузырька или сортировка простым обменом. Этот метод на-зывают также обменной сортировкой выбором. Нетрудно догадаться, что идея этого метода отражена в его названии. Самые "лёгкие" элементы масси-ва всплывают "наверх", самые "тяжёлые" - тонут. Алгоритмически это мож-но организовать следующим образом. Мы будем просматривать весь массив "сверху вниз" и менять стоящие рядом элементы в том случае, если "нижний" элемент меньше, чем "верхний". Таким образом, мы вытолкнем вниз самый "тяжёлый" элемент всего массива. Теперь повторим операцию для остав-шихся n-1 элементов, то есть для тех, которые лежат "выше" найденного.

/* Функция сортировки простым обменом (методом пузырька) */ void sort_bubl(int *x, int n) { int i,j,buf; /* Проход массива 'вниз', начиная с нулевого элемента */ for(i=0;i<n;i++) /*Проход массива 'вниз', начиная с нулевого и до n-i-го элемента */ for(j=0;j<n-i-1;j++) /* Сравнение двух соседних элементов и их обмен */ if(*(x+j)>*(x+j+1)) {buf=*(x+j); *(x+j)= *(x+j+1); *(x+j+1)=buf;} }

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

Сортировка выбором наименьшего элемента. Реализуем этот метод следующим образом: последовательно пройдем весь массив, сравнивая i-ый элемент со всеми, находящимися после него, и, найдя наименьший, переста-вим его на i-ое место. Таким образом, после перебора всех элементов, полу-чим отсортированный массив.

/* Функция сортировки выбором наименьшего элемента */ void sort_min (int *x, int n) { int i,j,k,buf; /*Проход массива, начиная с нулевого элемента до предпоследнего */ for(i=0;i<n-1;i++) { /* Проход массива, начиная (i+1)-го до последнего элемента */ for(k=i, j=i+1; j<n; j++) // Поиск наименьшего k-го элемента if(*(x+j)< *(x+k)) k=j; // Перемещение наименьшего элемента вверх

Page 205: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

205

buf=*(x+k); (x+k)=*(x+i); *(x+i)=buf; } }

Данные методы сортировки являются неэффективными и редко приме-няются в «серьезных» программах, но они полезны для иллюстрации прин-ципов сортирования данных и получения практических навыков работы с циклами. В программах, где требуется высокая производительность работы сортировок, применяются другие методы такие как метод Шелла, метод Хо-ра.

Метод Шелла. Метод был предложен автором Donald Lewis Shell в 1959г. Основная идея алгоритма состоит в том, что на начальном этапе реа-лизуется сравнивание и, если требуется, перемещение далеко отстоящих друг от друга элементов. Интервал между сравниваемыми элементами (gap) по-степенно уменьшается до единицы, что приводит к перестановке соседних элементов на последних стадиях сортировки (если это необходимо).

Реализуем метод Шелла следующим образом. Начальный шаг сорти-ровки примем равным n/2, т.е. 1/2 от общей длины массива, и после каждого прохода будем уменьшать его в два раза. Каждый этап сортировки включает в себя проход всего массива и сравнение отстоящих на gap элементов. Про-ход с тем же шагом повторяется, если элементы переставлялись. Следует от-метить, что после каждого этапа сортировки отстоящие на gap элементы яв-ляются отсортироваными.

Пример. Рассортировать массив чисел:

41, 53, 11, 37, 79, 19, 7, 61.

Процесс сортировки выглядит следующим образом:

41 53 11 37 79 19 7 61 Исходный массив 41 19 11 37 79 53 7 61 (0,4), (1,5)

1-ый цикл 41 19 7 37 79 53 11 61 (2,6), (3,7) 7 19 41 37 11 53 79 61 (0,2),(1,3),(2,4),(3,5),(4,6),(5,7)

2-ой цикл 7 19 11 37 41 53 79 61 (0,2),(1,3),(2,4),(3,5),(4,6),(5,7) 7 11 19 37 41 53 61 79 сравнивались соседние (3-ий цикл).

В строке после массива в круглых скобках указаны индексы сравни-ваемых элементов и указан номер внешнего цикла.

Функция реализации сортировки методом Шелла имеет вид:

/* Функция сортировки методом Шелла */ void sort_sh(int *x, int n) { int i, j; // две переменные цикла int buffer; // используется при перестановке

Page 206: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

206

int gap; // шаг сортировки int sorted; // флаг окончания этапа сортировки for(gap = n/2; gap > 0; gap /= 2) // начало сортировки do { sorted = 0; for(i = 0, j = gap; j < n; i++, j++) if(*(x+i) > *(x+j)) // сравниваем отстоящие на gap элементы { // переставляем элементы buff = *(x+j); *(x+j) = *(x+i); *(x+i) = buff; sorted = 1; // была перестановка , сортировка не завершена } } while (sorted); // окончание этапа сортировки } void main() { int x[]={2,5,9,1,4,3,8,7,6,0}; sort_sh(x,10); }

Метод Хоара. Метод Хоара (Charles Antony Richard Hoare, 1962 г.), на-зываемый также методом быстрой сортировки (QuickSort) основывается на следующем: находится такой элемент, который разбивает множество на два подмножества так, что в одном все элементы больше, а в другом - меньше элемента делящего множество на два подмножества. Каждое из подмножеств также разделяется на два, по такому же принципу. Конечным итогом такого разделения станет рассортированное множество. Рассмотрим один из вариан-тов реализации сортировки Хоара.

В самой процедуре сортировки сначала выберем средний элемент. По-том, используя переменные i и j, пройдемся по массиву, отыскивая в левой части элементы больше среднего, а в правой - меньше среднего. Два найден-ных элемента переставим местами. Будем действовать так, пока i не станет больше j. Тогда мы получим два подмножества, ограниченные с краев индек-сами l и r, а в середине - j и i. Если эти подмножества существуют (то есть i<r и j>l), то выполняем их сортировку.

Например, необходимо рассортировать массив: 13,3,23,19,7,53,29,17. Переставляемые элементы будем подчёркивать, средний - выделим жирным шрифтом, а элемент попавший на своё место и не участвующий в последую-щих сравнениях - курсивом. Индекс i будет задавать номер элемента слева от среднего, а j справа от среднего. Тогда получим:

13 3 23 19 7 53 29 17 13 3 17 19 7 53 29 23 13 3 17 7 19 53 29 23 — делим на два подмножества

Page 207: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

207

13 3 17 7 19 53 29 23 Выделяем подмножество 3 13 17 7 19 23 29 53 13 17 7 Выделяем подмножество 13 7 17 Результат: 3 7 13 17 19 23 29 53

Фрагмент программа реализации сортировки методом Хоара имеет вид:

void main() { void Hoare(int *, int , int ); // прототип функции int x[10] = {7,2,4,0,3,1,9,6,8,5}; // исходный массив int n=10; // ...операции... Hoare(x,0,n-1); // вызываем рекурсивный алгоритм

/* массив рассортирован */ // ...операции... } /* процедура сортировки */ void Hoare(int *x, int l, int r) // передаем левую/правую границы { int i, j; // две «передвижные» границы int buffer; // используется при перестановке int sr = x[(l+r)/2]; // средний элемент i = 1; j = r; // устанавливаем начальные значения do { while(x[i] < sr) i++; // ищем слева элемент больше среднего while(x[j] > sr) j--; // ищем справа элемент меньше среднего if(i <= j) // если левая граница не прошла за правую { // перестановка элементов buff = x[i]; x[i] = x[j]; x[j] = buff; i++; j--; // переходим к следующим элементам } } while(i <= j); // пока границы не сошлись // массив разбит на два подмножества if(i < r) // если есть что-нибудь справа Hoare(x,i,r); // сортируем правую часть if(j>l) // если есть что-нибудь слева Hoare(x,l,j); // сортируем левую часть }

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

Сортировка с помощью бинарного дерева. Если составить бинарное дерево из элементов неупорядоченного массива, то в общем случае дерево

Page 208: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

208

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

Если обходить бинарное дерево выбирая узлы слева направо, то мы по-лучим упорядоченное в порядке возрастания множество. На этом и основана идея сортировки деревом.

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

Page 209: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

209

3 ЛАБОРАТОРНЫЙ ПРАКТИКУМ

Лабораторная работа №1.

СЛОВЕСНОЕ ОПИСАНИЕ АЛГОРИТМА

1. Алгоритм. Псевдокод. Решение любой задачи, связанной с вы-числениями, включает в себя выполнение ряда действий в определенном порядке. Процедура решения задачи в виде

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

программистам разрабатывать алгоритмы. Псевдокод, особенно полезен для разработки алгоритмов, которые преобразуются затем в структурные програм-мы, например, на языке Си. Псевдокод напоминает повседневный язык; он удо-бен и достаточно прост, хотя и не является подлинным языком программиро-вания для компьютера.

Программы на псевдокоде на самом деле не выполняются на компьюте-рах. Скорее они просто помогают программисту «продумывать» программу пе-ред попыткой написать ее на языке программирования, таком, например, как Си. В данной лабораторной работе дается несколько примеров эффективного использования псевдокода при разработке структурированных программ на языке Си.

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

Язык Си предоставляет программисту три типа конструкций выбора. В конструкции выбора if некоторое действие либо выполняется (выбирается), если условие истинно, либо пропускается, если это условие ложно. В конст-рукции выбора if…else некоторое действие выполняется, если условие истин-но, и выполняется другое действие, если это условие ложно. В конструкции выбора switch выполняется одно из набора различных действий в зависимо-сти от значения некоторого выражения.

Page 210: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

210

Конструкция if называется конструкцией с единичным выбором, по-скольку в ней выбирается или игнорируется одно действие. Конструкция if…else называется конструкцией с двойным выбором, поскольку в ней выбор происходит между двумя альтернативными действиями. Конструкция switch называется конструкцией со множественным выбором, поскольку в ней выбор происходит из нескольких различных действий.

Язык Си предусматривает три типа конструкций повторения, а именно цикл while и циклы do…while и for.

Таким образом, в языке Си имеется только семь управляющих конст-рукций: последовательная, три типа выбора и три типа повторения. Любая программа на языке Си строится путем объединения такого количества управ-ляющих конструкций каждого типа, которое соответствует алгоритму, реали-зуемому программой. Управляющие конструкции могут присоединяться друг к другу путем соединения точки выхода одной управляющей конструкции с точ-кой входа последующей. Будем называть это суперпозицией управляющих кон-струкций. Существует еще один способ их соединения — метод, называемый вложением управляющих конструкций. Таким образом, любая программа на языке Си, может быть построена всего лишь из семи различных типов управ-ляющих конструкций, объединенных одним из двух возможных способов.

2.1. Конструкция выбора if. Конструкция выбора используется для избрания одного из альтернативных направлений действий. Например, пред-положим, что проходной балл на экзамене равен 60. Оператор псевдокода

Если оценка студента больше или равна 60 Вывести на экран «Экзамен сдан»

определяет, является ли условие «оценка студента больше или равна 60» ис-тинным или ложным. Если условие истинно, на экран выводится «Экзамен сдан» и «выполняется» следующий по порядку оператор псевдокода. Если ус-ловие ложно, вывод на экран игнорируется и выполняется следующий по по-рядку оператор псевдокода. Вторая строка конструкции выбора, как правило, записывается с отступом.

Описанный выше условный оператор псевдокода может быть написан на языке Си как

if (grade >= 60) printf("Passed\n");

Код на Си близко соответствует псевдокоду. Это является одним из свойств псевдокода, делающих его таким полезным инструментом разработки программ.

Page 211: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

211

Задание 1: Создать в текстовом процессоре MS Word новый документ.

Задание 2: Сохранить созданный документ с именем файла, включаю-щим Вашу фамилию и номер группы и номер лабораторной работы в папке D:\1kursd\номер_группы\ФИО

Задание 3: Оформить в этом файле титульный лист отчета по лабо-раторной работе.

Задание 4: Добавить после титульного листа разрыв страницы (меню Вставка – Разрыв – Новая страница) и на новой странице написать условие задачи из следующего задания.

Задание 5: Написать оператор псевдокод следующей задачи: «Присут-ствуют ли на занятие все студенты группы».

Задание 6: Условие задачи разместить по центру страницы и выделить полужирным курсивом синего цвета, размер шрифта 16 пт. Оператор псев-докода необходимо выровнять по левому краю и выделить шрифтом Arial, размер шрифта 14пт

2.2. Конструкция выбора if…else. В конструкции выбора if указанное действие выполняется только тогда, когда условие истинно; в противном слу-чае действие пропускается. Конструкция выбора if…else дает программисту возможность указать, что в зависимости от того, является ли условие истин-ным или ложным, должны выполняться различные действия. Например, опе-ратор псевдокода

Если оценка студента больше или равна 60 Вывести на экран «Экзамен сдан»

иначе Вывести на экран «Экзамен не сдан»

выводит на экран «Экзамен сдан», если оценка студента больше или равна 60, либо выводит «Экзамен не сдан», если оценка студента меньше 60. В любом случае после вывода на экран «выполняется» следующий по порядку оператор псевдокода. Тело для ветви else также записано с отступом.

Задание 7: Написать оператор псевдокод следующей задачи: «Опреде-лить максимальное и минимальное значения из двух различных вещественных чисел».

Задание 8: Оформить условие задачи и псевдокод в соответствии с за-данием 6.

Page 212: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

212

Вложенные конструкции if…else служат для проверки составных ус-ловий, при этом одни конструкции if…else помещаются внутри других конст-рукций if…else. Например, следующий оператор псевдокода будет печатать А для экзаменационных оценок, больших или равных 90, В для экзаменацион-ных оценок, больших или равных 80, С для экзаменационных оценок, боль-ших или равных 70, D для экзаменационных оценок, больших или равных 60, и F для всех других оценок.

Если оценка студента больше или равна 90 Вывести «А»

иначе Если оценка студента больше или равна 80 Вывести «В»

иначе Если оценка студента больше или равна 70 Вывести «С»

иначе Если оценка студента больше или равна 60 Вывести «D»

иначе Вывести «F»

Задание 9: Написать оператор псевдокод следующих задач: А) Определить максимальное и минимальное значения из трех различных

вещественных чисел. Б) Найти сумму двух наибольших из тех различных чисел. В) Найти произведение двух наименьших из тех различных чисел.

Задание 10: Оформить условие задачи и псевдокод в соответствии с за-данием 6.

3. Конструкция повторения while. Конструкция повторения позво-ляет программисту специфицировать многократное выполнение действия до тех пор, пока некоторое условие остается истинным. Оператор псевдо-кода

Пока в моем списке покупок еще остаются пункты Сделать следующую покупку и вычеркнуть соответствующий пункт описывает повторяющиеся действия, происходящие во время поездки за покупками. Условие «в моем списке покупок еще остаются пункты» может быть истинным или ложным. Если оно истинно, то выполняется действие «Сделать следующую покупку и вычеркнуть соответствующий пункт из списка». Это действие будет многократно выполняться до тех пор, пока ус-

Page 213: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

213

ловие будет оставаться истинным. Оператор(ы), содержащийся в конструк-ции повторения while, составляет тело этой конструкции.

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

4. Формулирование алгоритмов на основе нисходящего поша-гового уточнения: повторение, управляемое контрольным значени-ем. Рассмотрим следующую задачу:

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

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

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

Очевидно, что контрольное значение должно выбираться таким обра-зом, чтобы его нельзя было спутать с допустимым входным значением. По-скольку экзаменационные оценки обычно являются неотрицательными це-лыми числами, приемлемым контрольным значением для этой задачи будет -1. Таким образом, при запуске программы подсчета средней оценки в груп-пе может быть обработан поток входных значений, например, 95, 96, 75, 74, 89 и -1. После этого программа вычислит и выведет на экран среднее значе-ние по группе для оценок 95, 96, 75, 74 и 89 (-1 является контрольным зна-чением, поэтому оно не должно учитываться при расчете среднего).

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

Page 214: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

214

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

Определить среднюю оценку в группе за экзамен

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

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

Инициализировать переменные Ввести, просуммировать и подсчитать количество оценок Вычислить и вывести на экран среднюю оценку для группы Здесь имеет место последовательная структура — перечисленные шаги

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

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

Инициализировать итоговую сумму нулем Инициализировать счетчик нулем Обратите внимание, что нужно инициализировать только итоговую

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

Page 215: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

215

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

Ввести первую оценку Пока пользователь не ввел контрольного значения

Прибавить эту оценку к текущему итогу Прибавить единицу к счетчику оценок Ввести следующую оценку (возможно, контрольное значение)

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

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

Если счетчик не равен нулю Присвоить переменной average сумму, деленную на счетчик Вывести на экран average

иначе Вывести на экран «Не было ввода оценок»

Здесь осуществляется проверка деления на ноль — фатальной ошибки, которая, оставшись невыявленной, способна привести к отказу в работе про-граммы. Полностью второе уточнение имеет следующий вид:

Инициализировать итоговую сумму нулем Инициализировать счетчик нулем

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

Если счетчик не равен нулю Присвоить переменной average сумму, деленную на счетчик Вывести на экран average

иначе Вывести на экран «Не было ввода оценок»

Несколько пустых строк включаются в псевдокод для повышения его удобочитаемости. Фактически пустые строки разделяют эти программы на различные этапы их выполнения.

Алгоритм на псевдокоде, приведенный выше, решает задачу о подсчете средней оценки в группе, был разработан после всего лишь двух этапов уточ-нения. Иногда требуется большее количество этапов.

Page 216: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

216

Задание 11: Используя метод нисходящим пошаговым уточнением на-писать псевдокод следующей задачи: «Необходимо определить общую зар-плату для каждого из нескольких служащих. Компания платит «обычную зарплату» за первые 40 часов, отработанных каждым служащим, и «полу-торную зарплату» за все время, отработанное сверх 40 часов. Вводиться ФИО служащих компании, число часов, отработанных каждым служащим за последнюю неделю, и почасовой тариф каждого служащего. Программа должна определить и отобразить на экране его общую зарплату. Количе-ство сотрудников сразу точно неизвестно, для завершения выполнения про-граммы необходимо использовать контрольное значение».

Задание 12: Оформить условие задачи и псевдокод в соответствии с за-данием 6. Каждый шаг метода нисходящего пошагового уточнения выделить отдельным цветом шрифта.

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

Рассмотрим следующую постановку задачи:

Колледж предлагает платный курс для подготовки студентов к сдаче государственного экзамена на получение диплома брокера по недвижимости. В прошлом году несколько студентов из прослушавших этот курс сдавали экзамен на получение диплома. Естественно, что колледж хотел бы знать, насколько успешно его студенты сдали этот экзамен. Необходимо напи-сать программу для обобщения результатов экзамена. Есть список этих 10 студентов. Напротив фамилии каждого студента проставлена 1, если сту-дент сдал экзамен, и 2, если он экзамен не сдал.

Программа должна анализировать результаты экзамена следующим об-разом:

1. Ввести результат каждого экзамена (т.е. 1 или 2). При каждом оче-редном запросе результата экзамена отображать на экране сообщение «Вве-дите результат».

2. Подсчитать количество результатов каждого типа.

Page 217: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

217

3. Отобразить краткую сводку результатов экзамена, указав количест-во студентов, сдавших экзамен, и количество студентов, его не сдавших.

4. Если экзамен сдали более 8 студентов, вывести сообщение «Повы-сить плату за курс».

После тщательного изучения постановки задачи можно сделать сле-дующие наблюдения:

1. Программа должна обработать 10 результатов экзамена. Будет ис-пользован цикл, управляемый счетчиком.

2. Каждый результат экзамена представляет собой число, 1 или 2. Вся-кий раз, когда программа считывает результат экзамена, она должна опреде-лять, является ли это число 1 или 2. В алгоритме необходимо проверять на 1. Если число не равно 1, предполагается, что это 2.

3. Используются два счетчика — один для подсчета числа студентов, сдавших экзамен, и другой для подсчета числа студентов, его не сдавших.

4. После того, как программа обработает все результаты, она должна решить, сдали ли экзамен более 8 студентов.

Перейдем к нисходящему пошаговому уточнению алгоритма. Начинаем с представления на псевдокоде верхнего уровня:

Проанализировать результаты экзамена и решить, должна ли быть повышена плата за курс

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

Первым уточнением является:

Инициализировать переменные Ввести десять экзаменационных оценок и подсчитать число сданных и

несданных экзаменов Вывести краткую сводку результатов экзамена и решить, должна

ли быть повышена плата за курс Хотя здесь также имеем полное представление всей программы, необхо-

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

Инициализировать переменные

может быть уточнен следующим образом:

Инициализировать нулем количество сданных экзаменов Инициализировать нулем количество несданных экзаменов

Page 218: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

218

Инициализировать счетчик студентов единицей Обратите внимание, что инициализируются только счетчики и итоговые

суммы. Оператор псевдокода

Ввести десять экзаменационных оценок и подсчитать число сданных и несданных экзаменов

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

Пока счетчик студентов меньше или равен десяти Ввести следующий результат экзамена

Если студент сдал экзамен Прибавить единицу к счетчику сданных экзаменов

иначе Прибавить единицу к счетчику несданных экзаменов

Прибавить единицу к счетчику студентов Вставка пустых строк для выделения управляющей структуры if…else

делает программу более удобочитаемой. Оператор псевдокода

Вывести краткую сводку результатов экзамена и решить, должна ли быть повышена плата за курс

может быть уточнен следующим образом:

Вывести количество сданных экзаменов Вывести количество несданных экзаменов Если экзамен сдали более восьми студентов

Вывести «Повысить плату за курс» Полностью второе уточнение показано ниже. В данном случае для вы-

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

Инициализировать нулем количество сданных экзаменов Инициализировать нулем количество несданных экзаменов Инициализируйте счетчик студентов единицей

Пока счетчик студентов меньше или равен десяти Ввести следующий результат экзамена

Page 219: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

219

Если студент сдал экзамен Прибавить единицу к счетчику сданных экзаменов

иначе Прибавить единицу к счетчику несданных экзаменов

Прибавить единицу к счетчику студентов

Вывести количество сданных экзаменов Вывести количество несданных экзаменов Если экзамен сдали более восьми студентов

Вывести «Повысить плату за курс» Теперь псевдокод является достаточно детализированным для преобра-

зования его в код языка Си.

Задание 13: Используя метод нисходящим пошаговым уточнением на-писать псевдокод следующей задачи: «Известны оценки каждого из учеников класса по физике. Посчитать количество пятерок, количество четверок, ко-личество троек и количество двоек»

Задание 12: Оформить условие задачи и псевдокод в соответствии с за-данием 6. Каждый шаг метода нисходящего пошагового уточнения выделить отдельным цветом шрифта.

Индивидуальное задание Задание 1: Создать новый текстовый документ, который будет содер-

жать выполнение индивидуального задания. Задания 2: Написать псевдокод (словесное описание алгоритма) задачи

в соответствии с вариантом. Условие и решение задачи в отчете разместить с новой страницы. Применить различные варианты оформления для условия задачи и псевдокода.

Индивидуальное задание

Вариант 1: Известны два расстояния: одно в километрах, другое – в футах (1 фут = 0,45 м). Какое из расстояний меньше, а какое больше?

Вариант 2: Даны радиус круга и сторона квадрата. У какой фигуры пло-щадь больше?

Вариант 3: Даны объемы и массы двух тел из разных материалов. Мате-риал какого из тел имеет большую плотность?

Вариант 4: Известны сопротивления двух несоединенных друг с другом участков электрической цепи т напряжение на каждом из них. По какому участку протекает меньший ток?

Вариант 5: Дано натуральное число. Определить является ли оно четным. Вариант 6: Дано двузначное число. Определить какая из его цифр больше:

Page 220: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

220

первая или вторая.

Задания 3: Используя метод нисходящим пошаговым уточнением на-писать псевдокод (словесное описание алгоритма) задачи в соответствии с ва-риантом (при необходимости использовать повторение, управляемое кон-трольным значением). Условие и решение задачи в отчете разместить на но-вой странице. Применить различные варианты оформления для условия зада-чи и псевдокода на каждом шаге метода нисходящего пошагового уточнения.

Вариант 1: Известна масса каждого груза загруженного в автомобиль. Вы-яснить не превысила ли общая масса всех грузов грузоподъем-ность автомобиля.

Вариант 2: Известно число жителей, проживающих в каждом доме улицы. Нумерация домов проведена подряд. Дома с нечетными номе-рами расположены на одной стороне улицы, с четными - на другой. На какой стороне улицы проживает больше жителей?

Вариант 3: Известна стоимость каждого из восьми предметов в двух набо-рах. Какой из наборов предметов более дешевый?

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

Вариант 5: Даны десять целых чисел. Определить является ли их сумма четным числом.

Вариант 6: Три группы студентов, в каждой из которых 20 человек, в сес-сию сдавали по три экзамена. Определить лучшую по среднему баллу группу.

Задания 4: Используя метод нисходящим пошаговым уточнением на-писать псевдокод (словесное описание алгоритма) задачи в соответствии с ва-риантом (при необходимости использовать повторение, управляемое кон-трольным значением). Условие и решение задачи в отчете разместить на но-вой странице. Применить различные варианты оформления для условия зада-чи и псевдокода на каждом шаге метода нисходящего пошагового уточнения.

Примечание: Для нахождения минимального/максимального элемента в последовательности при вводе необходимо первоначально принять за ми-нимальный/максимальный элемент первый элемент последовательности. Да-лее каждый введенный элемент сравнивается с минимальным/максимальным на текущий момент элементом. Если он меньше/больше его, то его значение

Page 221: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

221

становиться минимумом/максимумом последовательности на данный момент. Далее считывается новый элемент и сравнение повторяется.

Вариант 1: Известны расстояния от Москвы до нескольких городов. Най-ти расстояние от Москвы до самого удаленного от нее города, из представленных в списке городов.

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

Вариант 3: Известны данные о количестве людей, живущих в квартире №1, в квартире №2 и т.д. В каком числе квартир проживает больше всего жильцов?

Вариант 4: Известны максимальные скорости каждой из 20 марок легко-вых автомобилей. Определить, какую максимальную скорость имеет самый быстрый автомобиль.

Вариант 5: Известен рост каждого человека из группы. На сколько рост самого высокого из них превышает рост самого низкого?

Вариант 6: Известно число учеников в каждом из 20 классов школы. На сколько численность самого большого (по числу учеников) класса превышает численность самого маленького класса?

Лабораторная работа №2.

ГРАФИЧЕСКОЕ ОПИСАНИЕ АЛГОРИТМА

Теоретическая часть При выполнении лабораторной работы используется такие программ-

ные продукты, как Microsoft Office Word и Microsoft Office Visio. Microsoft Office Visio 2003 графический редактор, который позволяет

создавать блок-схемы алгоритмов. 1. Создание нового документа

Для построения блок-схемы с помщью Microsoft Office Visio 2003. Для запуска графического редактора Microsoft Office Visio 2003 необходимо вы-брать команду Пуск – Программы - Microsoft Office - Microsoft Office Visio 2003.

Microsoft Office Visio 2003 предоставляет широкий набор графических шаблонов для создания различных схем и диаграмм. Для создания блок-схем в категории шаблонов (на левой панели) необходимо выбрать Business Process, а в подкатегории Basic Flowchart (см. рис.1).

Page 222: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

222

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

шаблоны

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

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

Для прорисовки линей необходимо включить панель рисования Draw-

ing Tools нажав на панели инструментов кнопку Drawing Tools и в от-крывшейся панели инструментов выбрать элемент рисования линии Line

Tool , после чего курсором мыши прорисовать линию.

Page 223: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

223

Линию можно преобразовать в стрелки, для этого необходимо выде-

лить линию и в раскрывающемся списке Line Ends выбрать требуемый вид стрелки.

Кнопка на панели инструментов Text Tool позволяет создать тексто-вую надпись вне элементов.

Кнопка на панели инструментов Pointer Tool позволяет выделить элемент для перемещения. Удерживаю клавишу Shift можно выделить сразу несколько элементов для перемещения или редактирования.

Чтобы все элементы созданной блок-схемы можно было копировать и перемещать как один элемент их необходимо сгруппировать. Для этого пер-воначально необходимо выделить все элементы блок-схемы (удерживая кла-вишу Shift мышью выделить все элементы либо удерживая левую клавишу мыши обвести прямоугольником все элементы блок-схемы) и потом выбрать пункт Shape – Grouping – Group. Пункт меню Shape – Grouping – Ungroup позволяет разгруппировать элементы, для того чтобы их можно было по от-дельности перемещать и редактировать.

2 Графическое представление алгоритма Базовые структуры схемы алгоритма. Под схемой программы будем

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

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

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

Функциональный блок.

Логический блок.

Блок, обозначающий операции ввода-вывода.

Page 224: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

224

Название блока Изображение блока

Изображение цикла

Используя исходные элементы блок-схем можно собрать более крупные кирпичики, которые называют базовыми структурами. Базовые структуры (конструкции):

- следование; - ветвление (полное и не полное); - повторение (цикл с предусловием или постусловием); - вход; -выход. Каждая базовая структура имеет один вход и один выход. Схемы ос-

новных базовых алгоритмических структур: Следование Повторение (Цикл )

Ветвление (полное)

Page 225: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

225

Выбор (оператор switch)

3. Линейные алгоритмы.

Пример 1: Нарисовать схему алгоритма решения следующей задачи: «Дано натуральное трёхзначное число N. Получить число M, которое является перевёртышем числа N».

Схема алгоритма представлена на рисунке 2. Пример 2: Нарисовать схему алгоритма решения следующей задачи:

«Определить периметр и площадь квадрата, если заданы две его стороны a и b».

Схема алгоритма представлена на рисунке 3.

Page 226: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

226

Рис. 2 Схема алгоритма (пример 1) Рис. 3 Схема алгоритма (пример 3)

Задание 2: Нарисовать схему решения следующей задачи «Дано нату-ральное трёхзначное число N. Составить алгоритм для получения произведе-ния цифр этого числа». Сгруппировать схему и скопировать ее в отчет.

Задание 3: Нарисовать схему решения следующей задачи «Ввести два действительных числа. Найти среднее арифметическое этих чисел и среднее геометрическое их модулей». Сгруппировать схему и скопировать ее в отчет.

4. Разветвляющиеся алгоритмы В логических блоках для проверки условия используются логические

операции. Логические операции предназначены для выполнения логических

Page 227: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

227

преобразований над операндами. Перечень логических операций приведен в таблице 2 Таблица 2. Логические операции Знак опера-ции

Наименование Пример

&& Логическое "И" (конъюнкция)

а= b && с; если b и с не равны нулю, то а=1, в противном случае а=0

|| Логическое "ИЛИ" (дизъюнкция)

а= b || с; если b и с равны нулю, то а=0, в противном случае а=1

! Логическое отрица-ние (инверсия)

а= ! b; если b равно нулю, то а=1, если b не равно нулю, то а=0

Логические операции выполняют следующие действия: логическое от-рицание (!), логическое И (&&) и логическое ИЛИ (||).

Пример 3: Нарисовать схему алгоритма решения следующей задачи: «Вводиться двузначное число. Определить входят ли в него цифра 4».

Схема алгоритма представлена на рисунке 4.

Page 228: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

228

Рис. 4 Схема алгоритма (пример 3)

Задание 4: Нарисовать схему решения следующей задачи «Вводиться двузначное число. Определить, равен ли квадрат этого числа учетверенной сумме кубов его цифр». Сгруппировать схему и скопировать ее в отчет.

Пример 4: Нарисовать схему алгоритма решения следующей задачи: «Даны три числа a, b, c. Значение наибольшего из них присвойте переменной d.».

Схема алгоритма представлена на рисунке 5.

Page 229: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

229

Начало

a,b,c

d

Конец

a>b && a>c

d=a

Данет

b>cДанет

d=c d=b

Рис. 5 Схема алгоритма (пример 4)

Задание 5: Нарисовать схему решения следующей задачи «Если среди чисел a, b и c есть пара взаимно противоположных, вывести третье (остав-шееся) число, в противоположном случае вывести сообщение "нет"». Сгруп-пировать схему и скопировать ее в отчет.

Пример 5: Нарисовать схему алгоритма решения следующей задачи: «Подсчитать количество отрицательных чисел среди чисел m, n, p».

Схема алгоритма представлена на рисунке 6.

Page 230: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

230

Начало

m,n,p

k=0

m<0Да

Инициализируется нулем счетчик

отрицательных чисел

k=k+1

n<0Да

k=k+1

n<0Да

k=k+1

k

Конец

Нет

Нет

Нет

Рис. 6 Схема алгоритма (пример 5)

Page 231: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

231

Задание 6: Нарисовать схему решения следующей задачи «Подсчитать количество четных чисел среди чисел a, b и c». Сгруппировать схему и скопи-ровать ее в отчет.

5. Циклические алгоритмы. Пример 6: Нарисовать схему алгоритма решения следующей задачи:

«Найти произведение и сумму целых положительных четных чисел от 0 до n (значение n вводится с клавиатуры)». Схема алгоритма представлена на ри-сунке 7.

Пример 7: Нарисовать схему алгоритма решения следующей задачи: «Даны натуральное число n и числа а1, а2, …, an. Определить сумму четных среди чисел а1, а2, …, an.». Схема алгоритма представлена на рисунке 8.

Page 232: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

232

Рис. 8 Схема алгоритма (пример 6) Рис. 9 Схема алгоритма (пример 7)

Индивидуальное задание

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

вой поверхности, площадь полной поверхности и объем

Page 233: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

233

цилиндра. Вариант 2: Ввести длины ребер куба. Найти объем куба и площадь

его боковой поверхности. Вариант 3: Ввести радиус шара. Найти площадь поверхности и объем

шара. Вариант 4: Ввести два действительных числа. Найти среднее арифме-

тическое этих чисел и среднее геометрическое из моду-лей.

Вариант 5: Ввести катеты прямоугольного треугольника. Найти его гипотенузу и площадь.

Вариант 6: Ввести стороны равностороннего треугольника. Найти площадь этого треугольника и его высоту.

Вариант 7: Ввести радиус круга. Найти длину окружности и площадь круга, ограниченного этой окружностью.

Вариант 8: Ввести стороны прямоугольного параллелепипеда. Найти площадь поверхности и объем параллелепипеда.

Вариант 9: Найти сумму членов арифметической прогрессии a, a+d, ..., a+(n—1)d по введенным значениям a, d, n.

Вариант 10: Вычислить расстояние между двумя точками с координа-тами (х1, y1) и (х2, y2). Координаты точек вводятся с кла-виатуры.

Вариант 11: Треугольник задан координатами своих вершин. Найти периметр треугольника. Координаты вершин вводятся с клавиатуры.

Вариант 12: Ввести радиус, длину ребра и высоту конуса. Найти пло-щадь боковой поверхности, площадь полной поверхности и объем конуса.

Вариант 13: Найти сумму членов геометрической прогрессии b, b*q, ..., b*q(n—1) по введенным значениям b, q, n.

Вариант 14: Определить высоту треугольника, если даны три его стороны (a,b,c).

Вариант 15: Треугольник задан координатами своих вершин. Найти периметр треугольника. Координаты вершин вводятся с клавиатуры.

Задания 2: Вариант 1: Известны два расстояния: одно в километрах, другое – в фу-

тах (1 фут = 0,45 м). Какое из расстояний меньше, а какое больше?

Вариант 2: Даны радиус круга и сторона квадрата. У какой фигуры пло-щадь больше?

Вариант 3: Даны объемы и массы двух тел из разных материалов. Мате-риал какого из тел имеет большую плотность?

Вариант 4: Вводиться трехзначное число. Определить кратна ли трем сумма его цифр.

Page 234: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

234

Вариант 5: Вводиться натуральное трехзначное число n. Выяснить, вер-но ли, что это число содержит ровно две одинаковые цифры.

Вариант 6: Вводиться трехзначное число. Определить какая из его цифр больше: первая, вторая или третья.

Вариант 7: Вводиться натуральное трехзначное число n. Выяснить, раз-личны ли все три цифры этого числа.

Вариант 8: Вводиться трехзначное число. Определить больше ли числа а сумма его цифр. Число а вводиться с клавиатуры.

Вариант 9: Вводиться натуральное число. а) Верно ли, что оно заканчи-вается четной цифрой? б) Верно ли, что оно заканчивается нечетной цифрой?

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

Вариант 11: Вводиться трехзначное число. Определить входит ли и него цифра а. Число а вводиться с клавиатуры.

Вариант 12: Определить, является ли треугольник со сторонами а, b, c равнобедренным. Стороны треугольника вводятся с клавиа-туры.

Вариант 13: Вводиться трехзначное число. Определить одинаковы ли его цифры.

Вариант 14: Вводиться натуральное трехзначное число n. Выяснить, яв-ляется ли оно палиндромом ("перевертышем"). Палиндромом называется число, десятичная запись которого читается оди-наково слева направо и справа налево.

Вариант 15: Вводиться трехзначное число. Определить кратна ли сумма его цифр числу а. Число а вводиться с клавиатуры.

Задания 3: Вариант 1: Даны натуральное число n и вещественные числа а1, а2, …,

an. Определить среднее арифметическое вещественных чи-сел.

Вариант 2: Известна масса каждого из 12 предметов. Определить об-щую массу всего набора предметов.

Вариант 3: Даны натуральное число n и числа а1, а2, …, an. Определить сумму положительных среди чисел а1, а2, …, an.

Вариант 4: Известен возраст (в годах в виде 14,5 лет и т. п.) каждого ученика класса. Определить средний возраст учеников класса. Количество учеников в классе вводится с клавиату-ры.

Вариант 5: Даны натуральное число n и числа а1, а2, …, an. Определить сумму четных среди чисел а1, а2, …, an.

Вариант 6: Известна масса каждого предмета из некоторого набора предметов. Определить среднюю массу. Количество пред-метов вводиться с клавиатуры.

Вариант 7: Даны натуральное число n и вещественные числа а1, а2, …,

Page 235: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

235

an.Определить сумму квадратов отрицательных веществен-ных чисел.

Вариант 8: Найти сумму целых положительных чисел от a до b и крат-ных 3 (значения а и b вводятся с клавиатуры; b > а).

Вариант 9: Даны натуральное число n и числа а1, а2, …, an. Определить сумму чисел кратных 3 среди чисел а1, а2, …, an.

Вариант 10: Найти среднее арифметическое целых положительных чи-сел от a до b и кратных 5 (значения а и b вводятся с клавиа-туры; b > а).

Вариант 11: Даны натуральное число n и числа а1, а2, …, an.Определить сумму и произведение модулей чисел а1, а2, …, an.

Вариант 12: Найти среднее арифметическое целых положительных не-четных чисел от 1 до n (значение n вводится с клавиатуры).

Вариант 13: Найти сумму квадратов всех четных целых чисел от а до 50 (значение а вводится с клавиатуры; 0 < а < 50).

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

Вариант 15: Найти сумму целых положительных чисел от 1 до n, крат-ных 3 (значение n вводится с клавиатуры).

Задания 4: Вариант 1: Дана последовательность ai=i2, номера её первого и послед-

него членов 1 и n. Найдите сумму S и произведение P тех её членов, номера которых являются нечетными.

Вариант 2: Дана последовательность ai=i2, номера её первого и послед-него членов 1 и n. Найдите сумму S и произведение P тех её членов, номера которых являются четными.

Вариант 3: Дана последовательность ai=i2, номера её первого и послед-него членов 1 и n. Найдите сумму S и произведение P тех её членов, номера которых являются кратными 3.

Вариант 4: Дана последовательность an=n sin n найдите сумму членов, номера которых записываются двузначными числами.

Вариант 5: Дана последовательность an=n sin n найдите сумму положи-тельных членов из первых 100 членов.

Вариант 6: Дана последовательность an=n sin n найдите сумму тех из первых 100 членов, модули которых меньше 0,5.

Вариант 7: Найти значение выражения (для натуральных m и n, m<n) A=m+(m+1)+...+(m+n)

Вариант 8: Найти значение выражения ( для натуральных m и n, m<n) B=m*(m+1)*...*(m+n)

Вариант 9: Найти сумму квадратов четных чисел из первых n натураль-ных чисел.

Вариант 10: Найти значение выражения (для натурального числа n) S=1+1*2+1*2*3+1*2*3*4+...+1*2*3*...*n.

Page 236: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

236

Вариант 11: Найти значение выражения (для натурального числа n) S=1+2+...+n.

Вариант 12: Найти сумму кубов первых n натуральных чисел. Вариант 13: Найти значение выражения (для натурального числа n)

F=1*2*...*n Вариант 14: Найти значение выражения (для натурального числа n)

Y=1+1/2+1/3+...+1/n Вариант 15: Найти значение выражения ( для натуральных m и n, m<n)

X=1/m+1/(m+1)+...+1/(m+n)

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

СТРУКТУРА ПРОСТОЙ ПРОГРАММЫ НА Си.

ФУНКЦИИ ВВОДА-ВЫВОДА

Теоретическая часть Структура программы. Функция вывода. Рассмотрим довольно про-

стую программу на Си — печать строки текста:

Пример 1. /* Первая программа на С */ #include<stdio.h> void main () { printf ("Welcome to C!\n"); }

Результат работы программы:

Welcome to С!

Рассмотрим подробно каждую строчку программы. Строка:

/* Первая программа на С */

начинается символами /* и заканчивается символами */, означающими, что эта строка является комментарием. Программисты вставляют в код коммен-тарии для документирования программ и для того, чтобы сделать их более удобочитаемыми. Комментарии не оказывают никакого влияния на работу компьютера во время исполнения программы. Комментарий «Первая про-грамма на С» просто объясняет назначение программы. Комментарии также помогают другим людям прочитать и понять программу, однако слишком многословные комментарии могут, наоборот, затруднить ее прочтение.

Строка:

void main ()

Page 237: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

237

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

Левая фигурная скобка ({) должна предварять тело каждой функции. Соответственно правая фигурная скобка должна стоять в конце каждой функции. Эта пара скобок и часть программы между ними называется бло-ком.

Строка:

printf("Welcome to C!\n");

дает компьютеру команду выполнить действие, а именно вывести на экран строку символов, находящуюся внутри кавычек. Такую строку называют символьной строкой, сообщением или литералом. Вся строка, включая printf, аргументы внутри круглых скобок и точку с запятой (;), называется оператором. Каждый оператор должен заканчиваться точкой с запятой (ино-гда называемой символом конца оператора). Результатом выполнения опера-тора printf является вывод сообщения Welcome to С! на экран. Символы обычно печатаются именно так, как они записаны внутри двойных кавычек в операторе printf. Заметьте, что символы \n не появились на экране. Обратная косая черта (\) называется esc-символом. Он указывает, что оператор printf предстоит выполнить нечто нестандартное. Когда встречается обратная косая черта, printf считывает следующий за ним символ и, объединяя его с обрат-ной косой четой, создает esc-код. Esc-код \n означает перевод на новую стро-ку, результатом является перевод курсора на начало следующей строки на экране. Функция printf — одна из многих функций, входящих в стандартную библиотеку языка Си.

Правая фигурная скобка (}) означает, что выполнение функции main окончено.

Задание 1. Выполнить пример 1, приведенный выше. Рассмотрим еще два примера программы с использованием оператора

printf. Пример 2. Программа печатает в одну строку двумя вызовами функции

printf.

#include<stdio.h> void main () {

Page 238: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

238

printf("Welcome "); printf("to C!\n");

}

Результат работы программы:

Welcome to C!

Пример 3. Программа печатает несколько строк одним вызовом функции printf().

#include<stdio.h> void main() {

printf("Welcome\nto\nC!\n"); }

Результат работы программы:

Welcome to C!

Функция printf может напечатать Welcome to С! несколькими различ-ными способами. Например, результат выполнения программы в примере 2 такой же, что и в примере 1. Дело в том, что каждая последующая функция printf возобновляет печать с того самого места, на котором остановилась предыдущая функция printf. Первая функция printf печатает Welcome и сле-дующий за ним пробел, вторая функция printf начинает печатать в позиции, следующей сразу за пробелом.

Один оператор printf может напечатать несколько строк, если исполь-зовать символы перехода на новую строку, как показано в примере 3. Каж-дый раз, когда встречается esc-код \n (новая строка), функция printf перево-дит курсор на начало следующей строки.

Задание 2. Выполнить пример 2 и пример 3, приведенные выше.

Задание 3. Напишите программу, выводящую на печать вашу фамилию и имя следующими тремя способами:

- в одну строку применив один оператор printf; - в одну строку применив два оператора printf; - в две строки применив один оператор printf.

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

Page 239: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

239

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

Пример 4. Программа сложения двух чисел.

/* Программа сложения */ #include <stdio.h> int main () {

int integer1, integer2, sum; /* объявление */ printf("Vvedite pervoe celoe chislo\n"); /* подсказка */ scanf("%d", &integer1); /* прочитать целое */ printf("Vvedite vtoroe celoe chislo \n"); /* подсказка */ scanf("%d", &integer2); /* прочитать целое */ sum = integer1 + integer2; /* присвоить сумму */ printf("Summa ravna %d\n", sum); /* напечатать сумму */ return 0; /* показывает успешное завершение программы */

}

Результат работы программы:

Vvedite pervoe celoe chislo 45 Vvedite vtoroe celoe chislo 72 Summa ravna 117

Комментарий /* Программа сложения */ объясняет назначение про-граммы. Строка:

#include <stdio.h>

является директивой для препроцессора Си. Строка, начинающаяся символом #, выполняется препроцессором до того, как программа начнет компилиро-ваться. Эта специфическая строка сообщает препроцессору, что необходимо включить в программу содержание стандартного заголовочного файла вво-да/вывода (stdio.h). Этот заголовочный файл содержит информацию и объяв-ления, используемые компилятором во время компиляции вызовов стандарт-ных функций ввода/вывода, таких, как printf. Кроме того, заголовочный файл содержит информацию, которая помогает компилятору определить, корректно ли написаны обращения к библиотечным функциям.

Как было отмечено выше, каждая программа начинает исполняться с функции main. Левая фигурная скобка отмечает начало тела main, а правая соответственно конец. Строка:

int integer1, integer2, sum;

Page 240: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

240

является объявлением. Группы символов integer1, integer2 и sum — имена пе-ременных. Переменная — это ячейка памяти, в которую можно записывать значение, предназначенное для использования программой. Приведенное выше объявление сообщает, что переменные integer1, integer2 и sum принад-лежат к типу int и, следовательно, в этих переменных будут храниться целые величины. Все переменные, которые используются в программе, должны быть объявлены. При объявлении указывается имя и тип переменной. Име-нем переменной в Си может служить любой допустимый идентификатор.

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

Оператор:

printf("Vvedite pervoe celoe chislo \n");

печатает на экране символы Vvedite pervoe celoe chislo и переводит курсор на начало следующей строки.

Оператор:

scanf("%d", &integer1);

вызывает scanf, чтобы получить от пользователя некое значение. Функция scanf считывает данные со стандартного устройства ввода, которым обычно является клавиатура. В нашем случае функция scanf имеет два аргумента, %d и &integer1. Первый аргумент — управляющая строка, задает формат счи-тывания, тем самым определяется тип данных, которые предстоит ввести пользователю. Так, в частности, %d — спецификация преобразования, озна-чающая, что вводимые данные должны быть целыми числами (буква d ис-пользуется для «десятичных целых»). Знак % в данном контексте трактуется scanf (в дальнейшем мы увидим, что это в полной мере относится и к printf), как esc-код (подобно \), а комбинация %d является esc-кодом (подобно \n). Второй аргумент scanf начинается со знака амперсанда (&), которым в Си задается операция взятия адреса следующей за ним переменной. Амперсанд, когда он используется совместно с именем переменной, сообщает scanf ячейку памяти, в которой хранится переменная integer1. В последующем компьютер будет хранить величину для integer1 в этой ячейке.

Когда компьютер выполняет вышеприведенный оператор scanf, он ждет, пока пользователь не введет значение для переменной integer1. Поль-зователь вводит целое число, после чего нажимает клавишу Enter, посылая, таким образом, число в компьютер. После этого компьютер присваивает дан-

Page 241: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

241

ное число (значение) переменной integer1. Любая последующая ссылка в программе на integer1 будет представлять именно это значение.

Оператор

printf("Vvedite vtoroe celoe chislo \n");

печатает на экране сообщение Enter second integer, после чего переводит кур-сор на начало следующей строки.

Оператор

scanf("%d", &integer2);

получает от пользователя значение для переменной integer2. В результате выполнения оператора присваивания

sum = integer1 + integer2;

вычисляется сумма переменных integer1 и integer2, и ее значение присваива-ется переменной sum посредством операции присваивания =. Оператор чита-ется как «sum получает значение integer1 + integer2».

Оператор

printf("Summa ravna %d\n", sum);

вызывает функцию printf, чтобы напечатать на экране текст Sum is, после которого следует численное значение переменной sum. В данном случае printf имеет два аргумента, "Sum is %d\n" и sum. Первый аргумент — управ-ляющая строка, определяет формат вывода. Он содержит несколько симво-лов, которые будут отображены, и спецификатор преобразования %d, опре-деляющий, что будет напечатано целое число. Второй аргумент задает значе-ние, которое будет напечатано.

Вычисления могут выполняться и непосредственно внутри оператора printf. Мы могли бы скомбинировать два предыдущих оператора в один:

printf("Summa ravna %d\n", integerl + integer2);

Оператор:

return 0;

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

Правая фигурная скобка означает, что функция main окончена.

Задание 4. Выполнить пример 4, приведенный в методических реко-мендациях.

Page 242: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

242

Задание 5. Написать программу, которая запрашивает у пользователя три целых числа и выводит на экран их сумму и произведение.

Кроме упомянутого выше типа данных int для объявления целочислен-ных чисел, в Си существуют и другие типы данных для объявления перемен-ных и констант вещественного, символьного и других типов.

Имеются следующие базовые (фундаментальные) типы данных: - char - символьный - int - целый - float - вещественный - double - вещественный с двоичной точностью - void - пустой тип

С базовыми типами данных могут использоваться модификаторы типа. К модификаторам относятся:

- unsigned - беззнаковый - signed - знаковый - short - короткий - long - длинный

В функциях printf и scanf необходимо использовать следующие спе-цификации преобразования для соответствующих типов:

%i — для ввода/вывода целых со знаком, %d — для ввода/вывода беззнаковых целых, %f — для ввода/вывода дробных чисел, в виде числа с плавающей

точкой, %n.mf — для вывода дробных чисел в формате с фиксированной

точкой, где n — количество цифр целой части, m — дробной; Количество спецификаций преобразования в функциях printf и scanf

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

Кроме переменных в программе могут быть объявлены константы – данные, которые не могут быть изменены в процессе выполнения програм-мы. Для объявления констант перед указанием типа константы и ее имени необходимо добавить ключевое слово const.

Пример 5. Объявление типов данных. #include<stdio.h> /*подсоединение раздела библиотеки с функциями ввода/вывода */ void main() // определение головного модуля {

Page 243: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

243

int i1, i2, i3; // три переменные целого типа со знаком int ix= 5, iy= -7; /* определение и инициализация переменных целого типа */ long int l1, l2; /* длинные целые знаковые переменные – четыре байта */ long unsigned int lu1= 125, lu2= 1234567; /* под длинные целые беззнаковые переменные выделяется по четыре байта и в них записываются соответствующие значения */ float f1= -1.575, f2= 3.14; /* переменные вещественного типа по четыре байта */ char let, symb= ‘z’, n_str= ‘\n’; /* символьные переменные,

выделяется по одному байту */ short int s1= 100, s2= 50; // два байта const unsigned int u= 113; //целочисленная константа const float pi= 3.14; // вещественная константа printf("Vvedite 3 celih chisla:\n"); scanf("%d%d%d", &i1, &i2, &i3); printf("Vvedennoe pervoe chislo=%d\n Vvedennoe vtoroe chislo =%d\n

Vvedennoe tret’e chislo =%d\n", i1, i2, i3); printf("Celoe bez znaka ix = %d\n Celoe so znakom iy = %i\n", ix, iy); printf("Veshestvenoe f1 = %.3f\n Veshestvenoe f2 = %.2f\n", f1, f2); printf("Simvol symbl = %c\n Kod simvola %c = %d \n", symb, symb,

symb); /* Данные типа char занимают в памяти 1 байт. Код от 0 до 255 в этом байте задает один из 256 возможных символов. Тип char является ти-пом «целое». */ }

Задание 6. Выполнить пример 5, приведенный выше.

Задание 7. Модифицируйте пример 4 так, чтобы программа работала с вещественными числами.

Задание 8. Написать программу, которая запрашивает у пользователя три вещественных числа и выводит на экран их сумму, произведение и сред-нее арифметическое.

Математические функции. Для работы с математическими функция-ми в языке Си необходимо подключить библиотеку math.h. Эта библиотека содержит ряд математических функций, таких как

- sqrt(x); - возвращает корень квадратный переменной х; - abs(n); - возвращает модуль числа n. n – целое число; - sin(x); - возвращает синус числа х; - cos(x); - возвращает косинус числа х.

Page 244: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

244

Индивидуальное задание

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

Варинт 1. Ввести высоту и радиус цилиндра. Найти площадь боковой поверхности, площадь полной поверхности и объем цилиндра. Результат вы-вести с точностью до двух знаков после запятой.

Варинт 2. Ввести длины ребер куба. Найти объем куба и площадь его боковой поверхности. Результат вывести с точностью до трех знаков после запятой.

Варинт 3. Ввести радиус шара. Найти площадь поверхности и объем шара. Результат вывести с точностью до двух знаков после запятой.

Варинт 4. Ввести два действительных числа. Найти среднее арифмети-ческое этих чисел и среднее геометрическое их модулей. Результат вывести с точностью до трех знаков после запятой.

Варинт 5. Ввести катеты прямоугольного треугольника. Найти его ги-потенузу и площадь. Результат вывести с точностью до двух знаков после за-пятой.

Варинт 6. Ввести стороны равностороннего треугольника. Найти пло-щадь этого треугольника и его высоту. Результат вывести с точностью до трех знаков после запятой.

Варинт 7. Ввести радиус круга. Найти длину окружности и площадь круга, ограниченного этой окружностью. Результат вывести с точностью до двух знаков после запятой.

Варинт 8. Ввести стороны прямоугольного параллелепипеда. Найти площадь поверхности и объем параллелепипеда. Результат вывести с точно-стью до трех знаков после запятой.

Варинт 9. Найти сумму членов арифметической прогрессии a, a+d, ..., a+(n-1)d по введенным значениям a, d, n.

Варинт 10. Вычислить расстояние между двумя точками с координата-ми (х1, y1) и (х2, y2). Координаты точек вводятся с клавиатуры. Результат вывести с точностью до двух знаков после запятой.

Варинт 11. Треугольник задан координатами своих вершин. Найти пе-риметр треугольника. Координаты вершин вводятся с клавиатуры.

Варинт 12. Ввести радиус, длину ребра и высоту конуса. Найти пло-щадь боковой поверхности, площадь полной поверхности и объем конуса. Результат вывести с точностью до трех знаков после запятой.

Page 245: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

245

Варинт 13. Найти сумму членов геометрической прогрессии b, b*q, ..., b*q(n—1) по введенным значениям b, q, n.

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

ОПЕРАТОРЫ ВЕТВЛЕНИЯ

Теоретическая часть Инструкция if

Вариант 1: if (условное выражение)

оператор1; Вариант 2: if (условное выражение)

оператор1; else

оператор2; □ инструкция if используется для выбора одного из двух направлений

дальнейшего хода программы; □ выбор последовательности инструкций осуществляется в зависимо-

сти от значения условия — заключенного в скобки выражения, записанного после if;

□ инструкция, записанная после else, выполняется в том случае, если значение выражения условие равно нулю, во всех остальных случаях выполняет-ся инструкция, следующая за условием;

□ если при соблюдении или несоблюдении условия надо выполнить несколько инструкций программы, то эти инструкции следует объединить в группу — заключить в фигурные скобки;

□ при помощи вложенных одна в другую нескольких инструкций if можно реализовать множественный выбор.

Выражения и операции. В языке Си существуют следующие виды операций:

§ арифметические операции; § логические операции; § операции отношений; § операции присваивания; § побитовые операции; § операции адресации/разадресации.

Рассмотрим каждый из названных видов операций.

Page 246: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

246

Арифметические операции предназначены для выполнения обычных арифметических действий над операндами и представлены в таблице 4.1

Таблица 4.1. Арифметические операции. Знак опера-

ции Наименование Пример

+ Сложение a=b+c; если b=6, c=5, то a=11 - Вычитание a=b-c; если b=6, c=5, то a=1 - Арифметическое

отрицание a=-b; если b=6, то a=-6

* Умножение a=b*c; если b=6, c=5, то a=30 / Деление a=b/c; если b=10, c=5, то a=2

% Деление по модулю (остаток от деления)

a=b%c; если b=6, c=5, то a=1

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

Логические операции предназначены для выполнения логических пре-образований над операндами. Перечень логических операций приведен в таблице 4.2

Таблица 4.2. Логические операции Знак опера-

ции Наименование Пример

&& Логическое "И" (конъюнкция)

а= b && с; если b и с не равны нулю, то а=1, в противном случае а=0

|| Логическое "ИЛИ" (дизъюнкция)

а= b || с; если b и с равны нулю, то а=0, в противном случае а=1

! Логическое отрица-ние (инверсия)

а= ! b; если b равно нулю, то а=1, если b не равно нулю, то а=0

Операции отношений являются бинарными операциями (таблица 4.3).

Таблица 4.3. Операции отношений Знак опера-

ции Наименование Пример

== Сравнение на ра-венство

а == b; вырабатывает 1,если а равно b, и 0 – в противном случае

Page 247: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

247

> Больше а > b; вырабатывает 1, если а больше b, и 0 – в противном случае

>= Больше или равно а >= b; вырабатывает 1, если а больше или равно b, и 0 – в противном случае

< Меньше а < b; вырабатывает 1,если а меньше b, и 0 – в противном случае

<= Меньше или равно а <= b, Вырабатывает 1, если а меньше или равно b, и 0 – в противном случае

!= Не равно а != b; вырабатывает 1, если а не равно b, и 0 – в противном случае

Бинарные операции отношений сравнивают значение первого операнда со значением второго. Результатом сравнения является значение переменной равное 1 (true) или 0 (false). Типом результата всегда является int. Операнды могут быть целого, вещественного или адресного типов. Типы первого и вто-рого операндов могут различаться.

Операции присваивания в Си могут вычислять и присваивать значения в одной операции (таблица 4.5)

Таблица 4.5. Операции присваивания Знак

операции Наименование Пример

= Простое присваивание а = b; а присваивается значение b ++ Унарный инкремент а++ (++а) значение а увеличивается

на единицу -- Унарный декремент а-- (--а) значение а уменьшается на

единицу znak= Составная операция

присваивания: znakÎ(*,/,%,+,-,<<,

>>,&, |, ^)

a znak= b; понимается как а = a znak b; где znak символ операции; напри-мер, а += b, если а=3, b=4, то а=7; если операция a -=b, то a=-1

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

Унарные операции инкремента (++) и декремента (--) предназначены со-ответственно для увеличения и уменьшения значения операнда на единицу. Операции (++) и (--) можно записывать как после операнда, так и перед ним. В первом случае (a++ и a--) значение операнда (a) изменяется после его ис-

Page 248: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

248

пользования в соответствующем выражении, а во втором случае (++a и –a) перед его использованием.

Пример 1. Отыскание максимума из трех чисел а, b, с. Числа вводятся с кла-виатуры.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int a, b, c, max; printf("Vvedite 3 chisla:\n"); scanf("%d%d%d",&a,&b,&c); if (a > b && a > c) max=a; else if (b > c) max=b; else max=c; printf("max = %d", max); return 0;

} Пример 2. Ввести число и определить, оно больше нуля, меньше или равно

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n; printf("Enter n\n"); scanf("%d", &n); if (n>0) printf("n>0\n"); else if (n<0) printf("n<0\n"); else printf("n=0\n"); return 0; } Пример 3: Напишите программу (используя инструкцию if), которая запраши-

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

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n; printf("Vvedite nomer mesyaca\n"); scanf("%d", &n); if (n==1 || n==2 || n==12) printf("Zima\n"); else if (n>=3 && n<=5) printf("Vesna\n"); else if (n>=6 && n<=8) printf("Leto\n"); else printf("Osen'\n"); return 0; }

Page 249: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

249

Пример 4: Вводиться трехзначное число. Подсчитать количество четных цифр в числе.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n,a,b,c,z=0; //z-счетчик количества printf("Vvedite 3-hznachnoe chislo\n"); scanf("%d", &n); a=n%10; //последняя цифра числа b=n/10%10; // вторая цифра числа c=n/100; // третья цифра числа if (a%2==0) z++; if (b%2==0) z++; if (c%2==0) z++; printf("V chisle %d kol-vo chetnih cifr %d\n", n, z); return 0; } Задание 1: Выполнить пример 1, пример 2, пример 3 и пример 4, при-

веденный в методических рекомендациях.

Задание 2: Написать программу (используя инструкцию if), которая запрашивает у пользователя номер дня недели и выводит одно из сообще-ний: "Рабочий день", "Суббота" или "Воскресенье".

Задание 3: Написать программу, в которой вводятся три вещест-венных числа и находиться минимальное и максимальное значение среди этих трех чисел.

Инструкция switch.

Вариант 1:

switch ( выражение ) {

case константа1: оператор1; break; case константа2: оператор2; break; case константа N: операторы; break; default: оператор; break;

} Вариант 2: switch ( выражение ) {

case константа1: оператор1; break; case константа2: оператор2; break;

Page 250: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

250

case константа N: операторы; break;

} □ инструкция switch предназначена для выбора одного из нескольких

возможных направлений дальнейшего хода программы; □ выбор последовательности инструкций осуществляется в зависимо-

сти от равенства значения переменной-селектора константе, указанной после слова case;

□ если значение переменной-селектора не равно ни одной из констант, записанных после case, то выполняются инструкции, расположенные после слова default;

□ в качестве переменной-селектора можно использовать переменную целого (int) или символьного (char) типа.

Пример 5. Требуется вывести на экран оценку, введенную цифрой, пропи-сью.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int rez; printf("Vvedite ocenku\n"); scanf("%d", &rez); switch (rez) { case 5: printf("Ocenka - otlichno.\n"); break; case 4: printf("Ocenka - horosho.\n"); break; case 3: printf("Ocenks - udovletvoritelno.\n"); break; case 2: printf("Ocenka - ne udovletvoritelno.\n");

break; default: printf("Nevernoe znachenie.\n"); } return 0; } Задание 4: Выполнить пример 5, приведенный в методических реко-

мендациях.

Задание 5: Напишите программу (используя инструкцию switch), ко-торая запрашивает у пользователя номер дня недели, затем выводит на-звание дня недели или сообщение об ошибке, если введены неверные данные.

Индивидуальное задание

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

Page 251: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

251

Задания 1 (использовать оператор if): Вариант 1: Известны два расстояния: одно в километрах, другое – в фу-

тах (1 фут = 0,45 м). Какое из расстояний меньше, а какое больше?

Вариант 2: Даны радиус круга и сторона квадрата. У какой фигуры площадь больше?

Вариант 3: Даны объемы и массы двух тел из разных материалов. Ма-териал какого из тел имеет большую плотность?

Вариант 4: Вводиться трехзначное число. Определить кратна ли трем сумма его цифр.

Вариант 5: Вводиться натуральное трехзначное число n. Выяснить, верно ли, что это число содержит ровно две одинаковые цифры.

Вариант 6: Вводиться трехзначное число. Определить какая из его цифр больше: первая, вторая или третья.

Вариант 7: Вводиться натуральное трехзначное число n. Выяснить, различны ли все три цифры этого числа.

Вариант 8: Вводиться трехзначное число. Определить больше ли числа а сумма его цифр. Число а вводиться с клавиатуры.

Вариант 9: Вводиться натуральное число. а) Верно ли, что оно закан-чивается четной цифрой? б) Верно ли, что оно заканчивает-ся нечетной цифрой?

Вариант 10: Вводиться трехзначное число. Определить, равен ли квад-рат этого числа сумме кубов его цифр.

Вариант 11: Вводиться трехзначное число. Определить входит ли и него цифра а. Число а вводиться с клавиатуры.

Вариант 12: Определить, является ли треугольник со сторонами а, b, c равнобедренным. Стороны треугольника вводятся с клавиа-туры.

Вариант 13: Вводиться трехзначное число. Определить одинаковы ли его цифры.

Вариант 14: Вводиться натуральное трехзначное число n. Выяснить, яв-ляется ли оно палиндромом ("перевертышем"). Палиндро-мом называется число, десятичная запись которого читается одинаково слева направо и справа налево.

Вариант 15: Вводиться трехзначное число. Определить кратна ли сумма его цифр числу а. Число а вводиться с клавиатуры.

Page 252: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

252

Задания 2 (использовать оператор switch):

Вариант 1: По номеру месяца напечатать его название. Вариант 2: По номеру месяца напечатать пору года. Вариант 3: Описать список времен года: 1 - лето, 2 - осень, 3 - зима, 4 -

весна. По введенному значению времени года перечисляла все месяца этого сезона.

Вариант 4: Составить программу, которая бы по названию месяца (1 – январь, 2 – февраль, 3 – март и т.д.) выдавала бы количество дней в месяце.

Вариант 5: Составить программу, которая бы по введенному времени года (1 – зима, 2 – весна, 3 – лето, 4 – осень) выдавала бы на-звание месяцев, относящихся к нему.

Вариант 6: Дан список дисциплин, изучаемых в БГУИР и отчетность по ним. Составить программу, которая бы по названию дисцип-лины выдавала бы отчетность по нему. 1 - Информатика (экзамен, зачет) 2 - Культурология (зачет) 3 - Математика (экзамен, зачет) 4 - Иностранный язык (экзамен, зачет) 5 - Экономика(экзамен)

Вариант 7: Дан список дисциплин, изучаемых в БГУИР и номер семест-ра, когда они изучаются. Составить программу, которая бы по номеру семестра выдавала бы список изучаемых дисцип-лин. 1 - Информатика-2,1 2 - Культурология-3,4 3 - Математика-4,3 4 - Ин.язык-4,1,2,3

Вариант 8: Составить программу, которая бы с помощью оператора CASE реализовала бы все возможные операции над двумя целыми числами. (1 – сложение, 2 – вычитание, 3 – остаток от деления, 4 – целая часть от деления).

Вариант 9: Составить программу, которая бы выдавала по названию страны название столицы этой страны (использовать не ме-нее 6-7 названий: 1 – Беларусь, 2 – Россия и т.д.).

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

Page 253: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

253

Вариант 11: Составить программу, которая бы по введенному названию страны выдавала название ее континента (использовать не менее 6-7 названий: 1 – Беларусь, 2 – Россия и т.д.).

Вариант 12: Составить программу, которая бы по значению переменной Х, означающему некоторую длину в следующих единицах измерения: 1 – дециметр, 2 –километр, 3 – метр, 4 – милли-метр, 5 – сантиметр, выдавала бы эту длину в метрах.

Вариант 13: Составить программу, которая реализовала бы следующие действия: по введенному числу К (до 10) выдавала бы соот-ветствующую ей римскую цифру.

Вариант 14: Для целого числа К от 1 до 9 напечатать фразу "мне К лет", учитывая при этом, что при некоторых значениях К слово "лет" надо заменить на слово "год" или"года"

Вариант 15: Для натурального числа К напечатать фразу "мы нашли К грибов в лесу", согласовав окончание слова "гриб" с числом К.

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

ОПЕРАТОРЫ ЦИКЛА (for и while)

Теоретическая часть

Оператор for. Синтаксис оператора for имеет следующий вид:

for ( Инициализация; УсловиеВыполнения; Изменение ) {

// Здесь операторы цикла (тело цикла) ) }

где Иициализация — оператор инициализации счетчика циклов. УсловиеВыполнения — выражение, значение которого определяет условие

выполнения операций цикла; операторы, входящие в цикл, выполняются до тех пор, пока УсловиеВыполнения истинно, т. е. не равно нулю.

Изменение — оператор изменения параметра цикла; Как правило, этот оператор изменяет значение переменной, которая входит в УсловиеВыполне-ния.

Оператор for используется для организации циклов с фиксированным, известным во время разработки программы, числом повторений. Количество повторений цикла определяется начальным значением переменной-счетчика и условием завершения цикла. Переменная-счетчик должна быть целого (int) типа и может быть объявлена непосредственно в операторе цикла.

Page 254: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

254

Пример 1. Программа выводит на экран числа от 1 до 10.

#include <stdio.h> void main() { int counter; for (counter=1; counter<=10; counter++) printf("%d\n", counter); }

Пример 2: Написать программу, которая выводит таблицу квадратов первых n целых положительных четных чисел. Количество чисел должно вво-диться во время работы программы.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n,i; printf("Vvedite n "); scanf("%d",&n); for(i=2;i<=n;i+=2) printf(" %d %d\n",i,i*i); }

Пример 3: Написать программу, которая суммирует последовательность n целых чисел. Количество чисел n и целые числа вводятся с клавиатуры.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n,i,s=0,ch; //с помощью цикла for printf("Vvedite kolichestvo chisel: "); scanf("%d",&n); printf("Vvedite chisla: "); for(i=1;i<=n;i++) { scanf("%d",&ch); s+=ch; } printf("Summa ravna %d\n", s); }

Задание 1. Выполнить пример 1 и пример 2, приведенные выше.

Задание 2. Написать программу, которая вычисляет и выводит сред-нее значение для n целых чисел. Количество суммируемых чисел должно вво-диться во время работы программы. Для решения задачи использовать цикл for.

Page 255: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

255

Задание 3. Написать программу, которая вычисляет факториалы це-лых чисел от 1 до n, где n вводиться во время выполнения программы. Фак-ториал положительного целого числа n (записывается n!) равен произведе-нию положительных целых чисел от 1 до n. Для решения задачи использо-вать цикл for.

Оператор while. Синтаксис оператора while имеет следующий вид:

while ( УсловиеВыполнения ) { // Операторы цикла (тело цикла)

}

Сначала проверяется значение выражения УсловиеВылолнения Если оно не равно нулю, т.е. условие истинно, то выполняются операторы цикла, т.е. выполняется тело цикла. Затем снова проверяется значение выражения УсловиеВыполнения, и если оно не равно нулю, операторы цикла выполняют-ся еще раз. И так до тех пор, пока значение выражения УсловиеВыполнения не станет равным нулю.

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

нения программы. - оператор цикла while выполняются до тех пор, пока значение выра-

жения, записанного после слова while, не станет ложным (равным нулю). - после слова while надо записывать условие выполнения оператор

цикла. - для завершения цикла while в теле цикла обязательно должны быть

операторы, выполнение которых влияет на условие завершения цикла. Цикл while — это цикл с предусловием, т. е. возможна ситуация, при

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

Пример 4: Программа выводит на экран числа от 1 до 10.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int counter =1; /* инициализация */ while (counter <= 10) /*условие повторения*/ { printf("%d\n", counter); ++counter; /* приращение */ }

Page 256: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

256

} Пример 5: Напишите программу, которая суммирует последователь-

ность n целых чисел. Количество чисел n и целые числа вводятся с клавиату-ры.

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { nt n,i,s=0,ch; printf("Vvedite kolichestvo chisel:"); scanf("%d",&n); i=1; s=0; printf("Vvedite chisla: "); while(i<=n) { scanf("%d",&ch); s+=ch; i++; } printf("Summa ravna %d\n", s); }

Задание 4: Выполнить пример 4 и пример 5, приведенный в методиче-ских рекомендациях.

Задание 5: Напишите программу, которая вычисляет и выводит сред-нее значение для n целых чисел. Количество суммируемых чисел должно вво-диться во время работы программы. Для решения задачи использовать цикл while.

Задание 6: Напишите программу, которая вычисляет факториалы це-лых чисел от 1 до n. n вводиться во время выполнения программы. Фактори-ал положительного целого числа n (записывается n! и произносится «n факториал») равен произведению положительных целых чисел от 1 до n. Для решения задачи использовать цикл while.

Индивидуальное задание Задания 1: Написать программу для решения задачи в соответствии с

вариантом. Решить задачу двумя способами: используя цикл for и цикл while.

Вариант 1: Дана последовательность ai=i2, номера её первого и последне-го членов 1 и n. Найдите сумму S и произведение P тех её членов, номера которых являются нечетными.

Вариант 2: Дана последовательность ai=i2, номера её первого и последне-го членов 1 и n. Найдите сумму S и произведение P тех её

Page 257: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

257

членов, номера которых являются четными. Вариант 3: Дана последовательность ai=i2, номера её первого и последне-

го членов 1 и n. Найдите сумму S и произведение P тех её членов, номера которых являются кратными 3.

Вариант 4: Дана последовательность an=n sin n найдите сумму членов, номера которых записываются двузначными числами.

Вариант 5: Дана последовательность an=n sin n найдите сумму положи-тельных членов из первых 100 членов.

Вариант 6: Дана последовательность an=n sin n найдите сумму тех из пер-вых 100 членов, модули которых меньше 0,5.

Вариант 7: Найти значение выражения (для натуральных m и n, m<n) A=m+(m+1)+...+(m+n)

Вариант 8: Найти значение выражения ( для натуральных m и n, m<n) B=m*(m+1)*...*(m+n)

Вариант 9: Найти сумму квадратов четных чисел из первых n натураль-ных чисел.

Вариант 10: Найти значение выражения (для натурального числа n) S=1+1*2+1*2*3+1*2*3*4+...+1*2*3*...*n.

Вариант 11: Найти значение выражения (для натурального числа n) S=1+2+...+n.

Вариант 12: Найти сумму кубов первых n натуральных чисел. Вариант 13: Найти значение выражения (для натурального числа n)

F=1*2*...*n Вариант 14: Найти значение выражения (для натурального числа n)

Y=1+1/2+1/3+...+1/n Вариант 15: Найти значение выражения (для натуральных m и n, m<n)

X=1/m+1/(m+1)+...+1/(m+n)

Задания 2: Написать программу для решения задачи в соответствии с вариантом. Решить задачу двумя способами: используя цикл for и цикл while.

Вариант 1: Даны натуральное число n и вещественные числа а1, а2, …, an. Определить среднее арифметическое вещественных чисел.

Вариант 2: Известна масса каждого из 12 предметов. Определить общую массу всего набора предметов.

Вариант 3: Даны натуральное число n и числа а1, а2, …, an. Определить сумму положительных среди чисел а1, а2, …, an.

Вариант 4: Известен возраст (в годах в виде 14,5 лет и т. п.) каждого уче-ника класса. Определить средний возраст учеников класса.

Page 258: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

258

Количество учеников в классе вводится с клавиатуры. Вариант 5: Даны натуральное число n и числа а1, а2, …, an. Определить

сумму четных среди чисел а1, а2, …, an. Вариант 6: Известна масса каждого предмета из некоторого набора пред-

метов. Определить среднюю массу. Количество предметов вводиться с клавиатуры.

Вариант 7: Даны натуральное число n и вещественные числа а1, а2, …, an.Определить сумму квадратов отрицательных вещественных чисел.

Вариант 8: Найти сумму целых положительных чисел от a до b и кратных 3 (значения а и b вводятся с клавиатуры; b > а).

Вариант 9: Даны натуральное число n и числа а1, а2, …, an. Определить сумму чисел кратных 3 среди чисел а1, а2, …, an.

Вариант 10: Найти среднее арифметическое целых положительных чисел от a до b и кратных 5 (значения а и b вводятся с клавиатуры; b > а).

Вариант 11: Даны натуральное число n и числа а1, а2, …, an.Определить сумму и произведение модулей чисел а1, а2, …, an.

Вариант 12: Найти среднее арифметическое целых положительных нечет-ных чисел от 1 до n (значение n вводится с клавиатуры).

Вариант 13: Найти сумму квадратов всех четных целых чисел от а до 50 (значение а вводится с клавиатуры; 0 < а < 50).

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

Вариант 15: Найти сумму целых положительных чисел от 1 до n, кратных 3 (значение n вводится с клавиатуры).

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

ОПЕРАТОРЫ ЦИКЛА (do…while)

Теоретическая часть

Оператор do…while. Синтаксис оператора do…while имеет следую-щий вид:

do {

// Инструкции цикла (тело цикла) } while ( УсловиеПовторения ) ;

Page 259: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

259

Сначала выполняются инструкции цикла (тело цикла), затем проверяет-ся значение выражения УсловиеПовторения, и если условие истинно, не равно нулю, то инструкции цикла выполняются еще раз. И так до тех пор, пока УсловиеПовторения не станет ложным, т. е. равным нулю.

· число повторений инструкций цикла do…while определяется ходом выполнения программы;

· инструкции цикла do…while выполняются до тех пор, пока зна-чение выражения, записанного после слова while, не станет ложным (равным нулю);

· после слова while надо записывать условие выполнения инструк-ций цикла;

· для завершения цикла do…while в теле цикла обязательно долж-ны быть инструкции, выполнение которых влияет на условие завершения цикла;

· цикл do…while — это цикл с постусловием, т. е. инструкции тела цикла будут выполнены хотя бы один раз;

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

Пример 1. В программе структура do…while используется для вывода чи-сел от 1 до 10. Обратите внимание, что к управляющей переменной counter при проверке условия продолжения цикла применяется операция преинкремента. Об-ратите также внимание на фигурные скобки, заключающие тело структуры do/while (состоящее из одного оператора) подсчитать разность.

#include <stdio.h> void main () {

int counter = 1; do {

printf("%d ", counter); } while (++counter <= 10);

}

Задание 1: Выполнить пример 1, приведенный в методических реко-мендациях.

Задание 2: Напишите программу, которая вычисляет факториалы це-лых чисел от 1 до n. n вводиться во время выполнения программы. Факто-риал положительного целого числа n (записывается n! и произносится «n факториал») равен произведению положительных целых чисел от 1 до n. Для решения задачи использовать цикл do…while.

Page 260: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

260

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

#include "stdafx.h" #include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n,a,b; while(1) { //бесконечный цикл, условие цикла всегда верно do{ printf("Menu: \n"); printf("1 - podschet summi dvuh chisel (+)\n"); printf("2 - podschet raznosti dvuh chisel (-)\n"); printf("3 - exit\n"); scanf("%d",&n); }while (n<0&&n>3); switch (n) { case 1: printf("Vvedite 2 chisla\n "); scanf("%d%d", &a, &b); printf("Summa ravna %d\n ", a+b); break; case 2: printf("Vvedite 2 chisla\n "); scanf("%d%d", &a, &b); printf("Raznost ravna %d\n ", a-b); break; case 3: return 0; break; } }

}

Задание 3: Выполнить пример 2, приведенный в методических реко-мендациях.

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

10 8 11 7 9 9999 указывающая, что должно быть вычислено среднее для всех значений, предшест-вующих 9999.

#include "stdafx.h"

Page 261: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

261

#include "stdio.h" int _tmain(int argc, _TCHAR* argv[]) { int n,i=0,s=0; printf("Vvedite chislo (ili 9999 dlya prekrasheniya vvoda):"); do{ scanf("%d",&n); if (n!=9999) { s+=n; i++; } }while (n!=9999); printf("Srednee posledovatelnosti = %f\n ", (float)s/i);

}

Индивидуальное задание

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

1) Вычисление факториала; 2) Вычисление среднего значения введенной последовательности це-лых чисел (ввод чисел заканчивается вводом контрольного значе-ния);

3) Индивидуальное задание в соответствии с вариантом; 4) Выход. Задание 1: Написать программу в соответствии с вариантом. Для ре-

шения использовать цикл do…while. Ввод последовательности данных дол-жен заканчиваться вводом контрольного значения.

Вариант 1 Известна масса каждого груза загруженного в автомобиль. Выяснить не превысила ли общая масса всех грузов грузо-подъемность автомобиля.

Вариант 2 Известно число жителей, проживающих в каждом доме ули-цы. Нумерация домов проведена подряд. Дома с нечетными номерами расположены на одной стороне улицы, с четными - на другой. На какой стороне улицы проживает больше жите-лей?

Page 262: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

262

Вариант 3 Известна стоимость каждого из восьми предметов в двух на-борах. Какой из наборов предметов более дешевый?

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

Вариант 5 Дана последовательность целых чисел. Определить является ли их сумма четным числом.

Вариант 6 Три группы студентов, в каждой из которых 20 человек, в сес-сию сдавали по три экзамена. Определить лучшую по средне-му баллу группу.

Вариант 7 Известны расстояния от Москвы до нескольких городов. Най-ти расстояние от Москвы до самого удаленного от нее города, из представленных в списке городов.

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

Вариант 9 Известны данные о количестве людей, живущих в квартире №1, в квартире №2 и т.д. В каком числе квартир проживает больше всего жильцов?

Вариант 10 Известны максимальные скорости каждой из 20 марок легко-вых автомобилей. Определить, какую максимальную скорость имеет самый быстрый автомобиль.

Вариант 11 Известен рост каждого человека из группы. На сколько рост самого высокого из них превышает рост самого низкого?

Вариант 12 Известно число учеников в каждом из 20 классов школы. На сколько численность самого большого (по числу учеников) класса превышает численность самого маленького класса?

Вариант 13 Известны оценки по химии каждого ученика класса. Опреде-лить количество пятерок и количество двоек.

Вариант 14 Дана последовательность ненулевых целых чисел. Опреде-лить, сколько раз в этой последовательности меняется знак. Например, в последовательности 10, -4, 12, 56, -4 знак меняет-ся 3 раза.

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

Page 263: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

263

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

ОДНОМЕРНЫЕ МАССИВЫ

Теоретическая часть

Массив — это сложный (составной, структурированный) тип данных, который характеризуется следующим:

- элементы массива имеют одинаковый тип в отличие от структур, поэтому каждый элемент массива занимает одинаковый объём памяти;

- массив располагается в оперативной памяти, а не на внешнем уст-ройстве, как файлы;

- элементы массива занимают подряд идущие ячейки, в отличие, на-пример, от списков.

Объявление массива должно содержать три аргумента: ­ тип каждого элемента; ­ название массива; ­ число элементов в массиве.

Общая форма для объявления массива имеет вид (т.е. массив объявля-ется так же, как и обычные переменные, но после имени следуют квадратные скобки, в которых указывается размер массива):

тип имя_массива[размер]; Размер – это константа или константное выражение, которая определя-

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

Массивы могут иметь одну или несколько размерностей. Одномерный массив имеет одну размерность, двумерный массив (матрица) – две раз-мерности (количество строк и столбцов). Три и более размерностей на прак-тике используются редко, так как такие массивы занимают большой объём оперативной памяти.

Примеры объявления массива: int a[20]; //целочисленный массив из 20 элементов float b[5][10]; // матрица вещественных чисел из 5 строк и 10 столбцов double с[10][10]; // квадратная матрица вещественных чисел

Доступ к элементам массива в языке Си осуществляется двумя спо-собами.

Page 264: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

264

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

Кроме того, в языке Си есть возможность обрабатывать массивы, ис-пользуя указатели (адреса), так как в С++ существует связь между массива-ми и указателями.

Примеры работы с элементами массива, используя индекс: a[3]=125; // присвоение значение 125 четвертому элементу массива tmp=a[3]; // присвоение значение элемента массива переменной tmp a[0]=a[3]; // присвоение значение эл-та массива другому эл-ту массиву int i=2, j=3; b[i][j]=5.5; // использование целочисленной переменной i и j для

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

Способы определения массивов. Рассмотрим два возмождных спосо-ба определения элементов массива:

1. Ввод элементов массива с клавиатуры или с заранее подготовленно-го файла.

Пример ввода с клавиатуры одномерного массива: printf("Vvedite elementi massiva"); for (i=0; i<n; i++) //n-количество элементов в массиве { printf(“a[%d]=”, i+1); scanf(“%d”, &a[i]); }

Обычно размер массива заранее неизвестен, поэтому при объявлении массива задается максимальная размерность, которая, как правило, известна. Реальная размерность n вводится и используется далее, например, в циклах и для других целей.

Второй способ. Значения элементов массива можно задать (проини-циализировать) во время объявления следующим образом:

тип имя [N]={список значений};

где в фигурных скобках записываются константы соответствующего типа, разделённые запятыми.

Пример инициализации одномерного массива:

Page 265: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

265

const N=5; float a[N]={-1.1, 22, 3, -4.4, 50};

При этом если в списке меньше чем N значений, то недостающие эле-менты массива примут нулевое значение. Наоборот, если указать больше N значений, “компилятору это не понравится”.

Пример 1. Программа запрашивает с клавиатуры десять чисел, а затем вы-водит их на эран в обратном порядке.

#include <stdio.h> #include <conio.h> void main () { int array[10], i; printf("Vvedite 10 chisel\n"); for (i = 0; i<10; i++) { printf("chislo %d: ", i+1); scanf("%d", &array[i]); } for (i = 9; i>=0; i--) printf("%d ", array[i]); printf("\n"); getch(); }

Задание 1. Выполнить пример 1, приведенный выше. Вывод одномерного массива. Простой вывод элементов небольшого

массива в одну строку экрана можно выполнить так:

printf("Massiv:"); for (i=0; i<n; i++) printf(“%d, ”, a[i]);

Подсчет суммы элементов одномерного массива. Алгоритм, нахож-дения суммы элементов одномерного массива заключается в следуещем:

- первоначально сумма принимается равная нулю, т.е. переменная, которая будет хранить сумму элементов, первоначально инициализируется нулем;

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

Пример нахождения суммы элементов одномерного массива: int sum=0; for (i=0; i<n; i++) //n-количество элементов в массиве sum+=a[i]; // аналогичная запись sum=sum+a[i] printf("Summa elementov massiva = %d", sum);

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

Page 266: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

266

#include <stdio.h> #include <conio.h> void main () { int array[10], i, sum=0; printf("Vvedite 10 chisel\n"); for (i = 0; i<10; i++) { printf("chislo %d: ", i+1); scanf("%d", &array[i]); }

for (i=0; i<10; i++) //n-количество элементов в массиве sum+=array[i]; printf("Summa 10 chisel = %d", sum);

getch(); }

Задание 2. Выполнить пример 3, приведенный выше.

Нахождение минимального (максимального) значения элемента одномерного массива. Алгоритм, нахождения минимального (максимально-го) значения элемента заключается в следующем:

- первоначально принимается за минимальное (максимальное) значе-ние первый элемент массива, т.е. переменная, которая будет хранить мини-мальное (максимальное) значение элементов массива, первоначально равна элементу с индексом 0;

- далее начинается перебор элементов массива и текущее минималь-ное (максимальное) значение сравнивается с текущим значением элемента, если текущее значение элемента массива меньше (больше) текущего мини-мального (максимального), то минимальное (максимальное) значение стано-виться равно текущему значению элемента массива.

Пример нахождения минимального значения элемента одномерного массива:

int min=a[0]; for (i=1; i<n; i++) //n-количество элементов в массиве if (min>a[i]) min=a[i]; printf("Minil'ni element massiva = %d", min);

Пример нахождения максимального элемента одномерного массива:

int max=a[0]; for (i=1; i<n; i++) //n-количество элементов в массиве if (max<a[i]) max=a[i]; printf("Maximal'ni element massiva = %d", max);

Пример 4. Программа запрашивает с клавиатуры десять чисел, а затем на-ходит среди них минимальный и максимальный элементы.

Page 267: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

267

#include <stdio.h> #include <conio.h> void main () { int array[10], i, sum=0, min, max; printf("Vvedite 10 chisel\n"); for (i = 0; i<10; i++) { printf("chislo %d:", i+1); scanf("%d", &array[i]); } min=array[0]; for (i=1; i<10; i++) if (min> array[i]) min= array[i]; printf("Minimal'ni element massiva = %d\n", min); max= array[0]; for (i=1; i<10; i++) if (max< array [i]) max= array [i]; printf("Maximal'ni element massiva = %d\n", max); getch(); }

Задание 3. Выполнить пример 3, приведенный выше.

Задание 4. Ввести массив вещественных чисел размером п, п вводить-ся с клавиатуры. Найти его наибольший и наименьший элементы и поме-нять их местами. Найти сумму и произведение всех элементов массива.

Задание 5: Ввести три массива (X, Y, Z) целых чисел по п элементов. На месте исходных массивов создать новые массивы по следующему прави-лу: последовательно рассматривая тройки Xi, Yi, Zi (где i=l,n), Xi следует присвоить наименьшее из этих значений, Zi - наибольшее, a Yi - среднее.

Индивидуальное задание

Написать программу на языке Си для решения задачи в соответствии с вариантом, заданным преподавателем.

Вариант 1: Известны длины участков пути (в км), которые проехали 10 легковых автомобилей, и время, затраченное каждым из них (в часах). Опре-делить минимальную из средних скоростей движения автомобилей на участ-ках.

Вариант 2: Известны данные о численности населения (в млн жителей) и площади (в млн кв. км) 10 государств. Определить общую численность го-сударств, чья площадь превышает 5 млн кв. км.

Page 268: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

268

Вариант 3: Известны данные о мощности двигателя (в л. с.) и стоимо-сти 30 легковых автомобилей. Определить общую стоимость автомобилей, у которых мощность двигателя превышает 100 л. с.

Вариант 4: Имеется информация о количестве осадков, выпавших за каждый день месяца, и о температуре воздуха в эти дни. Определить, какое количество осадков выпало в виде снега и какое — в виде дождя. (Считать, что идет дождь, если температура воздуха выше 0°.)

Вариант 5: Известны данные о численности населения (в миллионах жителей) и площади (в тысячах квадратных километров) 10 государств. Оп-ределить общую численность населения в "маленьких" государствах (чья площадь не превышает A тысяч квадратных километров, A – вводиться с кла-виатуры).

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

Вариант 7: Фирма имеет два магазина. Известен доход каждого мага-зина за каждый день февраля. Определить, в каком из магазинов общий до-ход за месяц меньше.

Вариант 8: Известны данные о массе (в кг) и объеме (в см3) 10-ти пред-метов, изготовленных из различных материалов. Определить максимальную плотность материала.

Вариант 9: Даны два массива из 10 однозначных чисел. В первом из них записано количество мячей, забитых футбольной командой в игре, во втором — количество пропущенных мячей в этой же игре. Для каждой про-веденной игры напечатать словесный результат "выигрыш", "ничья" или "проигрыш". Определить количество выигрышей, количество ничьих и коли-чество проигрышей данной команды.

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

Вариант 11: Даны два массива из 10 однозначных чисел. В первом из них записано количество мячей, забитых футбольной командой в игре, во втором — количество пропущенных мячей в этой же игре. Общее число оч-ков, набранных командой (за выигрыш дается 3 очка, за ничью — 1, за про-игрыш — 0).

Page 269: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

269

Вариант 12: Известны данные о вместимости (в мегабайтах) и стоимо-сти (в рублях) каждого из 10 типов жестких магнитных дисков (винчестеров). Напечатать вместимость тех винчестеров, которые стоят больше s рублей.

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

МНОГОМЕРНЫЕ МАССИВЫ

Теоретическая часть

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

Многомерные массивы объявляются точно так же, как и одномерные, только после имени массива ставится более одной пары квадратных скобок.

Пример объявления многомерных массивов:

double array[30][10]; // матрица с 30 строками и 10 столбцами int buffer[1][7]; // матрица с 1 строкой и 7 столбцами int bad1[0][5]; // ошибка: размерность не может быть нулевой int bad2[0][3][0]; // ошибка: размерность не может быть нулевой

Ввод с клавиатуры, вывод на экран и другие действия с матрицей, состоящей из n строк и m столбцов. Особых отличий работы с многомер-ными массивами от одномерных нет. При обращении к элементам многомер-ного массива необходимо указать все его индексы.

Пример ввода с клавиатуры элементов матрицы:

int i,j; float b[100][100]; for (i=0;i<n;i++) for (j=0;j<m;j++) { printf("Vvedite element [%d,%d]\n", i+1, j+1); scanf("%f",&b[i][j]); }

Пример вывода на экран элементов матрицы в табличной форме: int i,j; float b[100][100]; printf("MATRICA: \n"); for (i=0;i<n;i++) { for (j=0;j<m;j++) printf("%.2f", b[i][j]);

Page 270: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

270

printf("\n"); }

Пример нахождения суммы элементов матрицы:

int i,j; float b[100][100]; float s=0; for (i=0;i<n;i++) for (j=0;j<m;j++) s+=b[i][j] printf("Summa elementov matrici = %.2f\n", s);

Пример нахождения максимального элемента матрицы:

int i,j; float b[100][100]; float max=b[0][0]; for (i=0;i<n;i++) for (j=0;j<m;j++) if (b[i][j]>max) max=b[i][j]; printf("Max element matrici = %.2f\n", max);

Пример нахождения минимального элемента матрицы:

int i,j; float b[100][100]; float min=b[0][0]; for (i=0;i<n;i++) for (j=0;j<m;j++) if (b[i][j]<min) min=b[i][j]; printf("Min element matrici = %.2f\n", min);

Пример нахождения суммы каждой строки матрицы:

int i,j; float s; float b[100][100]; for (i=0;i<n;i++) { s=0; for (j=0;j<m;j++) s+=b[i][j]; printf("Summa elementov %d-stroki matrici = %.2f\n", i+1, s); }

Пример нахождения произведения каждого столбца матрицы:

int i,j; float p; float b[100][100]; for (j=0;j<m;j++) {

Page 271: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

271

p=1; for (i=0;i<n;i++) p*=b[i][j]; printf("Proizvedenie elementov %d-stolbca matrici = %.2f\n", j+1, p); }

Пример подсчета количества положительных элементов на глав-ной диагонали:

int i, j, kol=0; float b[100][100]; for (i=0;i<n;i++) { if (b[i][i]>0) kol++; } printf("Kol-vo pologitelnih elementov na glavnoi diagonali = %.d\n", kol);

Пример 1. Дана матрица вещественных чисел N х N. Количество строк и столбцов N задается пользователем. Подсчитать сумму элементов матрицы, найти минимальный и максимальный элементы матрицы, найти сумму каж-дой строки матрицы, произведение каждого столбца матрицы и количество положительных элементов на главной диагонали.

#include <stdio.h> #include <conio.h> void main () { int i,j, kol=0, n; float b[30][30], s=0, p, max, min; do{ printf(“Vvedite kol-vo strok i stolbcov matrici (<30)\n"); scanf("%d",&n); } while (n>=30); for (i=0;kn;i++) for (j=0;j<n;j++) { printf("Vvedite element [%d,%d]\n", i+1, j+1); scanf("%f",&b[i][j]); } for (i=0;i<n;i++) for (j=0;j<m;j++) s+=b[i][j] printf("Summa elementov matrici = %.2f\n", s); max=b[0][0]; for (i=0;i<n;i++) for (j=0;j<m;j++) if (b[i][j]>max) max=b[i][j];

Page 272: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

272

printf("Max element matrici = %.2f\n", max); min=b[0][0]; for (i=0;i<n;i++) for (j=0;j<m;j++) if (b[i][j]<min) min=b[i][j]; printf("Min element matrici = %.2f\n", min); for (i=0;i<n;i++) { s=0; for (j=0;j<m;j++) s+=b[i][j]; printf("Summa elementov %d-stroki matrici = %.2f\n", i+1, s); } for (j=0;j<m;j++) { p=1; for (i=0;i<n;i++) p*=b[i][j]; printf("Proizvedenie elementov %d-stolbca matrici = %.2f\n", j+1, p); } for (i=0;i<n;i++) { if (b[i][i]>0) kol++; } printf("Kol-vo pologitelnih elementov na glavnoi diagonali = %.d\n", kol); printf("MATRICA: \n"); for (i=0;i<n;i++) { for (j=0;j<m;j++) printf("%.2f", b[i][j]); printf("\n"); } }

Задание 1. Выполнить пример 1, приведенный выше.

Задание 2. Дана матрица вещественных чисел N х М. Количество строк N и столбцов М задается пользователем. Найти максимальный и ми-нимальный элемент в каждой строке и поменять их местами. Найти сумму элементов на главной диагонали.

Индивидуальное задание

Написать программу на языке Си для решения задачи в соответствии с вариантом.

Page 273: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

273

Вариант 1: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Определить сумму и количество нечет-ных элементов матрицы. Подсчитать произведение элементов каждого столбца. На экран выводится введенная матрица и вычисленная сумма и ко-личество.

Вариант 2: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Найти минимальный и максимальный элемент матрицы. Подсчитать количество элементов, которые больше разно-сти максимального и минимального элементов.

Вариант 3: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Определить сумму и количество поло-жительных элементов матрицы. Подсчитать произведение элементов каждой строки. На экран выводится введенная матрица и вычисленная сумма и коли-чество.

Вариант 4: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Заменить нулями отрицательные эле-менты матрицы и подсчитать количество таких замен. Подсчитать произве-дение элементов каждой строки. На экран вывести исходную и преобразо-ванную матрицы.

Вариант 5: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Найти сумму всех чисел до первого нуля и его номер. Если нуля нет, вывести сумму всех чисел матрицы.

Вариант 6: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Найти количество положительных, от-рицательных и нулевых чисел.

Вариант 7: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Матрицу преобразовать следующим об-разом: все числа из отрезка [0,1] увеличить в 10 раз, отрицательные умень-шить в (–2) раза, остальные уменьшить в 10 раз.

Вариант 8: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Определить, есть ли нуль в матрице. Ес-ли есть, получить место расположения первого нуля. В противном случае вывести “нет нулей”.

Вариант 9: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. В матрице найти среднеарифметическое значение среди положительных чисел.

Page 274: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

274

Вариант 10: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. В матрице найти отрицательное наи-большее число, его номер, положительное наименьшее число и его номер. Определить все номера, если таких чисел несколько.

Вариант 11: Дана матрица целых чисел N x M. Количество строк N и столбцов M задается пользователем. Преобразовать матрицу следующим об-разом: числа, кратные 5, но не кратные 10, уменьшить в 5 раз; числа, кратные 10, уменьшить в 10 раз; остальные увеличить в 10 раз. Дополнительный мас-сив не формировать.

Вариант 12: Дана матрица целых чисел N x N. Количество строк и столбцов N задается пользователем. Найти наименьший и наибольший эле-менты, стоящие на главной диагонали и поменять их местами. Подсчитать количество элементов, которые больше разности максимального и мини-мального элементов главной диагонали.

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

ФУНКЦИИ

Теоретическая часть Большинство компьютерных программ, решающих реальные практиче-

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

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

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

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

Page 275: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

275

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

Функция активизируется (т. е. начинает выполнять запроектирован-ную для нее задачу) путем вызова функции. В вызове функции указывается ее имя и дается информация (в виде аргументов), необходимая вызываемой функции для ее работы. Это аналогично иерархической форме управления. Начальник (вызывающая функция или вызывающий оператор) просит под-чиненного (вызываемую функцию) выполнить задание и возвратить (т.е. со-общить) результаты после того, как задание выполнено. Функция-начальник не знает, как функция-подчиненный выполняет порученное ей задание. Под-чиненный может вызвать другие подчиненные функции, причем начальник не будет осведомлен об этом. Далее увидим, как это «скрытие» деталей вы-полнения способствует разработке хорошего программного обеспечения. На рис. 1 показана функция main, иерархически связанная с несколькими рабо-чими функциями. Заметим, что workerl действует как функция начальника по отношению к worker4 и worker5. Взаимоотношения между функциями могут отличаться от показанных на этом рисунке иерархических отношений.

Рис. 1. Иерархическое взаимоотношение функция-начальник / функ-

ция-подчиненный Математические библиотечные функции. Математические библио-

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

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

Page 276: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

276

printf("Koren’ kvadratni = %.2f", sqrt(900.0));

При выполнении этого оператора вызывается математическая библио-течная функция sqrt, которая вычисляет квадратный корень из числа, заклю-ченного в круглые скобки (900.0). Число 900.0 является аргументом функции sqrt. Приведенный выше оператор должен был бы напечатать 30.00. Функция sqrt получает аргумент типа double и возвращает результат типа double. Во-обще все функции в математической библиотеке возвращают данные типа double.

При использовании функций математической библиотеки необходимо включать соответствующий заголовочный файл с помощью директивы пре-процессора #include<math.h>.

Аргументами функции могут быть константы, переменные или выра-жения. Если cl = 13.0, d = 3.0 и f = 4.0, то оператор

printf("Koren’ kvadratni = %.2f", sqrt(cl + d*f));

вычислит и напечатает квадратный корень из (13.0 + 3.0 * 4.0) = 25.0, а имен-но, напечатает 5.00. Некоторые математические библиотечные функции при-ведены в таблице 1, где переменные х и у имеют тип double.

Таблица 1. Наиболее употребительные математические библиотечные функции

Функция Описание Пример sqrt(x) Корень квадратный из х sqrt(900.0)=30.0

sqrt(9.0)=3.0 exp(x) Экспоненциальная функция

ex exp(1.0)=2.718282 exp(2.0)=7.389056

log(x) Логарифм натурального чис-ла х (по основанию е)

log(2.718282)=1.0 log(7.389056)=2.0

log10(x) Логарифм натурального чис-ла х (по основанию 10)

log10(1.0)=0.0 log10(10.0)=1.0 log10(100.0)=2.0

fabs(x) Абсолютное значение х Есхи x>0, то fabs(x)=х Есхи x=0, то fabs(x)=0.0 Есхи x<0, то fabs(x)=-х

ceil(x) Округление х до наименьше-го целого, не меньшего чем х

ceil(9.2)=10.0 ceil(-9.8)=-9.0

floor(x) Округление х до наибольше-го целого, не большего чем х

floor(9.2)=9.0 floor(-9.8)=-10.0

pow(x,y) Возведение х в степени у pow(2,7)=128.0 pow(9,0.5)=3.0

fmod(x,y) Остаток от х/у, как число с плавающей точкой

fmod(13.657,2.333)=1.992

Page 277: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

277

sin(x) Синус х (х в радианах) sin(0.0)=1.0 cos(x) Косинус х (х в радианах) cos(0.0)=1.0 tan(x) Тангенс х (х в радианах) tan(0.0)=0.0

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

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

Существует несколько причин для построения программ на основе функций. Подход «разделяй и властвуй» делает разработку программ более управляемой. Другая причина — повторное использование программных ко-дов, т.е. использование существующих функций как стандартных блоков для создания новых программ. Повторное использование — основной фактор развития объектно-ориентированного программирования. При продуманном присвоении имен функций и хорошем их описании программа может быть создана быстрее из стандартизированных функций, соответствующих опре-деленным задачам. Третья причина — желание избежать в программе повто-рения каких-то фрагментов. Код, оформленный в виде функции, может быть выполнен в разных местах программы простым вызовом этой функции.

Определения функций. Каждая программа, которая рассматривалась выше, содержала функцию, называемую main, которая вызывает стандарт-ные библиотечные функции для выполнения соответствующих им задач. Рассмотрим, как программисты пишут свои собственные необходимые им функции. Рассмотрим программу, которая использует функцию square для вычисления квадратов целых чисел от 1 до 10 (пример 1). Функция square активизируется или вызывается в main вызовом square(х).

Функция создает копию значения х в параметре у. Затем square вычис-ляет у * у. Результат передается в ту точку main, из которой была вызвана square, и затем этот результат выводится на экран. Благодаря структуре по-вторения for этот процесс повторяется десять раз.

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

Page 278: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

278

указывает, что square возвращает целый результат. Оператор return в square передает результат вычислений обратно в вызывающую функцию.

Пример 1. Программа функции для вычисления квадрата числа.

// функция square, определяемая программистом #include <stdio.h> int square(int); // прототип функции main {

for (int x = 1; x <= 10; x++) printf(" %d\n ", square(x));

return 0; } // описание функции int square(int y) { return у * у; }

Задание 1. Выполнить пример 1, приведенный выше.

Строка

int square(int);

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

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

тип-возвращаемого-значения имя-функции (список-параметров) {

объявления и операторы; }

Имя-функции — это любой правильно написанный идентификатор. Тип-возвращаемого-значения — это тип данных результата, возвращаемого из функции оператору ее вызова. Тип возвращаемого значения void указыва-ет, что функция не возвращает никакого значения. Компилятор предполагает тип int для неопределенного типа возвращаемого значения.

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

Page 279: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

279

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

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

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

Список-параметров — это список разделенных запятыми объявлений тех параметров, которые получает функция при ее вызове. Если функция не получает никаких значений, список-параметров задается как void. Тип дол-жен быть указан явно для каждого параметра в списке параметров. Объявле-ние параметров функции, имеющих одинаковый тип, в виде float x, у вместо float x, float у. Объявление параметра float x, у вызовет ошибку компиляции, так как типы надо указывать для каждого параметра в списке.

Повторное определение параметра функции как локальной переменной этой функции является синтаксической ошибкой.

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

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

Описание функции внутри другой функции является синтаксической ошибкой.

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

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

Page 280: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

280

ление возвращается или при достижении правой фигурной скобки, завер-шающей функцию, или при выполнении оператора

return;

Если функция должна возвращать результат, то оператор

return выражение;

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

maximum для определения и возвращения наибольшего из трех целых чисел. Вводятся три целых числа. Затем эти целые числа передаются функции max-imum, которая определяет наибольшее из чисел. Это значение возвращается функции main с помощью оператора return в maximum и печатается.

Пример 2. Программа функции для определения максимального из трех чисел.

// Определение максимального из трех целых чисел #include <stdio.h> int maximum(int, int, int); // прототип функции main () { int a, b, c; printf("Vvedite 3 chisla: "); scanf("%d%d%d", &a, &b, &c); printf("Maxsimum = %d", maximum(a, b, c)); return 0; } // Определение функции maximum int maximum(int x, int y, int z) { int max=x; if (y > max) max = y; if (z > max) max = z; return max; }

Задание 2. Выполнить пример 2, приведенный выше.

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

Page 281: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

281

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

Прототип функции maximum в примере 2 имеет вид:

int maximum(int, int, int);

Этот прототип указывает, что maximum имеет три аргумента типа int и воз-вращает результат типа int. Заметим, что прототип функции такой же, как за-головок описания функции maximum, за исключением того, что в него не включены имена параметров (х, у и z).

Отсутствие точки с запятой в конце прототипа функции является син-таксической ошибкой.

Вызов функции, который не соответствует прототипу функции, ведет к синтаксической ошибке. Синтаксическая ошибка возникает также в случае отсутствия согласования между прототипом и описанием функции. Напри-мер, если бы в примере 2 прототип функции был бы написан так:

void maximum(int, int, int);

компилятор сообщил бы об ошибке, потому что возвращаемый тип void в прототипе функции отличался бы от возвращаемого типа int в заголовке функции.

Другой важной особенностью прототипов функций является приведе-ние типов аргументов, т.е. задание аргументам подходящего типа. Напри-мер, математическая библиотечная функция sqrt может быть вызвана с аргу-ментом целого типа, даже если функция прототип в math.h определяет аргу-мент типа double, и при этом функция будет работать правильно. Оператор

printf("Koren’ kvadratni = %.2f", sqrt(4));

правильно вычисляет sqrt(4), и печатает значение 2.00. Прототип функции за-ставляет компилятор преобразовать целое значение 4 в значение 4.0 типа double прежде, чем значение будет передано в sqrt. Вообще, значения аргу-ментов, которые первоначально не соответствуют типам параметров в прото-типе функции, преобразуются в подходящий тип перед вызовом функции. Эти преобразования могут привести к неверным результатам, если не руко-водствоваться правилами приведения типов Cи. Правила приведения опреде-ляют, как типы могут быть преобразованы в другие типы без потерь. В при-веденном выше примере sqrt тип int автоматически преобразуется в double без изменения его значений. Однако double преобразуется в int с отбрасыва-нием дробной части значения double. Преобразование больших целых типов

Page 282: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

282

в малые целые типы (например, long в short) может также привести к изме-нению значений.

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

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

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

#include<stdio.h> #include<ctype.h> #include<string.h> int menu(); // Прототип функции menu. int sum(int aa, int bb); // Прототип функции sum void kol(char *s); // Прототип функции kol void main() { int a,b,c=0,k1=0; char s1[20]; while(1) { //вызов функции menu switch(menu()) //условное выражение в операторе switch - { //это значение, которое возвращет функция menu. case 1: printf("vvedite a i b: "); scanf("%d%d",&a,&b); c=sum(a,b); //вызов функции sum printf("\nSum= %d\n",c); break; case 2: fflush(stdin); printf("vvedite ctroku: \n"); gets(s1); kol(s1); //вызов функции kol break; case 3: return; //Выполнение функции завершается после выполнения оператора return } } } int menu() //определение функции menu {

Page 283: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

283

int ch; do { printf("\n Menu: \n"); printf("1. Podschitat' summu chisel: \n"); printf("2. Podschitat' kolichestvo simvolov v stroke: \n"); printf("3. Exit\n"); printf("\t Vash vibor: "); scanf("%d",&ch); }while(ch>3); return ch; } int sum(int aa, int bb) //определение функции sum { return aa+bb; } void kol(char *s) //определение функции kol { printf("Dlina=%d", strlen(s)); }

Функция menu выводит на экран 5 строк меню, и считывает введенное пользователем значение. Никаких параметров функции не передается, функ-ция возвращает целочисленное значение - введеное пользователем значение

Функция sum подсчитвывает сумму двух чисел. Функции передаются 2 целочисленных параметра - складываемые числа, функция возвращает цело-численный параметр - сумму двух чискл.

Функция kol подсчитвывает и выводит на экран длину строки. Функ-ции передается введенная пользователем строка, функция ничего не возвра-щает.

Задание 3. Выполнить пример 3, приведенный выше.

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

Можно использовать три варианта описания массива, поступающего в функцию, в качестве параметра.

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

Пример 4. Элементы матрицы равны произведению номера столбца на номер строки. Подсчитать сумму элементов матрицы.

#include <stdio.h> int sum(int x[5]) // определение функции, размер указан

Page 284: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

284

{ int res=0; for(int i=0; i<5; i++) res+=x[i]; return res; } void main() { int mas[3][5], i, j; for(i=0; i<3; i++) for(j=0; j<5; j++) mas[i][j]=i*j; for(i=0; i<3; i++) printf(“\n res=%d”, sum(mas[i])); }

Прототип функции sum может быть записан одним из следующих спо-собов:

int sum(int x[]); int sum(int *); int sum(int []);

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

В этом случае Си автоматически преобразует mas[i] к указателю на це-лый тип, и в функцию передается адрес первого элемента каждой строки матрицы, т.е. адрес элемента mas[i][0]. В функции вычисляется сумма эле-ментов каждой строки матрицы и сумма выводится на экран.

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

int sum(int x[]) // определение функции, размер не указан { int res=0; for(int i=0; i<5; i++) // i<5 - известно программисту res+=x[i]; return res; } // Вызов функции остается тем же

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

Пример 5. Элементы матрицы равны произведению номера столбца на номер строки. Подсчитать сумму элементов матрицы.

Page 285: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

285

#include <stdio.h> int sum(int *x) // определение функции { int res=0; for(int i=0; i<5; i++) res+=*x++; // можно и res+=x[i] return res; } void main() { int mas[3][5], i, j; for(i=0; i<3; i++) for(j=0; j<5; j++) mas[i][j]=i*j; for(i=0; i<3; i++) printf(“\n res=%d”, sum(&mas[i][0])); }

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

Пример 6. Ввести матрицу n x m. Написать функцию, которая позволяет ввести матрицу и вывести ее на экран.

#include <stdio.h> #include <ctype.h> int x[50][50]; void vvod(int x[50][50], int n1,int m1); int vivod(int x[50][50], int n1, int m1); void main() { int n,m; printf("vvedite n\n"); scanf("%d",&n); printf("vvedite m\n"); scanf("%d",&m); vvod(x, n, m); vivod(x, n, m); } void vvod(int x[50][50], int n1, int m1) { int z,j; for (z=0;z<n1;z++) for (j=0;j<m1;j++){ printf("Vvedite element [%d,%d]\n", z+1, j+1); scanf("%d",&x[z][j]); } } int vivod(int x[50][50], int n1, int m1) { int z,j; printf("\n"); for (z=0;z<n1;z++){ for (j=0;j<m1;j++) printf("%d ", x[z][j]); printf("\n");

Page 286: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

286

} return 0; }

Задание 4. Выполнить пример 4 и пример 5, приведенные выше.

Задание 5. Создать программу, которая позволяет определить сумму всех элементов, минимальный и максимальный элемент n x m матрицы. По запросу с клавиатуры, программа выполняет следующие действия:

1) ввести новый массив; 2) выводит сумму элементов массива; 3) выводит минимальный элемент массива; 4) выводит максимальный элемент массива; 5) выход.

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

Индивидуальное задание

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

1. Простые проценты по ссуде рассчитываются по формуле:

interest = principal * rate * days / 365

В предыдущей формуле принимается, что rate является процентной ставкой за год и поэтому включает деление на 365 (дней). Разработать функцию на языке Си, в которой будут вводить значения principal, rate и days для не-скольких ссуд и будет вычислять и отображать на экране простые проценты по каждой ссуде, используя для этого предыдущую формулу.

Пример работы программы: Введите основную сумму ссуды: 1000.00 Введите процентную ставку: .1 Введите срок ссуды в днях: 365 Выплаты по простым процентам составляют $100.00

2. Написать функцию для определения общей зарплаты для каждого из нескольких служащих. Компания платит «обычную зарплату» за первые 40 часов, отработанных каждым служащим, и «полуторную зарплату» за все время, отработанное сверх 40 часов. Имеется список служащих компании,

Page 287: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

287

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

Пример работы программы: Введите количество отработанных часов (-1, если ввод закончен): 41 Введите почасовой тариф работника ($00.00): 10.00 Зарплата составляет $415.00

Задание 2. Дана матрица целых чисел NxM. Количество строк N и столбцов M задается пользователем. Создать программу, в которой реализу-ется:

1. Определить сумму и количество четных элементов матрицы. Подсчи-тать произведение элементов каждой строки. На экран выводится введенная матрица и вычисленная сумма и количество.

2. Найти минимальный и максимальный элемент матрицы. Подсчитать количество элементов, которые больше разности максимального и мини-мального элементов.

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

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

УКАЗАТЕЛИ

Теоретическая часть

Указатель – особый вид переменной, которая хранит адрес элемента памяти, где может быть записано значение другой переменной.

Определение указателя:

имя_типа *имя_переменной;

Например:

int var, *point;

Здесь var – целочисленная переменная, point указатель на целый тип. Символ * - звездочка определяет тип переменной point, как “указатель”.

Существует операция, неразрывно связанная с указателями. Это унарная операция – операция взятия адреса &. Результат операции & является адрес переменной в памяти. Результат имеет тип «указатель» на тип переменной.

Page 288: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

288

Операция & может использоваться практически со всеми типами данных, кроме констант и битовых полей. Например:

int var, *point; point = &var;

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

Вторая операция работы с указателями – это операция доступа по ука-зателю (разадресации) (*point). Результат операции – содержимое ячейки памяти, на которую указывает point.

Пример 1. В программе значение переменней изменяется, используя указа-тель на эту переменную.

#include<stdio.h> void main(void) { int *p, a=18; p=&a; printf(“a = %d = %d\n”, a, *p); printf(“адрес a = %d = %d\n”, &a, p); *p+=8; // a=26 printf(“a = %d = %d\n”, a, *p); }

Указятели могут участвовать в следующих операциях. Операция при-сваивания (если указатели разных типов, необходимо применить операцию приведения). Например:

int a=10, *p, *t; p=&a; t=p

Операции сложного присваивания (point+=i, point-=i). Операция увеличения (уменьшения) указателя (point+i; point-i; i- значе-

ние целочисленного типа). Результат операции (point+i) – “указатель”, опре-деляющий адрес i-го элемента после данного, а (point-i) – на i-ый элемент пе-ред данным.

Операция инкремента (декремента): point++; point--; ++point; --point. Указатель будет смещаться (увеличиваться или уменьшаться в зависимости от операции) на один элемент. Фактически указатель (адрес) измениться на количество байт, занимаемых этим элементом в памяти.

Page 289: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

289

Для операций увеличения (уменьшении) указателя справедливо, если объявлен:

type1 *pointer;

где type1 – некоторый тип, то операция pointer=pointer+i, где i- значение це-лочисленного типа, изменит pointer на sizeof(type1)*i байт. Например:

int a, *pi=&a; float f, *pf=&f; pi++; //смещение на 2 байта pf++; //смещение на 4 байта

Операция индексирования: point[i]. Эта операция полностью аналогич-на выражению *(point+i), т.е. извлекается из памяти и используется в выра-жении значение i-го элемента массива, адрес которого присвоен указателю point.

Операция вычитания: point1-point2 (операция имеет смысл только в том случае, если point1 и point2 указатели на один и тот же набор данных). Результат имеет тип int и равен количеству элементов, которые можно рас-положить между ячейками памяти, на которые указывают point1 и point2.

Операции отношения:

point1==point1; point1>=point2; point1>point2; point1<=point2; point1<point2; point1!=point1;

Также любой указатель (адрес) может быть проверен на равенство (==) или неравенство (!=) со специальным значением NULL, т.е. производиться срав-нение с 0.

Задание 1. Выполнить пример 1, приведенный веше.

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

При объявлении int m[10]; одновременно с выделением памяти для де-сяти элементов типа int, определяется значение указателя *m, значение *m равно адресу элемента m[0]. Значение *m изменить нельзя, т.к. оно является константой. Индексные выражения и адресные эквивалентны: m[i] ó *(m+i).

Для двухмерных массивов имя является указателем-константой на мас-сив указателей-констант. Элементами массива указателей являются указате-ли-константы на начало каждой из строк массива.

Page 290: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

290

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

#include <stdio.h> #include <conio.h> void main () { int i, kol=0, n; float b[30], s=0, max, min; do{ printf("Vvedite kol-vo elementov massiva (<30)\n"); scanf("%d",&n); } while (n>=30); for (i=0;i<n;i++) { printf("Vvedite element [%d]\n", i+1); scanf("%f",b+i); } for (i=0;i<n;i++) s+=*(b+i); printf("Summa elementov matrici = %.2f\n", s); max=*b; for (i=0;i<n;i++) if (*(b+i)>max) max=*(b+i); printf("Max element matrici = %.2f\n", max); min=*b; for (i=0;i<n;i++) if (*(b+i)<min) min=*(b+i); printf("Min element matrici = %.2f\n", min); }

Задание 2. Выполнить пример 2, приведенный выше.

Задание 3. Используя указатели ввести одномерный массив целых чи-сел из n элементов, подсчитать количество четных элементов и найти про-изведение элементов массива.

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

Page 291: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

291

Так как память выделяется по мере необходимости и освобождается, когда её использование завершилось, то можно использовать ту же самую память в другой момент времени и для других целей в другой части про-граммы. Динамическое выделение памяти даёт возможность создания дина-мических структур данных: списков, деревьев и др.

Ядром динамического выделения памяти в языке Си являются функ-ции, объявленные в стандартной библиотеке в заголовочном файле stdlib.h – malloc(), calloc(), realloc() и free().

Рассмотрим каждую функцию в отдельности.

Синтаксис функции malloc():

void *malloc(unsigned size)

Функция malloc выделяет из хипа область памяти размером size байт. В слу-чае успеха, malloc возвращает указатель на начало выделенного блока памя-ти. Если для выделения блока в хипе не хватает памяти, возвращается NULL. Содержимое памяти блока оставляется неизменным. Если размер аргумента равен нулю, malloc возвращает NULL.

Пример 3. Программа выделяет динамическую память под массив из n элементов, запрашивает массив с клавиатуры и выводит его на экран.

#include <stdio.h> #include <conio.h> #include <stdlib.h> void main() { int *ptr, i, n; do{ printf("Vvedite kol-vo elementov massiva (<30)\n"); scanf("%d",&n); } while (n>=30); if(!(ptr=(int*)malloc(n*sizeof(int)))) //Необходимо всегда { puts("Not enough memory"); // проверять выделилась getch(); // ли память return; } //ptr указывает на массив из n элементов for (i=0;i<n;i++) { printf("Vvedite element [%d]\n", i+1); scanf("%d",ptr+i); } printf("\nMassiv: \n", i+1); for (i=0;i<n;i++) printf("%d ", *(ptr+i)); }

Page 292: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

292

Синтаксис функции calloc():

void *calloc(unsigned num, unsigned size) Функция calloc выделяет блок памяти и возвращает указатель на первый байт блока. Размер выделяемой памяти равен величине num*size, т.е. функция вы-деляет память, необходимую для хранения массива из num элементов по size байт каждый. В случае нехватки памяти для удовлетворения запроса функция calloc возвращает NULL. Выделяемая память инициализируется нулями. На-пример:

void main() { int *ptr; ....................... if (!(ptr=(int*)calloc(5,sizeof(int)))) // ptr указывает {puts("Not enough memory"); //на массив из 5 getch(); return; //элементов, заполненный нулями } ....................... }

Синтаксис функции realloc():

void *realloc(void *ptr, unsigned size)

Эта функция изменяет размер динамически выделяемой области памяти, на которую указывает *ptr, на size (новый размер). Если указатель не является значением, которое ранее было определено функциями malloc, calloc или realloc, то поведение функции не определено. Это же справедливо, если ptr указывает на область памяти, ранее освобождённую функцией free. Значение size является абсолютным, а не относительным, т.е. задаёт новый размер бло-ка, а не приращение старого. Если size больше, чем размер ранее существо-вавшего блока, то новое, неинициализированное, пространство памяти будет выделено в конце блока и предыдущее содержимое пространства сохраняет-ся. Если функция realloc не может выделить память требуемого размера, то возвращаемое значение равно NULL и содержимое пространства, на которое указывает *ptr, остаётся нетронутым. Если *ptr – не NULL, а значение size равно нулю, то функция realloc действует как free.

Из вышесказанного следует сделать вывод, что когда бы размер блока памяти ни подвергся изменению под воздействием функции realloc, новое пространство может начинаться с адреса, отличного от исходного, даже если функция realloc “усекает” память. Следовательно, если используется функ-ция realloc, возникает необходимость следить за указателями на изменяемое пространство. Например, если вы создаёте связный список и выделяете при помощи функции realloc больший или меньший участок памяти для цепочки,

Page 293: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

293

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

if(p2 = = realloc(p1,new_size)) p1=p2;

Действуя подобным образом, вам никогда не придётся заботиться, вы-делялось ли для объекта новое пространство, т.к. p1 обновляется при каждом новом вызове функции, которая указывает на область памяти (возможно, но-вую). Например:

void main() { int *ptr, tmp; ..................... if(!(ptr=(int*)calloc(5,sizeof(int)))) //ptr указывает на { puts("Not enough memory"); // массив из 5 элементов, getch(); return; // заполненный нулями } ....................... if (tmp=realloc(ptr,10*sizeof(int))) ptr=tmp; // ptr else { puts("Not enough memory"); //указывает на массив getch(); return; //из 10 элементов } ..................... }

Синтаксис функции free():

void free(void *ptr)

Функция освобождает область памяти, ранее выделенную при помощи функций malloc, calloc или realloc, на которую указывает *ptr. Если *ptr – NULL, то функция free ничего не выполняет. Если *ptr не является указате-лем, проинициализированным ранее одной из функций выделения памяти, то поведение функции не определено. Заметим, что функция free не располагает средствами передачи ошибки, возможно возникающей при её выполнении, равно как возвращаемым значением. Например:

void main() { int *ptr; ..................... if (!(ptr=(int*)calloc(5,sizeof(int)))) // ptr указывает { puts("Not enough memory"); // на массив из 5 getch(); return; //элементов, заполненный нулями }

Page 294: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

294

....................... free(ptr); //ptr указывает на область памяти, ранее //занимаемую массивом ..................... }

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

Задание 4. Выполнить пример 3, приведенный выше.

Задание 5. Написать программу, которая выделяет память для масси-ва из n элементов (n вводиться с клавиатуры) и, используя указатель, найти количество элементов в массиве больше разности максимального и мини-мального элемента.

Сортировка. Цель сортировки - облегчить в дальнейшем поиск тре-буемых данных. Существует много методов сортировки данных, причём для разных типов данных применять разные методы сортировки.

Любой алгоритм сортировки можно разбить на три части: - сравнение двух элементов, определяющее упорядоченность этой па-

ры; - перестановку, меняющую местами неупорядоченную пару элементов; - сортирующий алгоритм, определяющий выбор элементов для сравне-

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

сортировка данных в файлах называется внешней. Рассмотрим некоторые ме-тоды сортировки данных в оперативной памяти.

Метод пузырька или сортировка простым обменом. Этот метод на-зывают также обменной сортировкой выбором. Идея этого метода заключа-ется в следующем: самые "лёгкие" элементы массива всплывают "наверх", самые "тяжёлые" - тонут. Алгоритмически это можно организовать следую-щим образом. Просматривается весь массив элементов "сверху вниз" и ме-няются местами стоящие рядом элементы в том случае, если "нижний" эле-мент меньше, чем "верхний". Таким образом, вниз вытолкиваются самый "тяжёлый" элемент из всего массива. Операция повторяется для оставшихся n-1 элементов, то есть для тех, которые лежат "выше" найденного.

Реализуем данный алгоритм функцией sort_bubl. Функция сортировки методом пузырька будет иметь следующий вид:

Page 295: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

295

/* Функция сортировки простым обменом (методом пузырька) */ void sort_bubl(int *x, int n) {

int i,j,buf; /* Проход массива 'вниз', начиная с нулевого элемента */ for (i=0; i<n; i++) /*Проход массива 'вниз', начиная с нулевого и до n-i-гo элемента*/

for (j=0; j<n-i-1; j++) /*Сравнение двух соседних элементов и их обмен*/ if (*(x+j)>*(x+j+1))

{buf=*(x+j); *(x+j)=*(x+j+1); *(x+j+1)=buf;} }

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

Пример 4. Программа сортирует массив из 10 элементов по возраста-нию методом пузырька.

#include <stdio.h> #include <conio.h> #include <stdlib.h> void sort_bubl(int *x, int n); void main() { int b[10], i, n; for (i=0;i<10;i++) { printf("Vvedite element [%d]\n", i+1); scanf("%d",b+i); } printf("\nIshodni massiv: \n", i+1); for (i=0;i<10;i++) printf("%d ", *(b+i)); sort_bubl(b,10); //вызов функции сортировки методом пузырька printf("\nOtsortirovani massiv: \n", i+1); for (i=0;i<10;i++) printf("%d ", *(b+i)); } void sort_bubl(int *x, int n) {

int i,j,buf; for (i=0; i<n; i++)

for (j=0; j<n-i-1; j++)

Page 296: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

296

if (*(x+j)>*(x+j+1)) {buf=*(x+j); *(x+j)=*(x+j+1); *(x+j+1)=buf;}

}

Сортировка выбором наименьшего элемента. Суть метода заклюю-чается в следующем: последовательно просматривается весь массив элемен-тов, при этом проводится сравнение i-го элемента со всеми элементами, на-ходящимися после него, и, определяется наименьший из них, который пере-ставляется на i-oe место. Таким образом, после перебора всех элементов, по-лучим отсортированный массив.

Реализация алгоритма функцией sor_min будет иметь следующий вид:

/* Функция сортировки выбором наименьшего элемента */ void sor_min (int *x, int n) {

int i,j,k,buf; /*Проход массива, начиная с нулевого элемента до предпоследнего */ for (i=0;i<n-1; i++) {

/*Проход массива, начиная (i+1)-гo до последнего элемента */ for (k=i, j=i+1; j<n; j++)

// Поиск наименьшего k-ro элемента if (*(x+j)< *(x+k)) k=j;

//Перемещение наименьшего элемента вверх buf=*(x+k); *(x+k)=*(x+i); *(x+i)=buf;

} }

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

Метод Шелла. Основная идея метода состоит в том, что на начальном этапе реализуется сравнивание и, если требуется, перемещение далеко от-стоящих друг от друга элементов. Интервал между сравниваемыми элемен-тами (gap) постепенно уменьшается до единицы, что приводит к перестанов-ке соседних элементов на последних стадиях сортировки.

Реализуем метод Шелла следующим образом. Начальный шаг сорти-ровки примем равным n/2, т.е. 1/2 от общей длины массива, и после каждого прохода будем уменьшать его в два раза. Каждый этап сортировки включает в себя проход всего массива и сравнение отстоящих на gap элементов. Про-ход с тем же шагом повторяется, если элементы переставлялись. Заметим, что после каждого этапа отстоящие на gap элементы отсортированы.

Рассмотрим работу алгоритма на примере. Пусть задан массив чисел:

Page 297: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

297

41,53,11,37,79,19,7,61.

Тогда произведя действия описанные выше получим:

41 53 11 37 79 19 7 61 Исходный массив 41 19 11 37 79 53 7 61 (0,4), (1,5)

1-ый цикл 41 19 7 37 79 53 11 61 (2,6), (3,7) 7 19 41 37 11 53 79 61 (0,2),(1,3),(2,4),(3,5),(4,6),(5,7)

2-ой цикл 7 19 11 37 41 53 79 61 (0,2),(1,3),(2,4),(3,5),(4,6),(5,7) 7 11 19 37 41 53 61 79 сравнивались соседние (3-ий цикл).

В строке после массива в круглых скобках указаны индексы сравни-ваемых элементов и указан номер внешнего цикла.

Функция, реализующая алгоритм сортировки Шелла, будет иметь сле-дующий вид:

/* Функция сортировки методом Шелла */ void sort_sh(int *x, int n) {

int i, j; // две переменные цикла int buff; // используется при перестановке int gap; // шаг сортировки int sorted; // флаг окончания этапа сортировки for (gap = n/2; gap > 0; gap /= 2) // начало сортировки do {

sorted = 0; for (i = 0, j = gap; j < n; i++, j++) if (*(x+i) > *(x+j)) // сравниваем отстоящие на gap элементы { // переставляем элементы buff = *(x+j); *(x+j) = *(x+i); *(x+i) = buff; sorted = 1; // есть еще не рассортированные данные }

} while (sorted); // окончание этапа сортировки }

Задание 6. Выполнить пример 4, приведенный выше.

Индивидуальное задание

Используя указатели отсортировать в порядке возрастания элементы динамического массива символов, состоящего из n-элементов методом Шел-ла, методом наименьшего элемента и методом пузырька. Метод сортировки выбирается пользователем через меню.

Лабораторная работа № 11.

СТРУКТУРЫ

Теоретическая часть Языки программирования C/C++ поддерживает определяемые пользо-

вателем структуры – структурированный тип данных.

Page 298: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

298

Структура является собранием одного или более объектов (перемен-ных, массивов, указателей, других структур и т.д.), которые для удобства ра-боты с ними сгруппированы под одним именем.

Использование структур в языке Си: - облегчает написание и понимание программ; - помогает сгруппировать данные, объединяемые каким-либо об-

щим понятием; - позволяют группу связанных между собой переменных использо-

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

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

Определение структуры состоит из следующих двух шагов: - объявление шаблона структуры (задание нового типа данных, опре-

деленного пользователем); - определение переменных типа объявленного шаблона. Объявление шаблонов структур. Общий синтаксис объявления шаб-

лона структуры:

struct имя_шаблона {

тип1 имя_переменной1; тип1 имя_переменной1; //другие члены данных;

}; Наример:

struct DateBase { char fam[20];

char name[15]; long TelNumber; char *Adress; double w;

}; Имена шаблонов должны быть уникальными в пределах их области

определения для того, чтобы компилятор мог различать различные типы шаблонов. Задание шаблона осуществляется с помощью ключевого слова struct, за которым следует имя шаблона структуры и список элементов, за-ключенных в фигурные скобки.

Page 299: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

299

Имена элементов в одном шаблоне также должны быть уникальными. Однако в разных шаблонах можно использовать одинаковые имена элемен-тов.

Задание только шаблона не влечет резервирования памяти компилято-ром. Шаблон представляет компилятору необходимую информацию об эле-ментах структурной переменной для резервирования места в оперативной памяти и организации доступа к ней при определении структурной переме-ной и использовании отдельных элементов структурной переменной.

Среди членов данных структуры могут также присутствовать, кроме стандартных типов данных (int, float, char и т.д.), ранее определенные типы других структур, например:

/* объявление шаблона структуры типа date */ struct date { int day, month, year; }; /* шаблон структуры person */ struct person {

char fam[30], im[20], otch[15]; float weight; int height; struct date birthday;

};

Структура date имеет три поля типа int. Шаблон структуры person в качестве элемента включает поле birthday, которое, в свою очередь, имеет ранее объявленный тип данных: struct date. Этот элемент (birthday) содержит в себе все компоненты шаблона struct date.

Определение структур-переменных. Определение структуры-переменной ничем не отличается от объявления обычной переменной с пре-допределенным типом. Общий синтаксис:

struct имя_шаблона имя_переменной;

Например:

struct person stud[10];

Компилятор выделит под каждую переменную количество байтов па-мяти, необходимое для хранения всех ее элементов.

Разрешается совмещать описание шаблона и определение структурной переменной. Например:

struct book {

Page 300: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

300

char title[20]; char autor[30]; double cast;

} book1, book2, *ptr_bk=&book1; struct date {int day, month, year;} date1[5]; // объявление массив из 15 структур

Доступ к компонентам структуры. Доступ к полям осуществляется с помощью оператора "." при непосредственной работе со структурой или "->" - при использовании указателей на структуру. Эти операторы называют-ся селекторами членов класса. Общий синтаксис для доступа к компонентам структуры следующий:

имя_переменной_структуры.член_данных; имя_указателя->имя_поля; (*имя_указателя).имя_поля;

Рассмотрим реализацию прямого доступа к элементам структуры и доступа по указателю на примерах. Прямой доступ к элементам структуры:

date1[5].day=10; date1[5].year=1991; strcpy(book1.title, “Война и мир”);

В последнем примере, используя прямое обращение к элементу, при-сваиваем значение выбранной переменной. Текс помещается в переменную, используя функцию копирования – strcpy().

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

stud[3].birthday.month=1; stud[3].birthday.year=1980;

Доступ по указателю к элементам структуры:

(date1+5)->day=10; (date1+5)->year=1991; (stud+3)->birthday.month=1; (stud+3)->birthday.year=1980;

Здесь, используя доступ по указателю на структуру, присваиваем зна-чение соответствующей переменной. Указатель можно использовать и так:

(*(date1+5)).day=10; (*(date1+5)).year=1991; (*(stud+3)).birthday.month=1; (*(stud+3)).birthday.year=1980;

Page 301: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

301

Инициализация структур. При определении структурных перемен-ных можно инициализировать их поля. Эта возможность подобна инициали-зации массива и следует тем же правилами:

имя_шаблона имя_переменной_структуры = {значение1, значение2, …}; Компилятор присваивает значение1 первой переменной в структуре, значе-ние2 – второй переменной структуры и т.д., при этом необходимо следовать некоторым правилам:

- присваиваемые значения должны совпадать по типу с соответствую-щими полями структуры;

- можно объявлять меньшее количество присваиваемых значений, чем количество полей. Компилятор присвоит нули остальным полям структуры;

- список инициализации последовательно присваивает значения полям структуры, полям вложенных структур и массивов. Например:

struct date { int day,month,year; }d[5] = { {1,3,1980}, {5,1,1990}, {1,1,1983} };

Копирование структур-переменных. Язык С(С++) позволяет опера-тору присваивания копировать значения одной структуры-переменной в дру-гую переменную, при условии, что обе структуры-переменные относятся к одному и тому же типу. Таким образом, единственный оператор может ско-пировать несколько членов данных, которые включают массивы и вложен-ные структуры.

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

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

#include<stdio.h> #include<conio.h> struct student { char name[20]; char fam[30]; int year; int mark[5];

Page 302: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

302

int average; }; struct student students[30]; struct student buffer; int records; int i, j; void main() { records=0; do { printf("Student №%d\n", records+1); puts("Vvedite familiu: "); fflush(stdin); gets(students[records].fam); puts("Vvedite imya: "); fflush(stdin); gets(students[records].name); puts("Vvedite vozrast: "); scanf("%d", &students[records].year); for(i=0; i<5; i++) { printf("Vvedite ocenku po ekzamenu №%d ", i+1); scanf("%d", &students[records].mark[i]); } records++; puts("Prekratit' rabotu? (1/0)"); scanf("%d", &i); } while(i); for (i=0; i<records; i++) { students[i].average=0; for (j=0; j<5; j++) students[i].average+=students[i].mark[j]; } for (i=0; i<records-1; i++) for (j=i; j<records; j++) if (students[i].average>students[j].average) { buffer=students[i]; students[i]=students[j]; students[j]=buffer; } for (i=0; i<records; i++) { printf("Student %s%s ", students[i].name, students[i].fam); printf(" Vosrast %d ", students[i].year); printf(" Sr. ball %d \n", students[i].average); } getch();

Page 303: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

303

} Пример 2. Ввести массив структур. Рассортировать массив в алфавитном

порядке фамилий, входящих в структуру, при этом перемещая сами структуры. #include<stdio.h> #include<conio.h> #include<string.h> struct st { char name[80]; int age; }; void main() { int i,j,k; struct st m[100], t; printf("Vvedite kol-vo studentov: "); scanf("%d", &k); for (i=0; i<k; i++) { puts("Vvedite imya studenta: "); fflush(stdin); gets(m[i].name); puts("Vvedite vozrast: "); scanf("%d", &m[i].age); } for (i=0; i<k-1; i++) for (j=i+1; j<k; j++) if (strcmp(m[i].name, m[j].name)>0) { t=m[i]; m[i]=m[j]; m[j]=t; } printf("\n\nRezultat: "); for (i=0; i<k; i++) { printf("\n\n"); puts(m[i].name); printf("%d years ", m[i].age); } getch(); } Задание. Выполнить пример 1 и пример 2, приведенные выше.

Индивидуальное задание Ввести массив структур в соответствии с вариантом, заданным препо-

давателем. Рассортировать массив в алфавитном порядке по первому полю, входящему в структуру.

Page 304: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

304

Вариант 1: Структура "Абитуриент": фамилия, имя, отчество; год рож-дения; оценки вступительных экзаменов (три оценки); средний балл аттеста-та.

Вариант 2: Структура "Сотрудник": фамилия, имя, отчество; долж-ность; год рождения; заработная плата.

Вариант 3: Структура "Государство": название; столица; численность населения; занимаемая площадь.

Вариант 4: Структура "Человек": фамилия, имя, отчество; домашний адрес; номер телефона; возраст.

Вариант 5: Структура "Человек": фамилия, имя, отчество; год рожде-ния; рост; вес.

Вариант 6: Структура "Школьник": фамилия, имя, отчество; класс; но-мер телефона; оценки по предметам (математика, физика, русский язык, ли-тература).

Вариант 7: Структура "Студент": фамилия, имя, отчество; домашний адрес; группа; рейтинг.

Вариант 8: Структура "Покупатель": фамилия, имя, отчество; домаш-ний адрес; номер телефона; номер кредитной карточки.

Вариант 9: Структура "Пациент": фамилия, имя, отчество; домашний адрес; номер медицинской карты; номер страхового полиса.

Вариант 10: Структура "Информация": носитель; объем; название; ав-тор.

Вариант 11: Структура "Публикации": название журнала; название ста-тьи; год издания; объем печатных листов.

Вариант 12: Структура "Товар": наименование товара; производитель; объем поставки; цена.

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

ФАЙЛЫ

Теоретическая часть

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

Различают два вида файлов: текстовые и бинарные. Текстовые файлы могут быть просмотрены и отредактированы с кла-

виатуры любым текстовым редактором и имеют очень простую структуру: последовательность ASCII-символов. Эта последовательность символов раз-

Page 305: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

305

бивается на строки, каждая из которых заканчивается двумя кодами: 13, 10 (0xD, 0xA). Примеры известных текстовых фалов: *.bat, *.c, *.asm, *.срр.

Бинарные файлы – это файлы, которые не имеют структуры текстовых файлов. Каждая программа для своих бинарных файлов определяет собст-венную структуру.

Библиотека языка C/С++ содержит функции для работы как с тексто-выми, так и с бинарными файлами.

Функции открытия и закрытия файла. Перед работой с файлом, его необходимо открыть.

Функция открытия файла fopen():

FILE *fopen(char *filename, char *mode);

где FILE – структурный тип, который связан с физическим файлом и содер-жит всю необходимую информацию для работы с ним (указатель на текущую позицию в файле, тип доступа и др.); char *filename - задает физическое местонахождение (путь) и имя открывае-мого файла; char *mode - тип доступа к файлу, который может принимать значения, ука-занные в таблице.

Функция fopen() при успешном открытии файла возвращает указатель на структуру типа FILE, называемый указателем на файл. Эта структура связана с физическим файлом и содержит всю необходимую информацию для работы с ним (указатель на текущую позицию в файле, тип доступа и др.). Возвращаемое функцией значение нужно сохранить и использовать для ссылки на открытый файл. Если произошла ошибка при открытии файла, то возвращается NULL.

Таблица 1: Тип доступа к файлам. Тип доступа Назначение "r" окрыть файл для чтения. "w" окрыть файл для записи; если файл существует, то его

содержимое теряется. "a" окрыть файл для записи в конец файла; если файл не су-

ществует, то он создается. "r+" окрыть файл для чтения и записи; файл должен сущест-

вовать. "w+" окрыть файл для чтения и записи; если файл существует,

то его содержимое теряется.

Page 306: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

306

"a+" окрыть файл для чтения и записи в конец файла; если файл не существует, то он создается.

Литералы "t" и "b" определяют текстовый или бинарный вида файл соответсвенно. Возможны следующие режимы доступа: "w+b", "wb+", "rw+", "w+t", "rt+" и др. Если режим не указан, то файл открывается в текстовом режиме.

После работы с файлом он должен быть закрыт функцией fclose(). Для этого необходимо в указанную функцию передать указатель на

FILE, который был получен при открытии функцией fopen(). При заверше-нии программы незакрытые файлы автоматически закрываются системой.

Стандартная последовательность операторов, необходимая для откры-тия и закрытия файла:

#include <stdio.h> . . . FILE *f; if(!(f = fopen(“readme.txt”, ”r+t”))) { printf(“Невозможно открыть файл \n”); return; } . . . // Работа с файлом fclose(f); // Закрытие файла . . .

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

fprintf(), fscanf(), fgets(), fputs().

Формат параметров этих функций очень похож на формат функций printf(), scanf(), gets() и puts(). Схожи не только параметры, но и действия. Отличие лишь в том, что printf(), scanf() и другие работают по умолчанию с консолью (экран, клавиатура), а fprintf(), fscanf() – с файлами (в том числе и со стандартными потоками stdin, stdout и др.), поэтому у них добавлен пара-метр, являющийся указателем на структуру FILE, которая была рассмотрена выше.

Функция fprintf() предназначена для форматированного вывода в файл

Пример 1. Записать в текстовый файл числа от 0 до 1000 кратные 3.

#include <stdio.h> void main( ) { int a; FILE *f; if(!(f = fopen("test.txt", "w+t")))

Page 307: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

307

{ printf("Невозможно создать файл\n"); return; } for(a=0;a<1000;a+=3) { fprintf(f, "%d, ",a); } fclose(f); }

Функции для работы с текстовыми файлами удобно использовать при создании текстовых файлов, ведении файлов-протоколов (log-файлов) и т.п. Но при создании баз данных целесообразно использовать функции для рабо-ты с бинарными файлами: fwrite() и fread(). Эти функции без каких-либо из-менений копируют блок данных из оперативной памяти в файл и соответст-венно из файла – в память. Такой способ обмена данными требует меньше времени. Прототипы функций имеют вид:

unsigned fread (void *ptr, unsigned size, unsigned n, FILE *stream); unsigned fwrite(void *ptr, unsigned size, unsigned n, FILE*stream);

где: *ptr – указатель на буфер; size – размер блока; n – количество блоков; *stream – указатель на структуру FILE открытого файла.

Пример 2. Записать в бинарный файл и прочитать из бинарного файла спи-сок абитуриентов. Информация об абитуриенте представлена структурой.

#include <stdio.h> struct abitur { char name[32]; int mark[3]; }; void main( ) { struct abitur inf; int a; FILE *f; if(!(f=fopen("inf.dat","w+"))) { printf("Ошибка создания файла\n"); return; } for(;;) { printf("Введите ФИО (пустая строка -- конец списка): "); fflush(stdin); gets(inf.name); if(!inf.name[0]) break; printf("\n Введите три оценки, полученные на экзаменах: "); scanf(“%d%d%d”, &inf.mark[0], &inf.mark[1], &inf.mark[2]);

Page 308: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

308

fwrite(&inf, 1,sizeof(inf), f); } fclose(f); printf("\nСписок абитуриентов:\n"); if(!(f=fopen("inf.dat","r"))) { printf("Ошибка создания файла\n"); } while(1) { if(sizeof(inf) != fread(&inf, sizeof(inf), 1,f)) break; /* Если не удалось прочитать необходимое количество байт, то заканчиваем чтение */ printf("%s %d %d %d \n", inf.name, inf.mark[0], inf.mark[1], inf.mark[2]); } fclose(f); }

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

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

#include <stdio.h> void main () { int account; char name[30]; float balance; FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "w")) == NULL) printf ("File could not be opened\n");

Page 309: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

309

else { printf("Enter the account, name, and balance.\n"); printf ("Enter EOF to end input.\n"); printf("? "); scanf("%d%s%f", &account, name, &balance); while ( !feof(stdin)) { fprintf(cfPtr, "%d %s %.2f\n", account, name, balance); printf("? "); scanf("%d%s%f", &account, name, &balance); } fclose (cfPtr); } }

Пример 4. Чтение и распечатка последовательного файла, созданного в предыдущем примере.

#include <stdio.h> void main () { int account; char name[30]; float balance; FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "r")) == NULL) printf("File could not be openedXn") ; else { printf("%-10s%-13s%s\n", "Account", "Name", "Balance"); fscanf(cfPtr, "%d%s%f", &account, name, &balance); while (!feof(cfPtr)) { printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } fclose(cfPtr); } }

Пример 5. Программа позволяет менеджеру по кредиту получить спи-сок клиентов с нулевым сальдо (клиентов, которые не должны денег), клиен-тов с положительным сальдо (которым компания должна какую-то сумму де-нег) и клиентов с отрицательным сальдо (которые должны компании деньги за уже полученные товары и услуги).

#include <stdio.h> void main () { int request, account; float balance; char name[30];

Page 310: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

310

FILE *cfPtr; if ((cfPtr = fopen("clients.dat", "r")) == NULL) printf("File could not be opened\n"); else { printf("Enter request\n"); printf(" 1 - List accounts with zero balances\n"); printf(" 2 - List accounts with credit balances\n"); printf(" 3 - List accounts with debit balances\n"); printf(" 4 - End of run\n? "); scanf("%d", &request); while (request != 4) { fscanf(cfPtr, "%d%s%f", &account, name, &balance); switch (request) { case 1: printf("\nAccounts with zero balances:\n"); while(!feof(cfPtr)) { if (balance ==0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf (cfPtr, "%d%s%f", &account, name, &balance); } break; case 2: printf("\nAccounts with credit balances : \n") ; while (!feof(cfPtr)) { if (balance < 0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } break; case 3: printf("\nAccounts with debit balances: \n"); while (!feof(cfPtr)) { if (balance >0) printf("%-10d%-13s%7.2f\n", account, name, balance); fscanf(cfPtr, "%d%s%f", &account, name, &balance); } break; } rewind(cfPtr); printf("\n? "); scanf("%d", &request); } printf("End of run.\n"); fclose(cfPtr); } }

Page 311: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

311

Задание. Выполнить пример 1-5, рассмотренные выше.

Индивидуальное задание

Сформировать текстовый файл из элементов структуры, заданной в ла-бораторной работе «Структуры», распечатать его содержимое, выполнить добавление элементов и поиск по одному из полей структуры. Формирова-ние, печать, добавление и поиск элементов оформить в виде функций. Пре-дусмотреть сообщения об ошибках при открытии файла и выполнении опе-раций ввода/вывода.

Вариант 1: Структура "Абитуриент": фамилия, имя, отчество; год рож-дения; оценки вступительных экзаменов (три оценки); средний балл аттеста-та.

Вариант 2: Структура "Сотрудник": фамилия, имя, отчество; долж-ность; год рождения; заработная плата.

Вариант 3: Структура "Государство": название; столица; численность населения; занимаемая площадь.

Вариант 4: Структура "Человек": фамилия, имя, отчество; домашний адрес; номер телефона; возраст.

Вариант 5: Структура "Человек": фамилия, имя, отчество; год рожде-ния; рост; вес.

Вариант 6: Структура "Школьник": фамилия, имя, отчество; класс; но-мер телефона; оценки по предметам (математика, физика, русский язык, ли-тература).

Вариант 7: Структура "Студент": фамилия, имя, отчество; домашний адрес; группа; рейтинг.

Вариант 8: Структура "Покупатель": фамилия, имя, отчество; домаш-ний адрес; номер телефона; номер кредитной карточки.

Вариант 9: Структура "Пациент": фамилия, имя, отчество; домашний адрес; номер медицинской карты; номер страхового полиса.

Вариант 10: Структура "Информация": носитель; объем; название; ав-тор.

Вариант 11: Структура "Публикации": название журнала; название ста-тьи; год издания; объем печатных листов.

Вариант 12: Структура "Товар": наименование товара; производитель; объем поставки; цена.

Page 312: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

312

4 МЕТОДИЧЕСКИЕ УКАЗАНИЯ ПО ВЫПОЛНЕНИЮ КУРСОВОЙ РАБОТЫ

4.1 Общие положения

Курсовая работа выполняется студентами на 1 курсе во 2-ом семестре, после изучения основных разделов дисциплины «Основы алгоритмизации и программирования».

Цель курсовой работы: углубить и закрепить теоретические знания, по- лученные в результате изучения дисциплины, приобрести практические на- выки алгоритмизации и программирования инженерных задач, используя процедурно-ориентированный язык С/С++, получить умения по отладке и тестированию программ, с учетом конкретного задания по курсовой работе.

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

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

Допуском к защите курсовой работы является допуск руководителя. Руководитель ставит на титульном листе пояснительной записки допуск к защите курсовой работы после того, как студент продемонстрирует разрабо-танный программный модуль, соответствующий требованиям, определенным в бланке задания, и завершенную пояснительную записку.

Защита курсовой работы осуществляется в комиссии (не менее 2 чело-век), в состав которой обязательно входит руководитель работы.

4.2 Требования к содержанию этапов проектирования

В процессе курсового проектирования выполняются следующие этапы работы.

Ø Описание предметной области: описание и краткая характеристика предметной области, в рамках которой разрабатывается программный мо-

Page 313: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

313

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

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

Ø Формализация и обоснование алгоритма решения задачи с учетом его реализации на алгоритмическом языке. Построение и разработка блок- схемы алгоритма решения задачи.

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

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

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

Ø Описание создаваемого программного модуля, его исходных тек-стов, отладки и тестирования.

Ø Разработка инструкции для конечного пользователя. Ø Оформление пояснительной записки на бумажном носителе вместе

с ее электронной копией и разработанным программным модулем. Ø Представление курсовой работы руководителю (представляется по-

яснительная записка с распечаткой листингов программы в приложении, и на электронном носителе исходные тексты программы, исполняемый модуль и контрольный пример.).

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

Необходимая для выполнения курсовой работы по дисциплине «Осно-вы алгоритмизации и проектирования» литература перечислена в рабочей программе дисциплины на сайте университета в .pdf-файле.

Page 314: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

314

4.3 Требования к разработке и оформлению работы

Пояснительная записка по курсовому проекту должна содержать сле- дующие основные разделы и подразделы:

ВВЕДЕНИЕ 1. АНАЛИЗ ЗАДАНИЯ И ПОСТАНОВКА ЗАДАЧИ 2. ОПИСАНИЕ РАЗРАБАТЫВАЕМОЙ ПРОГРАММЫ

2.1. Блок-схема алгоритма 2.2. Описание используемых функций

3. РАЗРАБОТКА РУКОВОДСТВА ПОЛЬЗОВАТЕЛЯ 3.1. Описание работы программы 3.2. Описание требований и ограничений

ЗАКЮЧЕНИЕ СПИСОК ИСПОЛЬЗУЕМЫХ ИСТОЧНИКОВ ПРИЛОЖЕНИЕ Листинги программных модулей

Оформление пояснительной записки должно выполняться в соответст-вии с требованиями ЕСКД, ЕСПД и Стандарта предприятия МИУ «Работы курсовые и дипломные. Структура и правила оформления».

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

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

Пример оформления курсовой работы приведен на сайте МИУ.

4.4 Допуск и защита курсовой работы

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

Page 315: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

315

последующей передачи работы руководителю. Электронная версия курсовой работы предоставляется комиссии во время защиты.

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

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

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

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

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

В случае недопуска студента к защите или при получении отрицатель-ной оценки дальнейшие действия определяются законодательными актами по образования Республики Беларусь.

Page 316: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

316

4.5 Рекомендуемые темы курсовых работ

Пример 1: Ввести массив структур в соответствии с вариантом. Рас- сортировать массив в алфавитном порядке по первому полю, входящему в структуру. В программе реализовать меню:

1) Ввод массива структур; 2) Считать массив структур из файла; 3) Сортировка массива структур; 4) Поиск в массиве структур по заданному параметру; 5) Изменение заданной структуры; 6) Удаление структуры из массива; 7) Вывод на экран массива структур; 8) Сохранение массива структур в файл; 9) Выход. Пример 2: Сформировать бинарный файл из элементов, заданной в ва-

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

ВАРИАНТЫ СТРУКТУР: 1. Структура «ПОКУПАТЕЛЬ». В магазине формируется список лиц,

записавшихся на покупку товара повышенного спроса. Каждая запись этого списка содержит: порядковый номер, Ф.И.О., домашний адрес покупателя и дату постановки на учет. Удалить из списка все повторные записи, проверяя Ф.И.О. и домашний адрес, используя созданное меню.

2. Структура «ТОВАР». Список товаров, имеющихся на складе, вклю-чает в себя: наименование товара, количество единиц товара, цену единицы и дату поступления товара на склад. Вывести в алфавитном порядке список то-варов, хранящихся больше месяца, стоимость которых превышает 100 руб., используя созданное меню.

3. Структура «ОЧЕРЕДНОСТЬ В ОБЩЕЖИТИИ». Для получения мес-та в общежитии формируется список студентов, который включает: Ф.И.О. студента, группу, средний балл, доход на члена семьи. Общежитие в первую очередь предоставляется тем, у кого доход на члена семьи меньше двух ми-нимальных зарплат, затем остальным в порядке уменьшения среднего балла. Вывести список очередности предоставления мест в общежитии, используя созданное меню.

Page 317: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

317

4. Структура «РАСПИСАНИЕ РЕЙСОВ». В справочной автовокзала хранится расписание движения автобусов. Для каждого рейса указаны: его номер, тип автобуса, пункт назначения, время отправления и прибытия. Вы-вести информацию о рейсах, которыми можно воспользоваться для прибытия в пункт назначения раньше заданного времени, используя созданное меню.

5. Структура «ТЕЛЕФОННЫЕ ТАРИФЫ». На междугородной АТС информация о разговорах содержит: дату разговора, код и название города, время разговора, тариф, номер телефона в этом городе и номер телефона абонента. Вывести по каждому городу общее время разговоров с ним и сум-му, используя созданное меню.

6. Структура «ЗАРАБОТНАЯ ПЛАТА». Информация о сотрудниках фирмы включает: Ф.И.О., табельный номер, количество проработанных ча-сов за месяц, почасовой тариф. Рабочее время свыше 144 часов считается сверхурочным и оплачивается в двойном размере. Вывести размер заработ-ной платы каждого сотрудника фирмы за вычетом подоходного налога, кото-рый составляет 13%, и пенсионного фонды, который составляет 1% от суммы заработка, используя созданное меню.

7. Структура «СПОРТСМЕНЫ». Информация об участниках спортив-ных соревнований содержит: наименование страны, название команды, Ф.И.О. игрока, его игровой номер, возраст, рост и вес. Вывести информацию о самой молодой, рослой и легкой команде, используя созданное меню.

8. Структура «БИБЛИОТЕКА». Для книг, хранящихся в библиотеке, задаются: регистрационный номер книги, автор, название, год издания, изда-тельство, количество страниц. Вывести список книг с фамилиями авторов в алфавитном порядке, изданных после заданного года, используя созданное меню.

9. Структура «ПРОДУКЦИЯ». Различные цехи завода выпускают про-дукцию нескольких наименований. Сведения о выпущенной продукции включают: наименование, количество, номер цеха. Для заданного цеха необ-ходимо вывести количество выпущенных изделий по каждому наименова-нию в порядке убывания количества, используя созданное меню.

10. Структура «СОТРУДНИКИ». Информация о сотрудниках предпри-ятия содержит: Ф.И.О., табельный номер, номер отдела, должность, дату приема на работы. Вывести списки сотрудников по отделам в порядке убы-вания стажа, используя созданное меню.

11. Структура «АБИТУРИЕНТ». Ведомость абитуриентов, прошедших централизованное тестирование и поступающих в университет, содержит:

Page 318: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

318

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

12. Структура «РАСПИСАНИЕ АВИОРЕЙСОВ». В справочной аэро-порта хранится расписание вылета самолетов на следующие сутки. Для каж-дого рейса указаны: номер рейса, тип самолета, пункт назначения, время вы-лета. Вывести все номера рейсов, типы самолетов и время вылета для задан-ного пункта назначения в порядке возрастания времени вылета, используя созданное меню.

13. Структура «БИЛЕТЫ». У администратора железнодорожных касс хранится информация о свободных местах в поездах дальнего следования на ближайшую неделю в следующем виде: дата выезда, пункт назначения, вре-мя отправления, число свободных мест. Оргкомитет международной конфе-ренции обращается к администратору с просьбой зарезервировать m мест до города N на k-й день недели со временем отправления поезда не позднее t ча-сов вечера. Вывести время отправления или сообщение о невозможности вы-полнить заказ в полном объеме, используя созданное меню.

14. Структура «СЕССИЯ». Ведомость студентов, сдавших сессию, со-держит: Ф.И.О. студента, нгомер группы и его оценки по пяти предметам. Определить средний балл по университету и вывести список студентов, средний балл которых выше среднего балла по университету. Первыми в списке должны идти студенты, сдавшие все экзамены на 9 и 10, используя созданное меню.

15. Структура «РАДИОАТЕЛЬЕ». В радиоателье хранятся квитанции о сданной в ремонт радиоаппаратуре. Каждая квитанция содержит следующую информацию: наименование группы изделий (телевизор, радиоприемник и т. п.), марку изделия, дату приемки в ремонт, состояние готовности заказа (вы-полнен, не выполнен). Вывести информацию о состоянии заказов на текущие сутки по группам изделий, используя созданное меню.

16. Структура «УСПЕВАЕМОСТЬ СТУДЕНТОВ». Ведомость об успе-ваемости студентов содержит: номер группы, Ф.И.О. студента, оценки за по-следнюю сессию. Вывести списки студентов по группам в порядке убыва- ния среднего балла, используя созданное меню.

17. Структура «ОЧЕРЕДЬ НА ЖИЛЬЁ». В исполкоме формируется список учета нуждающихся в улучшении жилищных условий. Каждая запись списка содержит: порядковый номер, Ф.И.О., величину жилплощади на од-

Page 319: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

319

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

18. Структура «СЕМЕЙНЫЕ ПАРЫ». Имеется список женихов и спи-сок невест. Каждая запись списка содержит: пол, имя, возраст, рост, вес, а также требования к партнеру: наименьший и наибольший возраст, вес, рост. Объединить эти данные в список пар с учетом требований к партнерам без повторений женихов и невест, используя созданное меню.

19. Структура «БИБЛИОТЕКА». В библиотеке имеется список книг, каждая запись которого содержит: фамилию автора, название книги, год из-дания. Вывести информацию о книгах, в названии которых встречается за-данное ключевое слово (ввести с клавиатуры) , используя созданное меню.

20. Структура «АВТОМОБИЛИ». В магазине имеется список посту-пивших в продажу автомобилей. Каждая запись этого списка содержит: мар-ку автомобиля, стоимость, расход топлива на 100 км, надежность (число лет безотказной работы), комфортность (отличная, хорошая, удовлетворитель-ная). Вывести перечень автомобилей, удовлетворяющих требованиям поку-пателя, которые вводятся с клавиатуры в виде некоторого интервала допус-тимых значений, используя созданное меню.

21. Структура «ВАКАНСИИ». Каждая запись списка вакантных рабо-чих мест содержит: наименование организации, должность, квалификацию (разряд или образование), стаж работы по специальности, заработную плату, наличие социального страхования (да/нет), продолжительность ежегодного оплачиваемого отпуска. Вывести список рабочих мест в соответствии с тре-бованиями клиента, используя созданное меню.

22. Структура «АВИОРЕЙСЫ». В технической службе аэропорта име-ется справочник, содержащий записи следующей структуры: тип самолета, год выпуска, расход горючего на 1000 км. Для определения потребности в горючем техническая служба запрашивает расписание полетов. Каждая за-пись расписания содержит следующую информацию: номер рейса, пункт на-значения, дальность полета. Вывести суммарное количество горючего, необ-ходимое для обеспечения полетов на следующие сутки, используя созданное меню.

23. Структура «ЗАМЕЩЕНИЕ ВАКАНСИЙ». Для участия в конкурсе на замещение вакантной должности сотрудника фирмы желающие подают следующую информацию: Ф.И.О., год рождения, образование (среднее, спе-циальное, высшее), знание иностранных языков (английский, немецкий,

Page 320: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

320

французский, владею свободно, читаю и перевожу со словарем), владение компьютером (MS DOS,Windows и т.д.), стаж работы, наличие рекоменда-ций. Вывести список претендентов в соответствии с требованиями руково-дства фирмы, используя созданное меню.

24. Структура «УЧЕТ АВТОМОБИЛЕЙ». При постановке на учет в ГАИ автолюбителя указывают следующие данные: марка автомобиля, год выпуска, номер двигателя, номер кузова, цвет, номерной знак, Ф.И.О и адрес владельца. Вывести список автомобилей, проходящих техосмотр в текущем году, сгруппированных по маркам автомобилей. Учесть, что если текущий год четный, техосмотр проходят автомобили с четными номерами двигате-лей, иначе – с нечетными номерами, используя созданное меню.

25. Структура «СТУДЕНТЫ». Список студентов группы содержит сле-дующую информацию: Ф.И.О., год рождения, рост и вес. Вывести Ф.И.О. студентов, рост и вес которых чаще всего встречается в списке, используя созданное меню.

26. Структура «КОМПЬЮТЕРЫ». В магазине имеется перечень ноут-буков с указанием марки, цены, типа процессора, объема оперативной памя-ти, объема дисковой памяти и их количества. Вывести полную стоимость всех компьютеров, используя созданное меню.

27. Структура «НОВОРОЖДЕННЫЕ». В роддоме ведется учет родив-шихся детей. В списке указывается: ФИО матери ребенка, дата и время его рождения, ФИО врача, принимавшего роды, пол ребенка, его вес и окруж-ность головы, дата выписки из роддома. Определить число детей родив- шихся с заданным весом, используя созданное меню.

28. Структура «МЕТЕОПРОГНОЗ». В метеоцентре ведется наблюдение за погодой и каждый день на состояние 12:00 часов делается запись, вклю-чающая: дату, температуру, атмосферное давление, направление и силу вет-ра, облачность, осадки, влажность. Определить дни с минимальным давлени-ем, используя созданное меню.

29. Структура «УЧЕТ ЖИЛЬЦОВ». В домоуправлении ведется учет жильцов данного района, который включает следующие сведения: улица, номер дома, номер квартиры, метраж, число комнат, для каждого прожи-вающего указывается: ФИО, дата рождения, дата регистрации и выписки, от-ношение к владельцу квартиры. Определить число проживающих в одноком-натных квартирах, используя созданное меню.

Page 321: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

321

5 УПРАВЛЯЕМАЯ САМОСТОЯТЕЛЬНАЯ РАБОТА СТУДЕНТОВ Контролируемая самостоятельная работа (КСР) студентов под управ-

лением препадавателя служит для более глубокого усвоения студентами тео-ретического материала и закрепеления практических навыков составления, отладки и выполнения программ на алгоритмическом языке C/C++.

1. Задания на первый семестр

Задание 1. Написать программу на языке Си для решения задачи с ис-пользованием оператора выбора if в соответствии с вариантом.

Варианты УСРС: 1. Вводиться двухзначное число. Определить, равен ли квадрат этого

числа учетверенной сумме кубов его цифр. Например, для числа 48 ответ по-ложительный, для числа 52 — отрицательный.

2. Вводиться двузначное число. Определить: а) входит ли в него циф-ра 3; б) входит ли и него цифра а. Число а вводиться с клавиатуры.

3. Вводиться двузначное число. Определить: а) входят ли в нею циф-ры 4 или 7; б) входят ли в него цифры 3, 6 или 9.

4. Вводиться двузначное число. Определить: а) какая из его цифр больше: первая или вторая; б) одинаковы ли его цифры.

5. Вводиться двузначное число. Определить: а) кратна ли трем сумма его цифр; б) кратна ли сумма его цифр числу а. Число а вводиться с клавиа-туры.

6. Вводиться двузначное число. Определить: а) является ли сумма его цифр двузначным числом; б) больше ли числа а сумма его цифр. Число а вводиться с клавиатуры.

7. Вводиться натуральное число n (n < 9999). Выяснить, верно ли, что это число содержит ровно три одинаковые цифры с учетом четырех цифр, как, например, числа 3363, 4844, 0300 и т. п.

8. Вводиться натуральное число n (n < 9999). Выяснить, различны ли все четыре цифры этого числа (с учетом четырех цифр). Например, в числе 3678 все цифры различны, в числе 0023 — нет.

9. Вводиться натуральное число n (n < 9999). Выяснить, является ли оно палиндромом ("перевертышем") с учетом четырех цифр, как, например, числа 7777, 8338, 0330 и т. п. (палиндромом называется число, десятичная запись которого читается одинаково слева направо и справа налево).

10. Вводиться натуральное число. Выяснить: а) заканчивается ли оно четной цифрой; б) заканчивается ли оно нечетной цифрой.

Page 322: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

322

11. Вводиться натуральное число. Определить: а) является ли оно чет-ным; б) оканчивается ли оно цифрой 7.

12. Вводиться трехзначное число. Выяснить, является ли оно палин-дромом ("перевертышем"), т.е. таким числом, десятичная запись которого читается одинаково слева направо и справа налево.

13. Вводиться трехзначное число. Определить, какая из его цифр боль-ше: а) первая или последняя; б) первая или вторая; в) вторая или последняя.

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

15. Вводиться трехзначное число. Определить: а) больше ли числа а произведение его цифр; б) кратна ли пяти сумма его цифр. Число а вводиться с клавиатуры.

16. Вводиться трехзначное число. Определить: а) больше ли числа а сумма его цифр; б) кратна ли сумма его цифр числу а. Число а вводиться с клавиатуры.

17. Вводиться трехзначное число. Определить: а) все ли его цифры одинаковые; б) есть ли среди его цифр одинаковые.

18. Вводиться трехзначное число. Определить: а) входит ли в него цифра 6; б) входит ли в него цифра n. Число n вводиться с клавиатуры.

19. Вводиться трехзначное число. Определить: а) входят ли в него циф-ры 4 или 7; б) входят ли в него цифры 3, 6 или 9.

20. Вводиться трехзначное число. Определить: а) является ли сумма его цифр двухзначным числом; б) является ли произведение его цифр трехзнач-ным числом.

21. Вводиться четырехзначное число. Определить: а) входит ли в него цифра 4; б) входит ли в него цифра n. Число n вводиться с клавиатуры.

22. Вводиться четырехзначное число. Определить: а) входят ли в него цифры 2 или 7; б) входят ли в него цифры 3, 6 или 9.

23. Вводиться четырехзначное число. Определить: а) кратно ли четы-рем произведение его цифр; б) кратно ли произведение его цифр числу а. Число а вводиться с клавиатуры.

24. Вводиться четырехзначное число. Определить: а) равна ли сумма двух первых его цифр сумме двух его последних цифр; б) кратна ли трем сумма его цифр.

25. Вводятся три вещественных числа a, b, с. Определить, имеется ли среди них хотя бы одна пара равных между собой чисел.

Page 323: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

323

26. Год является високосным, если его номер кратен 4, однако из крат-ных 100 високосными являются лишь кратные 400, например, 1700, 1800 и 1900 — невисокосные года, 2000 — високосный. Вводиться натуральное число n. Определить, является ли високосным год с таким номером.

27. Известен рост трех человек. Определить, одинаков ли их рост? 28. Определить, верно ли, что при делении неотрицательного целого

числа а на положительное число b получается остаток, равный одному из двух заданных чисел с или d. Числа a, b, c, d вводятся с клавиатуры.

29. Определить, является ли введенное шестизначное число счастли-вым. Счастливым называют такое шестизначное число, когда сумма его пер-вых трех цифр равна сумме его последних трех цифр.

30. Определить, является ли треугольник со сторонами а, b, c равно-бедренным. Стороны треугольника вводятся с клавиатуры.

31. Определить, является ли треугольник со сторонами а, b, c равносто-ронним. Стороны треугольника вводятся с клавиатуры.

Задание 2. Написать программу на языке Си для решения задачи с ис-пользованием оператора цикла for в соответствии с вариантом.

Варианты УСРС: 1. Найти произведение всех целых чисел от 1 до b (значение b вводит-

ся с клавиатуры; 1< b < 20). 2. Найти произведение всех целых чисел от а до 20 (значение а вво-

дится с клавиатуры; 1 < а < 20). 3. Найти произведение всех целых чисел от а до b (значения а и b вво-

дятся с клавиатуры; b > а). 4. Найти произведение целых положительных четных чисел от 1 до n

(значение n вводится с клавиатуры). 5. Найти произведение целых положительных чисел от 1 до n, крат-

ных 5 (значение n вводится с клавиатуры). 6. Найти произведение целых положительных чисел от a до b и крат-

ных 5 (значения а и b вводятся с клавиатуры; b > а). 7. Найти среднее арифметическое всех целых чисел от 100 до b (зна-

чение b вводится с клавиатуры; b > 100). 8. Найти среднее арифметическое всех целых чисел от а до 200 (зна-

чения а вводятся с клавиатуры; а < 200). 9. Найти среднее арифметическое всех целых чисел от а до b (значе-

ния а и b вводятся с клавиатуры; b > a).

Page 324: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

324

10. Найти среднее арифметическое целых положительных нечетных чисел от 1 до n (значение n вводится с клавиатуры).

11. Найти среднее арифметическое целых положительных чисел от a до b и кратных 5 (значения а и b вводятся с клавиатуры; b > а).

12. Найти сумму всех целых чисел а до 500 (значение а вводится с кла-виатуры; а < 500).

13. Найти сумму всех целых чисел от -10 до b (значение b вводится с клавиатуры; b >-10).

14. Найти сумму всех целых чисел от а до b (значения a и b вводятся с клавиатуры; b > a).

15. Найти сумму квадратов всех целых чисел oт 1 до n (значение n вво-дится с клавиатуры; 0 < n < 100).

16. Найти сумму квадратов всех целых чисел от a до b (значения а и b вводятся с клавиатуры; b > а).

17. Найти сумму квадратов всех целых чисел от а до 50 (значение а вводится с клавиатуры; 0 < а < 50).

18. Найти сумму целых положительных нечетных чисел от 1 до n (зна-чение n вводится с клавиатуры).

19. Найти сумму целых положительных четных чисел от 1 до n (значе-ние n вводится с клавиатуры).

20. Найти сумму целых положительных чисел от 1 до n, кратных 3 (значение n вводится с клавиатуры).

21. Найти сумму целых положительных чисел от a до b и кратных 3 (значения а и b вводятся с клавиатуры; b > а).

22. Напечатать квадраты всех целых чисел от 10 до b (значение b вво-дится с клавиатуры; b>10).

23. Напечатать квадраты всех целых чисел от а до b (значения а и b вводятся с клавиатуры; b > a).

24. Напечатать таблицу перевода 1, 2, ..., 20 долларов США в рубли по текущему курсу (значение курса вводится с клавиатуры).

25. Напечатать таблицу перевода расстояний в дюймах в сантиметры для значений 10, 11, ..., 22 дюйма (1 дюйм = 25.4 мм).

26. Напечатать таблицу стоимости 100, 200, 300, …, 2000 г конфет (стоимость 1 кг конфет вводится с клавиатуры).

27. Напечатать таблицу стоимости 50, 100, 150, ..., 1000 г сыра (стои-мость 1 кг сыра вводится с клавиатуры).

Page 325: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

325

28. Напечатать таблицу умножения на число n (значение n вводится с клавиатуры; 1 < n < 9).

29. Напечатать третьи степени всех целых чисел от а до 50 (значение а вводится с клавиатуры; а < 50).

30. Напечатать таблицу соответствия между весом в фунтах и весом в килограммах для значений 1, 2, ..., 10 фунтов (1 фунт = 453 г).

31. Одна единица некоторого товара стоит 20,4 руб. Напечатать табли-цу стоимости 2, 3, …, 20 единиц этого товара.

Задание 3. Написать программу на языке Си для решения задачи с ис-пользованием оператора цикла while в соответствии с вариантом.

Варианты УСРС: 1. В ведомости указана зарплата, выплаченная каждому из сотрудни-

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

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

3. В области 12 районов. Известны количество жителей (в тысячах че-ловек) и площадь (в км2) каждого района. Определить среднюю плотность населения по области в целом.

4. В области 12 районов. Известны количество жителей каждого рай-она (в тысячах человек) и плотность населения в нем (тыс. чел./км). Опреде-лить общую площадь территории области.

5. Даны натуральное число n и вещественные числа а1, а2, …, an. Опре-делить сумму всех вещественных чисел.

6. Даны натуральное число n и вещественные числа а1, а2, …, an. Опре-делить среднее арифметическое вещественных чисел.

7. Даны натуральное число n и вещественные числа а1, а2, …, an. Опре-делить сумму квадратов вещественных чисел.

8. Даны натуральное число n и числа а1, а2, …, an. Определить сумму положительных чисел среди чисел а1, а2, …, an.

9. Даны натуральное число n и числа а1, а2, …, an. Определить сумму чисел кратных 3 среди чисел а1, а2, …, an.

10. Даны натуральное число n и числа а1, а2, …, an. Определить сумму четных среди чисел а1, а2, …, an.

Page 326: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

326

11. Даны натуральное число n и числа а1, а2, …, an. Определить произ-ведение модулей чисел а1, а2, …, an.

12. Даны натуральное число n и числа а1, а2, …, an. Определить сумму модулей чисел а1, а2, …, an.

13. Даны числа a1, a2, …, a10. Определить их произведение. 14. Даны числа a1, a2, …, a10. Определить их среднее арифметическое. 15. Даны числа a1, a2, …, a10. Определить их сумму. 16. Даны числа a1, a2, …, a10. Определить сумму их квадратов. 17. Известен возраст (в годах в виде 14,5 лет и т. п.) каждого ученика

двух классов. Определить средний возраст учеников каждого класса. В каж-дом классе учатся 20 человек.

18. Известен рост каждого ученика двух классов. Определить средний рост учеников каждого класса. Численность обоих классов одинаковая и вво-диться с клавиатуры.

19. Известна масса каждого из 12 предметов. Определить общую массу всего набора предметов.

20. Известна масса каждого предмета из некоторого набора предметов. Определить среднюю массу. Количество предметов вводиться с клавиатуры.

21. Известна масса каждого предмета, загружаемого в автомобиль. Оп-ределить общую массу груза. Количество предметов, загруженных в автомо-биль, вводиться с клавиатуры.

22. Известно количество осадков, выпивших за каждый день января и марта. Определить среднедневное количество осадков за каждый месяц.

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

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

25. Известны оценки абитуриента на четырех экзаменах. Определить сумму набранных им баллов.

26. Известны оценки двух учеников по четырем предметам. Определить сумму оценок каждого ученика.

27. Известны оценки по дисциплине ОАиП каждого студента группы. Определить среднюю оценку. Количество учеников в группе вводиться с клавиатуры.

Page 327: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

327

28. Известны оценки по дисциплине ОКП каждого студента двух групп. Определить среднюю оценку в каждой из групп. Количество студентов в ка-ждой группе одинаковое и вводиться с клавиатуры.

29. Известны оценки по дисциплине «Высшая маиематика» каждого из 30 студентов группы. Определить среднюю оценку.

30. Известны оценки студента по 10 предметам. Определить среднюю оценку.

31. Известны результаты двух спортсменов-пятиборцев в каждом из пя-ти видов спорта в баллах. Определить сумму баллов, полученных каждым спортсменом.

Задание 4. Написать программу на языке Си для решения задачи в со-ответствии с вариантом. Для решения использовать цикл while. Ввод после-довательности данных во всех задачах должен заканчиваться вводом кон-трольного значения.

Варианты УСРС: 1. Известна масса каждого человека из некоторой группы людей. Лю-

дей, имеющих массу более 100 кг будем условно называть полными (извест-но, что в группе есть, по меньшей мере, один такой человек). Определить среднюю массу полных людей и среднюю массу остальных людей.

2. Известен рост каждого студента группы. Рост студентов мужского пола условно задан отрицательными числами. Определить средний рост сту-дентов мужского пола и средний рост студентов женского пола.

3. В чемпионате по футболу команде за выигрыш дается 3 очка, за проигрыш — 0, за ничью — 1. Известно число очков, полученных командой за каждую из проведенных игр. Определить количество выигрышей, количе-ство проигрышей и количество ничьих.

4. В ходе хоккейного матча игроки обеих команд удалялись в общей сложности 24 раза. По каждому удалению известен номер команды удален-ного игрока и продолжительность удаления (2, 5 или 10 мин). Для каждой команды определить общее число удалений и общее время всех удалений.

5. Дана последовательность ненулевых целых чисел. Определить, сколько раз в этой последовательности меняется знак. Например, в последо-вательности 10, -4, 12, 56, -4 знак меняется 3 раза.

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

Page 328: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

328

7. Известны оценки каждого студента из группы по двум экзаменам. Определить количество студентов группы, получивших на экзамене двойку.

8. Известны оценки по дисциплине ОАиП каждого студента группы. Определить количество положительных (балл от 4-10) и количество неудов-летворительных обенок (балл от 1 до 3).

9. Известен год рождения каждого студента группы. Определить число человек, родившихся до a года, и число людей, родившихся после b года (значение a и b вводяться с клавиатуры; a<b).

10. Известны данные о стоимости каждого товара из группы товаров. Найти общую стоимость тех товаров, которые стоят дороже 1000 рублей (ко-личество таких товаров неизвестно).

11. Известны данные о количестве страниц в каждой из нескольких га-зет и в каждом из нескольких журналов. Число страниц в газете не более 16. Найти общее число страниц во всех журналах (количество журналов неиз-вестно, но известно, что объем любого журнала превышает объем любой га-зеты).

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

13. Известно число студентов, обучающихся во всех группах на пер-вом, втором, …, пятом курсах. учащихся во всех первых классах, во всех вторых, ... и во всех одиннадцатых. Определить общее число студентов, обу-чающихся на первом, третьим, пятом курсах.

14. Известны оценки по дисциплине ОАиП каждого студента группы. Определить количество пятерок.

15. Известны данные о температуре воздуха в течение месяца. Опреде-лить, сколько раз температура опускалась ниже 0 °С.

16. Известны оценки студента по всем дисциплинам. Верно ли, что среди них нет неудовлетворительных оценок (балл от 1 до 3)?

17. Известны данные о количестве осадков, выпавших за каждый день марта. Верно ли, что осадков не было 10 дней в месяц?

18. Известны стоимости (в долларах) нескольких марок легковых авто-мобилей и мотоциклов. Верно ли, что средняя стоимость автомобилей пре-вышаем среднюю стоимость мотоциклов более чем в 3 раза? Стоимость од-ного автомобиля превышает $5000, что больше стоимости любой марки мо-тоцикла.

Page 329: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

329

19. Известен рост каждого студента группы. Рост студентов мужского пола условно задан отрицательными числами. Верно ли, что средний рост мужчин превышает средний рост девушек более чем на 10см?

20. Известны данные о количестве осадков, выпавших за каждый день февраля. Верно ли, что по четным числам выпало больше осадков, чем по не-четным?

21. Известно число жителей, проживающих в каждом доме улицы, Ну-мерация домов проведена подряд. Дома с нечетными номерами расположены на одной стороне улицы, с четными — на другой. На какой стороне улицы проживает больше жителей?

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

23. Известна масса каждого груза, загружаемого в автомобиль. Выяс-нить, не превысила ли общая масса всех грузов грузоподъемность автомоби-ля.

24. Известны результаты (в баллах) двух спортсменов-десятиборцев в каждом из десяти видов спорта. Определить, кто из них показал лучший ре-зультат.

25. Известны стоимости каждого предмета в двух наборах. Какой из наборов предметов более дешевый?

26. Известны оценки по дисциплине ОАиП каждого студента группы. Выяснить, сколько в группе неудовлетворительных оценок (балл от 1 до 3).

27. Известны данные о мощности двигателей различных моделей лег-ковых автомобилей. Выяснить, есть ли среди них модель, мощность двигате-ля которой превышает 200 л. с. Если есть, то сколько таких моделей.

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

29. Имеются данные о сумме очков, набранных в чемпионате каждой из футбольных команд. Выяснить, перечислены ли команды в списке в соот-ветствии с занятыми ими местами в чемпионате.

30. Дана последовательность вещественных чисел, оканчивающаяся числом 10 000. Количество чисел в последовательности не меньше двух. Оп-ределить, является ли последовательность упорядоченной по возрастанию. В случае отрицательного ответа определить порядковый номер первого числа, нарушающего такую упорядоченность.

Page 330: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

330

31. Дана последовательность целых чисел, оканчивающаяся числим 9999. Количество чисел в последовательности не меньше двух. Определить, есть ли в ней хотя бы одна пара "соседних" четных чисел. В случае положи-тельного ответа определить порядковые номера чисел первой из таких пар.

2. Задания на второй семестр

Задание 1. Массивы. Варианты УСРС: 1. Задан двумерный массив. Найти сумму элементов первого столбца

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

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

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

4. Дана матрица порядка NхM. Определить, является ли эта матрица симметричной (относительно главной диагонали). Вывести на экран соответ-ствующее сообщение. Найти максимальный элемент среди стоящих на главной и побочной диагонали и поменять местами с элементом, стоящим на пересечении этих диагоналей.

5. Дана матрица порядка NхM. Выведите номера столбцов, все элемен-ты, которых четны. Для каждого столбца с отрицательным элементом на главной диагонали вывести его номер и сумму всех элементов этого столбца.

6. Дана матрица порядка NхM. Для заданной целочисленной матрицы найти максимум среди сумм элементов диагоналей, параллельных главной диагонали матрицы.

7. Дана матрица порядка NхM. Для заданной целочисленной матрицы найти минимум среди сумм модулей элементов диагоналей, параллельных побочной диагонали матрицы.

8. Даны две действительные квадратные матрицы порядка N. Получить новую матрицу умножением элементов каждой строки первой матрицы на

Page 331: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

331

наибольшее из значений элементов соответствующей строки второй матри-цы.

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

10. Подсчитать количество столбцов заданной матрицы, которые со-ставлены из попарно различных чисел.

Задание 2. Строки и функции. Варианты УСРС: 1. В головном модуле ввести массив строк. Строк - не более 15, длина

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

2. Обработать n матриц. Размеры матрицы - не более 10x15. Элементы матрицы - строки символов, длина строки - не более 25 знаков. В строке есть слово, состоящее только из цифр (например 1327671). Найти это слово, преобразовать в число и сохранить в массиве. Вывести на экран полученное число, а также количество чисел в матрице, значения которых больше тыся-чи. Ввод матрицы, поиск слова, преобразование его в число реализовать в отдельных функциях.

3. В головном модуле определить матрицу, размеры которой 10х20. Элементами матрицы являются строки знаков. В первой функции ввести размеры матрицы и её элементы. Во второй функции все строки и столбцы матрицы, в которых хотя бы один из ее элементов совпадает со строкой, вве-денной с клавиатуры, удалить. Заданная строка может повторяться в строке или столбце матрицы.

4. В головном модуле ввести массив строк, размер массива - не более 20x30. В первой функции, используя указатели на строки, ввести их. Во вто-рой функции разбить строки на отдельные слова (выделить слова из строк). Известно, что слов не более 70, а длина слова – не более семи знаков. В третьей функции рассортировать массив слов по их длинам. Рассортирован-ный массив слов вывести в четвертой функции.

Page 332: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

332

5. Обработать n матриц (n задается с клавиатуры). Размеры матрицы - не более 15x10. Элементы матрицы – предложения, строки знаков длиной не более 80. В первой функции определить все слова в предложении, состоящие только из цифр. Во второй функции определить сумму чисел во всех пред-ложениях, составляющих строку матрицы. Сумму чисел каждой строки мат-рицы вывести в головном модуле. Рассортировать элементы каждой строки матрицы в алфавитном порядке и вывести в головном модуле.

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

ВариантыУСРС: 1. Структура "Абитуриент": фамилия, имя, отчество; год рождения;

оценки вступительных экзаменов (три оценки); средний балл аттестата. 2. Структура "Сотрудник": фамилия, имя, отчество; должность; год

рождения; заработная плата. 3. Структура "Государство": название; столица; численность населе-

ния; занимаемая площадь. 4. Структура "Человек": фамилия, имя, отчество; домашний адрес; но-

мер телефона; возраст. 5. Структура "Человек": фамилия, имя, отчество; год рождения; рост;

вес. 6. Структура "Школьник": фамилия, имя, отчество; класс; номер теле-

фона; оценки по предметам (математика, физика, русский язык, литература). 7. Структура "Студент": фамилия, имя, отчество; домашний адрес;

группа; рейтинг. 8. Структура "Покупатель": фамилия, имя, отчество; домашний адрес;

номер телефона; номер кредитной карточки. 9. Структура "Пациент": фамилия, имя, отчество; домашний адрес;

номер медицинской карты; номер страхового полиса. 10. Структура "Информация": носитель; объем; название; автор.

Page 333: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

333

6 ПЕРЕЧЕНЬ ТЕСТОВЫХ ВОПРОСОВ К ЭКЗАМЕНАМ

Приведенный перечень тестовых вопросов предназначен для проведе-ния экзаменов по дисциплине «Основы алгоритмизации и программирова-ния» с использованием средств вычислительной техники, либо в интерактив-ном режиме непосредственно на компьютерах под управлением программно-го продукта Assist2, либо в режиме обработки бланков ответов в центре тес-тирования Минского инновационного университета.

Тема 1. Общие сведения об алгоритмах 1. Конечный набор правил или команд (указаний), позволяющий ис-

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

2. Какими способами может быть представлен алгоритм? 3. Предписание, задающее алгоритм, должно удовлетворять следую-

щим требованиям: 4. Какими свойствами обладает алгоритм? 5. Что означает свойство дискретности алгоритма? 6. Что означает свойство детерминированности алгоритма? 7. Что означает свойство элементарности алгоритма? 8. Что означает свойство результативности алгоритма? 9. Что означает свойство направленности алгоритма? 10. Что означает свойство массовости алгоритма? 11. Исходные объекты, промежуточные и окончательные результаты,

которые используются в алгоритмах, называются ... 12. Описание последовательных этапов обработки данных на естест-

венном языке называется ... 13. Представление алгоритма в виде схемы, состоящей из последова-

тельности блоков, каждый из которых отражает содержание очередного шага алгоритма называется ...

14. Какие существуют варианты графического описания алгоритма? 15. В блок-схеме выполнение одной операции или группы операций, в

результате которых изменяются значения данных описывают ... 16. В блок-схеме условия, влияющие на выбор направления алгоритма

указывают ... 17. В блок-схеме объекты, значения которых заранее известны и

должны быть заданы перечисляются ...

Page 334: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

334

18. Для обозначения начала или конца выполнения алгоритма исполь-зуют ...

19. Представление алгоритма решения задачи, в котором блоки алго-ритма представляются вершинами, а соединительные стрелки – ребрами, на-зывается ...

20. Какие компоненты, понятия и правила должен включать любой ал-горитмический язык?

21. ... – перечень символов (знаков), используемых в данном алгорит-мическом языке.

22. ... – любая конечная упорядоченная последовательность символов на алгоритмическом языке.

23. ... – определяет правила записи и представления переменных, кон-стант, строк, массивов, структур и других конструкций, используемых в ал-горитмическом языке.

Тема 2. Общие сведения о системах программирования 24. Программные продукты подразделяются на: 25. Системное программное обеспечение подразделяется на: 26. Операционные оболочки предназначены для ... 27. Операционная система предназначена для ... 28. Какие программы являются операционными оболочками? 29. Системные утилиты предназначены для ... 30. Что относиться к системным утилитам? 31. BIOS – это … 32. В высказывание "Каталог содержит информацию о ..., хранящихся

в ..." (вместо многоточий вставить правильные выражения). 33. Прикладное программное обеспечение подразделяется на ... 34. Какие из перечисленных прикладных программных продуктов от-

носятся к ПО общего назначения? 35. В основе методоориентированных пакетов прикладных программ

лежит реализация разнообразных экономико-математических методов реше-ния задач. Каких?

36. Какие из перечисленных систем относятся к проблемно-ориентированным пакетам прикладных программ?

37. Графическим редактором называется программа, предназначенная для …

38. Языки программирования по синтаксису образования его конст-рукций условно можно разделить на:

Page 335: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

335

39. ... читает всю программу целиком, делает ее перевод и создает за-конченный вариант программы на машинном языке, который затем и выпол-няется.

40. ... переводит и выполняет программу построчно. 41. …. – это текст программы на языке программирования. 42. … – результат обработки компилятором исходного модуля. 43. … – модуль создаётся с помощью компоновщика, который объе-

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

44. Какие выделяют виды ошибок компиляции? 45. Какого рода ошибки могут возникать в процессе разработки про-

граммы? 46. Какие функции выполняет предпроцессор?

Тема 3 Основные элементы языка 47. Выберите одинаковые идентификаторы. 48. Какие группы символов используются для написания программ на

Си (исключая комментарии и выводимые на экран сообщения)? 49. Выберите различные идентификаторы. 50. Какие из перечисленных слов являются ключевыми? 51. Какие из перечисленных слов не являются ключевыми? 52. Какие из перечисленных утверждений справедливы для идентифи-

каторов? 53. Какие из перечисленных идентификаторов не являются ошибоч-

ными? 54. Какие из перечисленных идентификаторов являются ошибочны-

ми? 55. Ключевые слова сообщают компилятору … 56. Данные, значение которых во время программы менять нельзя, на-

зываются: 57. Данные, значение которых во время программы можно изменять,

называются … 58. Какой тип данных обозначает ключевое слово char? 59. Какой тип данных обозначает ключевое слово double? 60. Какой тип данных обозначает ключевое слово void? 61. Какой тип данных обозначает ключевое слово float? 62. Какой тип данных обозначает ключевые слова long int? 63. Какой тип данных обозначает ключевые слова unsigned char?

Page 336: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

336

64. Какой тип данных обозначает ключевые слова unsigned short int? 65. Тип данных и модификатор типа определяют: 66. Какие из перечисленных типов относятся к составным типам дан-

ных? 67. Выберите правильный вариант объявления переменных в функции

fun. 68. Что указывается при объявлении переменных? 69. Чем отличается объявление от определения? 70. Глобальная переменная – это … 71. Локальная переменная – это … 72. Выберите правильный вариант определения целых восьмеричных

констант. 73. Выберите правильный вариант определения целых шестнадцате-

ричных констант. 74. Какое значение получит переменная k, в следующем фрагменте

программы: int x=0; void main () {int x=5; ::x+=4;} int k=x; 75. Какое значение получит переменная k, в следующем фрагменте

программы: int x=10; void main () {int x=5; x+=4;} int k=x; 76. C какой функции начинается выполнение программы? 77. Тело функции заключается в … 78. В конце каждого оператора ставится … 79. Оператор – это ... 80. Комментарии – это ... 81. Какие утверждения верны для комментариев? 82. Какая стандартная библиотечная функция используется для прие-

ма данных с клавиатуры? 83. Какая стандартная библиотечная функция используется для выво-

да информации на экран? 84. Выберите правильный вариант использования функции scanf, если

x целочисленная переменная, а y – строка. 85. Выберите правильный вариант использования функции printf, если

x целочисленная переменная, а y – строка. 86. Верно ли, что когда вызывается функция printf, она всегда начина-

ет печатать сначала новой строки? 87. Какие из перечисленных операций являются унарными? 88. Указатель – это ... 89. Выберите правильные варианты объявления указателя.

Page 337: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

337

90. Фрагмент программы имеет вид: void main() { int *p, b=5; p=&b; *p+=5; ... } Чему будет равно b в результате выполнения этого фрагмента?

91. Какие операции могут выполняться над указателями? 92. Фрагмент программы: void main() { int a, *pi=&a; float f, *pf=&f;

pi++; pf++; ...} Как изменяться указатели pi и pf в результате выполнения этой программы?

93. Что такое пустой оператор? 94. Что такое составной оператор? 95. Что делает оператор ветвления if ... else? 96. Какими свойствами обладает конструкция if … else? 97. Операторы ветвления это … 98. Если необходимо выбрать один варианта решения задачи из не-

скольких возможных, то это можно сделать с помощью оператора … 99. Какие из перечисленных утверждений справедливы для условного

выражения оператора switch? 100. Какие утверждения справедливы для констант оператора switch? 101. Какие утверждения справедливы для метки default оператора

switch? 102. Какие утверждения справедливы для оператора break внутри опе-

ратора switch? 103. Какой оператор цикла лучше применять, когда известно точное

количество повторений? 104. Операторы цикла – это … 105. Какой необходимо выбрать оператор цикла для того чтобы органи-

зовать повторенное (количество повторений неизвестно) выполнение одного или нескольких операторов, заключенных в фигурные скобки? Тело цикла повторяется до тех пор, пока условие не примет значение «ложь», при этом проверка условия выполняется после первого выполнения оператора или группы операторов, т.е. тело цикла выполняется хоть один раз всегда.

106. Какой оператор цикла является оператором цикла с предусловием? 107. Какой необходимо выбрать оператор цикла для того чтобы органи-

зовать повторенное (количество повторений неизвестно) выполнение одного или нескольких операторов, заключенных в фигурные скобки? Тело цикла повторяется до тех пор, пока условие не примет значение «ложь», при этом проверка условия выполняется перед входом в цикл, т.е. возможна ситуация, когда тело цикла не выполниться ни разу.

108. Какой оператор цикла является оператором цикла с постусловием?

Page 338: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

338

109. Какие операторы цикла применяется, когда неизвестно количество повторений цикла?

110. Какой оператор прекращает выполнение цикла? 111. Какой оператор при его использовании в структуре повторения

вызывает немедленное выполнение следующей итерации цикла? 112. Какие из приведенных вариантов цикла не являются бесконечны-

ми? 113. Какие утверждения справедливы для цикла for? 114. Сколько раз выполниться цикл?

int k=3; while (k<8) k+=2;

115. Сколько раз выполниться цикл? for (i=0; i<=5; i++) res+=i;

116. Сколько раз выполниться цикл? char s[20]=«My name is Nick»; for (q=0;s[q];q++);

117. Сколько раз выполниться цикл? int k=9; do { k+=3; } while (k<8);

118. Сколько раз выполниться цикл? int k=10; while (k<8) k+=3;

119. Установите, какие значения управляющей переменной х выводятся каждым из следующих операторов for.

a) for(x = 2; х <= 13; х += 2) printf("%d\n", х); b) for(x = 5; х <= 22; х += 7) printf("%d\n", x); c) for (x = 3; x <= 15; x += 3) printf("%d\n", x); d) for (x = 1; x <= 5; x += 7) printf("%d\n", x)

Тема 4. Сложные типы данных 120. Массив – это …

Page 339: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

339

121. Определение массива должно содержать: 122. Порядковый номер элемента в массиве называется … 123. Какое утверждение справедливо для порядкового номера элемента

в массиве? 124. Выберите правильные варианты объявления массива. 125. Что необходимо указать, чтобы получить доступ к элементу мас-

сива? 126. Выберите правильные варианты доступа к элементам массива. 127. Размерность массива указывается после имени массива в … 128. Нумерация элементов массива начинается с … 129. Выберите правильные варианты обращения к элементам массива,

объявление которого имеет вид int array[3]. 130. Выберите правильные варианты объявления символьных перемен-

ных. 131. Выберите правильные варианты объявления массива указателей. 132. Фрагмент программы имеет вид: void main() {int *p, m[10];

p=&m[0]; ... }. Выберите правильные варианты присвоения значения 5 вто-рому элементу массива m.

133. Фрагмент программы имеет вид: void main() {int x[5], *m=x; ...}. Можно ли выполнить операцию x++; и m++; ?

134. Какие утверждения справедливы для структуры? 135. Какие шаги и в какой последовательности необходимо выполнить

для определения структуры? 136. Какие утверждения справедливы для шаблона структур? 137. Выберите правильные варианты определения переменных струк-

турного типа. 138. Пусть объявлены шаблон структуры и структурная переменная:

struct stud {char *fio; int marks[5];} student[3]; Выберите правильные варианты доступа к компонентам структуры.

139. Пусть объявлены шаблон структуры и структурная переменная: struct stud {char *fio; int marks[3];} student[3]; Выберите правильные варианты доступа к компонентам структуры:

140. Какие правила необходимо соблюдать при инициализации струк-тур?

Тема 5. Функции (подпрограммы) 141. Какие утверждения справедливы для имен функций? 142. Прототип функции – это ...

Page 340: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

340

143. Определение функции – это ... 144. Тип возвращаемого результата указывается в … 145. Тип параметров, передаваемых в функцию, описывается в … 146. Прототип функции заканчивается … 147. Прототип функции рекомендуется располагать … 148. Прототип является предварительным объявлением: 149. Тело функции, заключенное в фигурные скобки отсутствует в … 150. Что может быть использовано в арифметических выражениях? 151. Определение функции может быть размещено в … 152. Если прототип функции имеет вид: void add(void); Выберите пра-

вильный вариант вызова функции. 153. Параметры в функции разделяются: 154. Должно ли количество параметров в прототипе и в определении

функции совпадать с числом аргументов при вызове функции? 155. Какой тип результата должен указываться в прототипе и опреде-

лении, если функция ничего не возвращает? 156. Какие утверждения справедливы для оператора return? 157. Сколько значений можно явно вернуть с помощью оператора

return? 158. Тип возвращаемого результата определяется … 159. Параметры функции указываются в … 160. Выберите правильные варианты прототипов функций. 161. Выберите правильные варианты определений функций. 162. Если прототип функции имеет вид: void fun(int x, int z). Какие из

перечисленных вызовов функции правильные? 163. Какие правила должны выполняться в рекурсивной функции? 164. В чем сходства рекурсии и итерации? Выберите правильные вари-

анты. Тема 6. Файлы

165. Чем отличается файл от массива? 166. Какие функции используются для открытия и закрытия текстового

файла? 167. Какие функции используются для работы с бинарными файлами? 168. Выберите правильный вариант прототипа функции fopen()? 169. Какой параметр должен быть передан в функции fclose(), для за-

крытия файла?

Page 341: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

341

170. Какие функции предназначены для записи информации в тексто-вый файл?

171. Какие функции предназначены для чтения информации из тексто-вого файла?

172. Выберите правильный вариант прототипа функции для чтения из бинарного файла fread().

173. Относительно чего функция fseek() смещает указатель на текущую позицию?

174. Какие утверждения справедливы для функции fseek()? Тема 7. Динамические структуры данных

175. Какие утверждения справедливы для стека? 176. Какие утверждения справедливы для очереди? 177. Какие функции языка Си предназначены для динамического выде-

ления памяти? 178. Какие функции языка Си/C++ предназначены для освобождения

динамически выделенной области памяти? 179. С помощью какой функции можно изменить размер динамически

выделяемой области памяти? 180. Какое значение возвращает функция malloc(), если не хватает па-

мяти для удовлетворения запроса? 181. Выберите правильные варианты динамического выделения памяти

для массива целых чисел из 5 элементов. 182. Какие из перечисленных структур, являются динамическими

структурами (т.е. структурами данных, для которых заранее не определен не-обходимый объем памяти)?

Тема 8 Дополнительные возможности языка C/C++ 183. Какой класс памяти необходимо указать, чтобы переменная была

размещена не в оперативной памяти, а в одном из регистров? 184. Какой класс памяти устанавливается по умолчанию для всех пере-

менных, если он не задан явно? 185. Какой класс памяти необходимо указать, чтобы переменная суще-

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

186. Какой класс памяти необходимо указать, если предполагается, что память под переменную выделяется в другом модуле в месте ее определения, а в данном модуле только используется ее значение?

Page 342: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

342

7 СПИСОК ЛИТЕРАТУРЫ ПО ДИСЦИПЛИНЕ

7.1 Основная литература

1. ГОСТ 19.701-90 – Единая система программной документации – Схемы алгоритмов, программ, данных и систем – Условные обозначения и правила выполнения.

2. Таборовец В.В. Основы информатики и программирования: учеб.-метод. компл./ В.В. Таборовец, Е.М. Демидович, Т.В. Русак. – Минск: Изд-во МИУ, 2007.– 196с.

3. Таборовец В.В. Основы алгоритмизации и программирования: учеб.-метод. компл./ В.В. Таборовец, Т.В. Русак. – Минск: Изд-во МИУ, 2010.– 436с.

4. Голицына О., Попов И. Основы алгоритмизации и программирова-ния. – СПб, 2003.

5. Глухова Л.А., Бахтизин В.В. Основы алгоритмизации и структурно-го проектирования программ: Учеб. пособие по курсам «Основы алгоритми-зации и программирования» и «Технология разработки программного обес-печения». – Мн.: БГУИР, 2003. – 72 с.

6. Таборовец В.В., Демидович Е.М., Русак Т.В. Основы информатики и программирования. Учебно-методический комплекс. – Мн.: Минский ин-т управления, 2007 – 196 с.

7. Демидович Е.М. Основы алгоритмизации и программирования. Язык СИ.: Учебное пособие. СПб: БХВ-Петпрбург, 2006. – 438 с.

8. Демидович Е.М. Основы информатики и программирования. : Учебное пособие. В 2-х ч. Мн.: Минский ин-т управления, 2005, Ч. 1 – 256 с., Ч. 2 – 216 с.

9. Дейтел Х.М., Дейтел П.Дж. Как программировать на С. – М.: Би-ном, 2006 – 1037 с.

10. Йодан Э. Структурное программирование и конструирование про-грамм. – М.: Мир, 1979.

11. Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: Построение и ана-лиз. – СПб, 2003.

12. Уилсон С. Принципы проектирования и разработки программного обеспечения. Учебный курс. – СПб, 2003

Page 343: ЭУМК - ОАиП 2 с титульникомmedia.miu.by/files/store/umk/eumk_oap.pdfязык Си с элементами языка С++, так как в настоящее время

343

7.2 Дополнительная литература

13. Одинцов И. Профессиональное программирование. Системный подход. – СПб, 2003.

14. Орлов С.А. Технологии разработки программного обеспечения: Учеб. Пособие. – СПб, 2003.

15. Соммервилл И. Инженерия программного обеспечения. – СПб, 2003.

16. Хопкрофт Дж.Э., Мотивани Р., Ульман Дж.Д. Введение в теорию автоматов, языков и вычислений. – М.: Издательский дом “Вильямс”, 2002.

17. Шилдт Г. Искусство программирования на C++. – СПб.: БХВ-Петербург, 2005.

18. Уоррен Г.С. Алгоритмические трюки для программистов. – М.: Вильямс, 2004.

19. Шелест В.Д. Программирование: Структурный подход. Алгоритмы. Turbo Pascal. Borland C++. Современный Fortran. – СПб, 2003.

20. Подбельский В.В., Фомин С.С. Программирование на языке Си: Учебное пособие. 2-е доп. изд. - М.: Финансы и статистика, 2000. – 600 c.

21. Акулов О.А., Медведев Н.В. Информатика: базовый курс. - М.: Омега-Л, 2004. – 552 с.

22. Керниган Б., Ритчи Д. Язык программирования Си. - М.: Финансы и статистика, 1998.

23. Страуструп Б. Язык программирования С++. – М.:СПб.: «Изда-тельство БИНОМ» - «Невский диалект», 2001. – 1099с.

24. Юлин В.А., Булатова И.Р. Приглашение к Си. – Мн.: Выш. шк., 1990. – 224с.