Справочник от Автор24
Поделись лекцией за скидку на Автор24

Технологии программирования

  • 👀 357 просмотров
  • 📌 298 загрузок
Выбери формат для чтения
Загружаем конспект в формате docx
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Технологии программирования» docx
ТЕХНОЛОГИИ ПРОГРАММИРОВАНИЯ Конспект лекций Цель – получить представление о современной классификации программного обеспечения, понятии «технологии программирования», а также об основных этапах их развития. Программное обеспечение (ПО) – это совокупность программ, позволяющих осуществить автоматизированную обработку информации на компьютере, предназначенных для многократного использования и применения разными пользователями, а также программных документов, необходимых для их эксплуатации. Условно программное обеспечение классифицируется как системное (общее) и прикладное (специальное). Программы, работающие на системном уровне, обеспечивают взаимодействие программ базового уровня с прочими программами системы и непосредственно с аппаратным обеспечением. Программное обеспечение прикладного уровня представляет собой комплекс прикладных программ, с помощью которых на данном рабочем месте выполняются конкретные задания. Между тем, подразделение ПО на системное и прикладное является до некоторой степени устаревшим. Современное разделение предусматривает минимум три градации ПО: системное, промежуточное и прикладное. Современная тенденция развития ПО состоит в снижении объема как системного, так и прикладного программирования. Основная часть работы программистов выполняется в промежуточном ПО. Снижение объема системного программирования обусловлено современными концепциями ОС, объектно-ориентированной архитектурой и архитектурой микроядра, в соответствии с которыми большая часть функций системы выносится в утилиты, которые можно отнести и к промежуточному ПО. Снижение объема прикладного программирования обусловлено тем, что современные продукты промежуточного ПО предлагают все больший набор инструментальных средств и шаблонов для решения задач своего класса. Значительная часть системного и практически все прикладное ПО пишется на языках высокого уровня, что обеспечивает сокращение расходов на их разработку/модификацию и переносимость. Промежуточное ПО (middleware) определяется как совокупность программ, осуществляющих управление вторичными ресурсами (конструируемыми самим ПО), которые ориентированы на решение определенного класса задач. К такому ПО относятся менеджеры транзакций, серверы БД, серверы коммуникаций и другие программные серверы. С точки зрения инструментальных средств промежуточное ПО ближе к прикладному, так как не работает напрямую с первичными ресурсами, а использует для этого сервисы, предоставляемые системным ПО. С точки же зрения алгоритмов и технологий разработки оно ближе к системному, так как всегда является сложным программным изделием многократного и многоцелевого использования, в котором применяются алгоритмы, сходные с применяемыми в системном ПО. Технология программирования (ТП) - это совокупность методов и средств, используемых при разработке ПО. ТП представляет собой набор технологических инструкций: 1) указание последовательности выполнения технологических операций; 2) перечисление условий, при которых выполняются операции; 3) описания самих операций с исходными данными, результатами, инструкциями, нормативами, стандартами, критериями и методами оценки. Технология определяет способ описания проектируемой системы (модели), используемой на конкретном этапе разработки. Различают технологии, используемые на конкретных этапах разработки (определенный метод), и технологии, охватывающие несколько этапов разработки (базовый метод или методология). Среди основных этапов развития технологий программирования выделяют «стихийное» программирование, структурный, объектный и компонентный подходы к программированию [1]. Этап «стихийного» программирования. Характерной особенностью периода от момента появления первых ЭВМ до середины 60-х годов XX века является то, что сформулированные технологии программирования практически отсутствовали, а само программирование было искусством. Первые программы имели простейшую структуру: программа на машинном языке и обрабатываемые данные. Сложность программ в машинных кодах ограничивалась способностью программиста одновременно мысленно отслеживать последовательность выполняемых операций и местонахождение данных при программировании. Использовалась интуитивная технология программирования. В результате появления ассемблеров вместо двоичных кодов стали использовать символические имена данных и мнемоники кодов операций, а программы стали более «читаемыми». Именно в этот период зародилась ставшая впоследствии фундаментальной для ТП концепция модульного программирования [1, 9], ориентированная на преодоления трудностей программирования в машинном коде. Создание языков программирования высокого уровня (FORTRAN, ALGOL) существенно упростило программирование вычислений, снизив уровень детализации операций, что позволило увеличить сложность программ. В результате появления средств, позволяющих оперировать подпрограммами, были созданы огромные библиотеки расчетных и служебных подпрограмм. Типичная программа состояла из основной программы, области глобальных данных и набора подпрограмм (рисунок А.1а). Однако при увеличении количества подпрограмм возрастала вероятность искажения части глобальных данных какой-либо подпрограммой, поэтому было предложено размещать в них локальные данные (рисунок А.1б). В начале 60-х годов XX века разразился «кризис программирования»: разработчики сложного программного обеспечения срывали все сроки завершения проектов: проект устаревал раньше, чем был готов к внедрению, его стоимость увеличивалась, в результате многие проекты так никогда и не были завершены. Использование разработки «снизу-вверх» при отсутствии четких моделей описания подпрограмм и методов проектирования превращало создание программ в непростую задачу. Интерфейсы программ получались сложными, а при сборке программного продукта выявлялось большое количество ошибок согласования, исправление которых требовало серьезного изменения уже разработанных частей программ. При этом в программу часто вносились новые ошибки, в результате чего процесс тестирования и отладки программ занимал более 80% времени разработки, если вообще когда-нибудь заканчивался. Анализ причин возникновения ошибок позволил сформулировать новый подход к программированию - структурный. Этап структурного программирования. Структурный подход к программированию, который развивался на втором этапе развития технологий в 60-70 годы XX века. В его основе лежит декомпозиция сложных систем с целью последующей реализации в виде отдельных небольших (до 40-50 операторов) подпрограмм, позже названная процедурной декомпозицией. Структурный подход требовал представления задачи в виде иерархии подзадач простейшей структуры, а проектирование осуществлялось «сверху-вниз» и подразумевало реализацию общей идеи. Были введены ограничения на конструкции алгоритмов, рекомендованы формальные модели их описания, а также специальный метод проектирования алгоритмов - метод пошаговой детализации. Принципы структурного программирования были заложены в основу процедурных языков программирования, которые включали основные «структурные» операторы передачи управления, поддерживали вложение подпрограмм, локализацию и ограничение области «видимости» данных (PL/1, ALGOL-68, Pascal, С). Дальнейший рост сложности и размеров разрабатываемого программного обеспечения потребовал развития структурирования данных, в языках появляется возможность определения пользовательских типов данных [1, 5, 9]. Стремление разграничить доступ к глобальным данным программы дало толчок к появлению и развитию технологии модульного программирования (рисунок А.2), что предполагало выделение групп подпрограмм, использующих одни и те же глобальные данные в отдельно компилируемые модули (библиотеки). Связи между модулями осуществлялись через специальный интерфейс, в то время как доступ к реализации модуля (телам подпрограмм и некоторым «внутренним» переменным) был запрещен. Эту технологию поддерживают современные версии Pascal, С, C++, Ада и Modula. Структурный подход в сочетании с модульным программированием позволяет получать надежные программы, размером не более 100 000 операторов. Существенным недостатком является тот факт, что ошибка в интерфейсе при вызове подпрограммы выявляется только при выполнении программы (из-за раздельной компиляции модулей), а при увеличении размера программы возрастает сложность межмодульных интерфейсов, и предусмотреть взаимовлияние отдельных частей программы становится практически невозможно. Поэтому для разработки программного обеспечения большого объема было предложено использовать объектный подход. Этап объектного программирования. На третьем этапе (80-е - 90-е годы XX века) был сформирован объектный подход к программированию. Широкое внедрение персональных компьютеров во все сферы человеческой деятельности привело к бурному развитию пользовательских интерфейсов и созданию четкой концепции качества программного обеспечения [1, 9]. Развиваются методы и языки спецификации. Развивается концепция компьютерных сетей. Возникает необходимость в формировании совершенно нового подхода к разработке сложного программного обеспечения с интуитивно понятным и удобным пользовательским интерфейсом. Технология создания сложного программного обеспечения, основанная на представлении программы в виде совокупности взаимодействующих путем передачи сообщений программных объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию с наследованием свойств, была названа объектно-ориентированным программированием [1, 9]. Объектная структура программы (рисунок А.3) впервые была использована в языке имитационного моделирования сложных систем Simula, а затем использована в новых версиях универсальных языков программирования таких, как Pascal, C++, Modula, Java. Достоинством объектно-ориентированного программирования является «естественная» декомпозиция программного обеспечения, существенно облегчающая разработку. Это приводит к более полной локализации данных и интегрированию их с подпрограммами обработки, что позволяет вести практически независимую разработку отдельных объектов программы. Кроме того, объектный подход предлагает новые способы организации программ, основанные на механизмах наследования, полиморфизма, композиции, наполнения, позволяющих конструировать из простых объектов сложные. В результате существенно увеличивается показатель повторного использования кодов и появляется возможность создания библиотек классов. На основе объектного подхода были созданы среды, поддерживающие визуальное программирование (Delphi, C++ Builder, Visual C++), при использовании которого некоторая часть будущего продукта проектируется с применением визуальных средств добавления и настройки специальных библиотечных компонентов. В результате появляется заготовка будущей программы, в которую уже внесены коды. Использование объектного подхода имеет много преимуществ. Однако его конкретная реализация в объектно-ориентированных языках программирования таких, как Pascal и C++ имеет существенные недостатки: отсутствуют стандарты компоновки двоичных результатов компиляции объектов в единое целое, даже в пределах одного языка программирования; изменение в реализации одного программного объекта связано с перекомпиляцией модуля и перекомпоновкой всего программного обеспечения, использующего данный объект. Таким образом, сохраняется объективная зависимость модулей программного обеспечения от адресов экспортируемых полей и методов, а также структур и форматов данных. Связи модулей нельзя разорвать, но можно стандартизировать их взаимодействие, на чем и основан компонентный подход к программированию. В 90-е годы XX века персональные компьютеры стали подключаться к сети как терминалы. Остро встала проблема защиты компьютерной информации и передаваемых по сети сообщений. Начался решающий этап полной информатизации и компьютеризации общества. Четвертый этап развития технологий программирования - компонентный подход и CASEтехнологии - не завершился до настоящего времени. Компонентный подход предполагает построение ПО из отдельных компонентов, которые взаимодействуют между собой через стандартизованные двоичные интерфейсы. Объекты-компоненты можно собрать в динамически вызываемые библиотеки или исполняемые файлы, распространять в двоичном виде (без исходных текстов) и использовать в любом языке программирования, поддерживающем соответствующую технологию [1, 9]. Компонентный подход лежит в основе технологий, разработанных на базе COM (Component Object Model - компонентная модель объектов), и технологии создания распределенных приложений CORBA (Common Object Request Broker Architecture - общая архитектура с посредником обработки запросов объектов), которые используют сходные принципы и различаются лишь особенностями реализации. Кроме того, отличительной особенностью современного этапа развития технологии программирования являются создание и внедрение автоматизированных технологий разработки и сопровождения программного обеспечения, которые были названы CASE-технологиями (Computer-Aided Software/System Engineering - разработка программного обеспечения/программных систем с использованием компьютерной поддержки). Без средств автоматизации разработка достаточно сложного программного обеспечения на настоящий момент становится трудно осуществимой: память человека уже не в состоянии фиксировать все детали, которые необходимо учитывать при разработке программного обеспечения. CASEтехнологии поддерживают как структурный, так и объектный (компонентный) подходы к программированию [1, 9]. Технология СОМ фирмы Microsoft является развитием технологии OLE I (Object Linking and Embedding - связывание и внедрение объектов), которая использовалась в ранних версиях Windows для создания составных документов. Она определяет общую концепцию взаимодействия программ любых типов (библиотек, приложений, операционной системы), т. е. позволяет одной части программного обеспечения использовать функции (службы), предоставляемые другой (рисунок А.4). Модификация СОМ, обеспечивающая передачу вызовов между компьютерами, называется DCOM (Distributed COM - распределенная СОМ). На базе технологии СОМ и ее распределенной версии DCOM были разработаны компонентные технологии, решающие различные задачи разработки ПО. На возможностях COM базируется технология COM+, которая обеспечивает поддержку распределенных приложений на компонентной основе и предназначена для поддержки систем обработки транзакций [1, 9]. Кроме того, к технологиям, реализующим компонентный подход, заложенный в СОМ, относятся: а) OLE-automation - технология создания программируемых приложений, обеспечивающая программируемый доступ к их внутренним службам (например, MS Excel поддерживает ее, предоставляя другим приложениям свои службы); б) ActiveX - технология, построенная на базе OLE-automation и предназначенная для создания как сосредоточенного на одном компьютере программного обеспечения, так и распределенного в сети. Предполагает использование визуального программирования для создания компонентов - элементов управления ActiveX, которые устанавливаются на компьютер дистанционно с удаленного сервера и применяются в клиентских частях приложений Интернет; в) MTS (Microsoft Transaction Server - сервер управления транзакциями) - технология, обеспечивающая безопасность и стабильную работу распределенных приложений при больших объемах передаваемых данных; г) MIDAS (Multitier Distributed Application Server - сервер многозвенных распределенных приложений) - технология, организующая доступ к данным разных компьютеров с учетом балансировки нагрузки сети. Технология CORBA, разработанная группой компаний OMG (Object Management Group - группа внедрения объектной технологии программирования), реализует подход аналогичный СОМ на базе объектов и интерфейсов CORBA. Программное ядро CORBA реализовано для всех основных аппаратных и программных платформ, и потому технологию можно использовать для создания распределенного программного обеспечения в разнородной вычислительной среде. Организация взаимодействия между объектами клиента и сервера в CORBA осуществляется с помощью посредника (VisiBroker) и специализированного программного обеспечения. К сожалению, в силу ряда причин разработчики были вынуждены отказаться от этой технологии [1, 9]. Сегодня CORBA, главным образом, используется для связывания компонентов, выполняемых внутри корпоративных сетей, в которых коммуникации защищаются брандмауэрами от внешнего мира. Технология CORBA используется также при разработке систем реального времени и встроенных систем, секторе, в котором CORBA действительно развивается. Однако в целом CORBA находится в упадке, и теперь ее нельзя назвать никак иначе, кроме как нишевой технологией. Лекция №2. Особенности разработки сложных программных систем Цель – получить представление о принципах разработки сложных программных систем и их жизненном цикле; изучить основные этапы разработки программного обеспечения и их особенности. Большинство современных программных систем являются достаточно сложными. Эта сложность обуславливается многими причинами, главной из которых является логическая сложность решаемых ими задач. Раньше компьютеры применяли в очень узких областях науки и техники, в первую очередь там, где задачи были хорошо детерминированы и требовали значительных вычислений. Сейчас, когда созданы мощные компьютерные сети, появилась возможность переложить на них решение сложных ресурсоемких задач, о компьютеризации которых раньше не задумывались. В процесс компьютеризации вовлекаются новые предметные области, а для освоенных областей усложняются уже сложившиеся постановки задач. Сложность разработки программных систем увеличивается за счет сложности формального определения требований к этим системам, отсутствия удовлетворительных средств описания поведения дискретных систем с большим числом состояний при недетерминированной последовательности входных воздействий, коллективной разработки, необходимости увеличения степени повторяемости кодов. Однако все эти факторы напрямую связаны со сложностью объекта разработки - программной системы [1, 9]. Подавляющее большинство сложных систем имеет иерархическую внутреннюю структуру. Связи элементов сложных систем различны как по типу, так и по силе, что и позволяет, рассматривать эти системы как некоторую совокупность взаимозависимых подсистем. Внутренние связи элементов таких подсистем сильнее, чем связи между подсистемами. Так, компьютер состоит из процессора, памяти и внешних устройств, а Солнечная система включает Солнце и планеты, вращающиеся вокруг него. Используя то же различие связей, каждую подсистему можно аналогично разделить на подсистемы до «элементарного» уровня. На этом уровне система, состоит из немногих типов подсистем, по-разному скомбинированных и организованных. Иерархии такого типа получили название «целое-часть». В природе существует еще один вид иерархии - иерархия «простоесложное» или иерархия развития (усложнения) систем в процессе эволюции. В этой иерархии любая функционирующая система является результатом развития более простой системы. Именно этот вид иерархии реализуется механизмом наследования объектно-ориентированного программирования. Будучи отражением природных и технических систем, программные системы являются иерархическими и обладают описанными выше свойствами. На этих свойствах иерархических систем строится блочно-иерархический подход к их исследованию или созданию, предполагающий сначала создание частей объекта (блоков и модулей), а затем сборку из них самого объекта. Процесс разбиения сложного объекта на сравнительно независимые части получил название декомпозиции. При декомпозиции учитывают, что связи между отдельными частями должны быть слабее, чем связи элементов внутри частей. Чтобы из полученных частей можно было собрать разрабатываемый объект, в процессе декомпозиции необходимо определить все виды связей частей между собой. При создании сложных объектов процесс декомпозиции выполняется многократно: каждый блок, в свою очередь, декомпозируют на части, пока не получают блоки, которые сравнительно легко разработать. Этот метод разработки получил название пошаговой детализации. В процессе декомпозиции стараются выделить аналогичные блоки, которые можно было бы разрабатывать на общей основе. Таким образом, обеспечивают увеличение степени повторяемости кодов и снижение стоимости разработки. Результат декомпозиции обычно представляют в виде схемы иерархии, на нижнем уровне которой располагают сравнительно простые блоки, а на верхнем - объект, подлежащий разработке [1, 6]. На каждом иерархическом уровне описание блоков выполняют с определенной степенью детализации, абстрагируясь от несущественных деталей. Как правило, для объекта в целом, удается сформулировать лишь общие требования, а блоки нижнего уровня должны быть специфицированы таким образом, чтобы из них действительно можно было собрать работающий объект. Другими словами, чем больше блок, тем более абстрактным должно быть его описание (рисунок А.5). При соблюдении этого принципа разработчик сохраняет возможность осмысления проекта и принимает наиболее правильные решения на каждом этапе, что называют локальной оптимизацией (в отличие от глобальной оптимизации характеристик объектов, которая для действительно сложных объектов не всегда возможна). Итак, в основе блочно-иерархического подхода лежат иерархическое упорядочение и декомпозиция. Важную роль играют следующие принципы: а) непротиворечивость - контроль согласованности элементов; б) полнота - контроль на присутствие лишних элементов; в) формализация - строгость методического подхода; г) повторяемость - необходимость выделения одинаковых блоков для удешевления и ускорения разработки; д) локальная оптимизация - оптимизация в пределах уровня иерархии. Совокупность языков моделей, постановок задач, методов описаний некоторого иерархического уровня принято называть уровнем проектирования. Различные взгляды на объект проектирования принято называть аспектами проектирования. Достоинства блочно-иерархического подхода: • упрощение проверки работоспособности отдельных блоков и системы в целом; • возможность создания сложных систем; • обеспечение возможности модернизации систем. Использование блочно-иерархического подхода применительно к программным системам стало возможным только после конкретизации общих положений подхода и внесения изменений в процесс проектирования. При этом структурный подход учитывает только свойства иерархии: «целое - часть», а объектный дополнительно использует свойства иерархии: «простое - сложное». Жизненным циклом программного обеспечения называется период от момента появления идеи создания некоторого программного обеспечения до момента завершения его поддержки фирмой-разработчиком или фирмой, выполняющей сопровождение [1, 9]. Состав процессов жизненного цикла регламентируется международным стандартом ISO/IEC 12207: 1995 «Information Technologe - Software Life Cycle Processes» («Информационные технологии - Процессы жизненного цикла программного обеспечения»). В стандарте описывается структура жизненного цикла программного обеспечения, определяются его процессы, не конкретизируя в деталях их реализацию. Процесс жизненного цикла – это совокупность взаимосвязанных действий, преобразующих некоторые входные данные в выходные. На рисунке А.6 представлены процессы жизненного цикла по указанному стандарту. Согласно этой структуре, процессы разработки и сопровождения ПО относятся к основным процессам [1, 9]. Условно выделяют следующие основные этапы разработки программного обеспечения: а) постановка задачи - формулируется назначение программного обеспечения, а также определяются основные требования к нему (функциональные и эксплуатационные). Результатами являются техническое задание (ТЗ), фиксирующее принципиальные требования, и принятие основных проектных решений; б) анализ требований и разработка спецификаций - выполняется анализ требований ТЗ, формулируется содержательная постановка задачи, строится модель предметной области, определяются подзадачи и выбираются или разрабатываются методы их решения, формируются тесты для поиска ошибок в проектируемом ПО с указанием ожидаемых результатов, т.е. разрабатывается общая логическая модель проектируемого ПО; в) проектирование - определяются подробные спецификации разрабатываемого программного продукта, выполняется проектирование общей структуры, декомпозиция компонентов и проектирование компонентов. Результат - детальная модель разрабатываемого ПО со спецификациями компонентов всех уровней; г) реализация - процесс поэтапного написания кодов программы на выбранном языке программирования (кодирование), их тестирование и отладка. Сопровождение - это процесс создания и внедрения новых версий программного обеспечения. В соответствии со стандартом ISO/IEC 12207 этап сопровождения был выделен в отдельный процесс жизненного цикла. Причинами выпуска новых версий могут служить: необходимость исправления ошибок, выявленных в процессе эксплуатации предыдущих версий; необходимость совершенствования предыдущих версий; изменение среды функционирования (появление новых технических средств и/или программных продуктов, с которыми взаимодействует сопровождаемое программное обеспечение); в программный продукт вносят необходимые изменения, которые могут потребовать пересмотра уже принятых проектных решений. Изменение жизненного цикла программного обеспечения стало возможным в результате использования при разработке программного обеспечения CASE-технологий, которые представляют собой совокупность методологий анализа, проектирования, разработки и сопровождения сложных программных систем, основанных как на структурном, так и на объектном подходах. В основу любой CASE-технологии положены методология, метод, нотация и средства [1, 9]. Среди средств различают: 1) CASE-средства анализа требований, проектирования спецификаций и структуры, редактирования интерфейсов. Первое поколение CASE-I, в основном включают средства для поддержки графических моделей, проектирования спецификаций, экранных редакторов и словарей данных; 2) CASE-средства генерации исходных текстов и реализации интегрированного окружения поддержки полного жизненного цикла разработки программного обеспечения. Второе поколение CASE-II существенно отличается большими возможностями, обеспечивая контроль, анализ и связывание системной информации и информации по управлению процессом проектирования, построение прототипов и моделей системы, тестирование, верификацию и анализ сгенерированных программ. Современные CASE-средства позволяют автоматизировать трудоемкие операции; повысить производительность труда программистов; улучшить качество создаваемого программного обеспечения; уменьшить время создания прототипа системы; автоматизировать формирование проектной документации для всех этапов жизненного цикла в соответствии с современными стандартами; частично генерировать коды программ для различных платформ разработки; применять технологии повторного использования компонентов системы и т. д. Однако современные CASE-средства дороги, а их использование требует более высокой квалификации разработчиков. Следовательно, имеет смысл использовать их в сложных проектах, причем, чем сложнее разрабатываемое программное обеспечение, тем больше выигрыш от использования CASE-технологий. На сегодняшний день практически всё промышленно производимое сложное программное обеспечение разрабатывается с использованием CASE-средств. Лекция №3. Структурное и неструктурное программирование. Основы алгоритмизации Цель – получить представление об особенностях структурного и неструктурного программирования; изучить особенности представления алгоритмов, а также основные алгоритмические структуры. Одним из способов обеспечения высокого уровня качества разрабатываемого программного обеспечения является структурное программирование. В основе любой программы лежит алгоритм. Понятие «алгоритм» происходит от имени математика IX в. Аль Хорезми, который сформулировал правила выполнения арифметических действий. Первоначально под алгоритмом понимали только правила выполнения четырех арифметических действий над числами. В дальнейшем это понятие стали использовать вообще для обозначения последовательности действий, приводящих к решению любой поставленной задачи. Алгоритм решения вычислительной задачи - это формальное описание способа решения задачи путем разбиения ее на конечную по времени последовательность действий (этапов), понятных исполнителю. При этом должны быть четко указаны как содержание каждого этапа, так и порядок выполнения этапов. Отдельный этап алгоритма либо представляет собой другую, более простую задачу, алгоритм которой разработан ранее, либо должен быть достаточно простым и понятным без пояснений. Основными свойствами алгоритма являются: 1) детерминированность (определенность) - получение однозначного результата вычислительного процесса при заданных исходных данных, поэтому процесс выполнения алгоритма носит механический характер; 2) результативность - реализуемый по заданному алгоритму вычислительный процесс должен через конечное число шагов остановиться и выдать из исходных данных искомый результат; 3) массовость - алгоритм должен быть пригоден для решения всех задач данного типа; 4) дискретность - расчлененность вычислительного процесса на отдельные этапы. Существует несколько способов записи алгоритмов: словесный, формульно-словесный, графический, язык операторных схем, алгоритмический язык. Наибольшее распространение благодаря своей наглядности получил графический способ записи алгоритмов с помощью блок-схем. Блок-схемой называется графическое изображение логической структуры алгоритма, в котором каждый этап процесса обработки информации представляется в виде геометрических символов (блоков), имеющих определенную конфигурацию в зависимости от характера выполняемых операций. Графические символы, их размеры и правила построения схем алгоритмов определены Единой системой программной документации (ЕСПД), являющейся государственным стандартом (ГОСТ). Перечень символов, их наименование, отображаемые ими функции, форма и размеры определяются ГОСТами (таблица Б.1). Все формулы в блок-схеме записываются на языке математики, а не конкретном языке программирования. Различают три вида вычислительного процесса, реализуемого программами: линейный, разветвленный и циклический. Линейная структура процесса вычислений предполагает, что для получения результата необходимо выполнить операции в определенной последовательности. При разветвленной структуре процесса вычислений конкретная последовательность операций зависит от значений одной или нескольких переменных. Для получения результата при циклической структуре некоторые действия необходимо выполнить несколько раз. Для реализации этих вычислительных процессов в программах используют соответствующие управляющие операторы. Программы, написанные с использованием только структурных операторов передачи управления, называют структурными, чтобы подчеркнуть их отличие от программ, разрабатываемых с использованием низкоуровневых способов передачи управления. После того, как в 60-х годах XX в. было доказано, что любой сложный алгоритм можно представить, используя три основные управляющие конструкции, в языках программирования высокого уровня появились управляющие операторы для их реализации [3, 4]. К базовым относят: а) следование - обозначает последовательное выполнение действий; б) ветвление - выбор одного из двух вариантов действий; в) цикл-пока - определяет повторение действий, пока не будет нарушено некоторое условие, выполнение которого проверяется в начале цикла. Кроме базовых, процедурные языки программирования высокого уровня используют три дополнительные конструкции, реализуемые через базовые: а) выбор - выбор одного варианта из нескольких в зависимости от значения некоторой величины; б) цикл-до - повторение действий до выполнения заданного условия, проверка которого осуществляется после выполнения действий в цикле; в) цикл с заданным числом повторений (счетный цикл) - повторение некоторых действий указанное количество раз. Перечисленные конструкции были положены в основу структурного программирования. Программы, написанные с использованием только структурных операторов передачи управления, называют структурными, чтобы подчеркнуть их отличие от программ, разрабатываемых с использованием низкоуровневых способов передачи управления. Недостатки схем: а) низкий уровень детализации, что скрывает суть сложных алгоритмов; б) использование неструктурных способов передачи управления, которые на схеме выглядят проще, чем эквивалентные структурные. Пример 3.1 – Использование блок-схемы для описания алгоритма поиска в массиве А(n) элемента, равного заданному (рисунок 3.1). Рисунок 3.1 – Фрагмент блок-схемы алгоритма поиска В приведенном примере используется структурный вариант алгоритма (цикл-пока). Элементы массива перебираются и поочередно сравниваются с заданным значением Y. В результате выводится соответствующее сообщение. К недостаткам блок-схем можно отнести следующие: а) низкий уровень детализации, что скрывает суть сложных алгоритмов; б) использование неструктурных способов передачи управления, которые на схеме выглядят проще, чем эквивалентные структурные. Кроме схем, для описания алгоритмов можно использовать псевдокоды, Flow-формы и диаграммы Насси-Шнейдермана, которые базируются на тех же основных структурах, допускают разные уровни детализации и делают невозможным описание неструктурных алгоритмов [1, 3, 8]. Псевдокод - формализованное текстовое описание алгоритма (текстовая нотация в нескольких вариантах, таблица В.1). Изначально ориентирует проектировщика только на структурные способы передачи управления, не ограничивают степень детализации проектируемых операций, позволяют соизмерять степень детализации действия с рассматриваемым уровнем абстракции и хорошо согласуются с методом пошаговой детализации. Пример 3.2 – Использование псевдокода для описания алгоритма поиска в массиве А(n) элемента, равного заданному (фрагмент). i:=1 Цикл-пока i  n и A(i)  Y i:= i + 1 Все-цикл Если i  n то Вывести «Элемент найден» иначе Вывести «Элемент не найден» Все-если Flow-формы - графическая нотация описания структурных алгоритмов, иллюстрирующая вложенность структур. Каждому символу Flow-формы соответствует управляющая структура, изображаемая в виде прямоугольника и содержащая текст в математической нотации или на естественном языке. Для демонстрации вложенности структур символ Flow-формы вписывается в соответствующую область прямоугольника любого другого символа. В таблице В.1 приведены символы Flow-форм, соответствующие основным и дополнительным управляющим конструкциям. Пример 3.3 – Использование Flow-форм для описания алгоритма поиска в массиве А(n) элемента, равного заданному (рисунок 3.2). i:=1 Пока i  n и A(i)  Y i:= i + 1 Если i  n то иначе Вывести «Элемент найден» Вывести «Элемент не найден» Рисунок 3.2 – Flow-форма алгоритма поиска (фрагмент) Диаграммы Насси-Шнейдермана являются развитием Flow-форм лишь с той разницей, что область обозначения условий и вариантов ветвления изображают в виде треугольников (таблица В.1), обеспечивающих большую наглядность представления алгоритма. Пример 3.4 – Использование диаграмм Насси-Шнейдермана для описания алгоритма поиска в массиве А(n) элемента, равного заданному (рисунок 3.3). Рисунок 3.3 – Фрагмент диаграммы Насси-Шнейдермана Так же, как при использовании псевдокодов описать неструктурный алгоритм, применяя Flow-формы или диаграммы Насси-Шнейдермана, невозможно (отсутствуют условные обозначения). В то же время, являясь графическими, эти нотации лучше отображают вложенность конструкций, чем псевдокоды. Недостаток: сложность построения изображений символов усложняет их практическое применение для описания больших алгоритмов. Лекция №4. Алгоритмические языки и предъявляемые к ним требования. Процедурные языки Цель – получить представление об основных характеристиках алгоритмических языков и их классификации; изучить особенности использования процедурных языков. Языки программирования, которые используются при записи алгоритмов, обладают рядом характеристик, которые позволяют классифицировать, сравнивать и выбирать их с учетом целей разработки программы. К таким характеристикам относятся мощность, уровень и целостность [11]. Мощность языка характеризуется разнообразием задач, алгоритмы которых можно записать, используя этот язык. Поэтому, очевидно, что самым мощным является язык процессора, так как любая задача в конечном итоге записывается на языке компьютера. Уровень языка определяется сложностью решения задач с использованием этого языка. Чем проще записывается решение, тем более непосредственно выражаются сложные операции и понятия, тем меньше объем получаемых исходных программ и, наконец, тем выше уровень языка. Целостность языка обусловлена свойствами экономии, независимости и единообразия понятий. Экономия понятий предполагает достижения максимальной мощности языка при условии использования минимального числа понятий. Независимость понятий означает, что правила использования одного и того же понятия в разных контекстах также должны быть одними и теми же, кроме того, между ними не должно быть взаимного влияния. Единообразие понятий требует единого согласованного подхода к описанию и использованию всех понятий. Традиционно при классификации языков программирования используется такая характеристика, как уровень языка (рисунок 4.1). На нижних уровнях размещаются машинно-ориентированные языки, а на верхних – машинно-независимые. Рисунок 4.1 – Классификация языков программирования по уровню Машинно-ориентированные языки позволяют в полной мере учитывать особенности процессора и получать программы с высокой степенью быстродействия. Однако они не способны обеспечить мобильность (переносимость) программ между разнотипными компьютерами. Под мнемокодами подразумеваются языки ассемблера без макросредств, к макроязыкам относятся языки ассемблера с макросредствами. Машинно-независимые языки еще называются языками высокого уровня. Процедурные языки - это алгоритмические языки, которые предназначены для описания процедуры решения задачи, то есть программист должен указать компьютеру, что и как следует сделать для решения задачи. Среди процедурных выделяют группу универсальных языков, пригодных для решения любых задач (например, Паскаль, С/С++, Ада). Непроцедурные (проблемные) языки позволяют указать компьютеру, что нужно сделать для решения задачи, а как это сделать - система программирования решает автоматически. Среди проблемных языков выделяют языки СУБД, объектноориентированные, веб-программирования, функциональные, логические и другие. Каждая из этих групп отличается от других не уровнем, а принципами программирования. Таким образом, классификация, которая показана на рисунке 4.1, содержит 5 уровней языков: 0 – машинные, 1 – мнемокоды, 2 – макроязыки, 3 – процедурные, 4 – проблемные языки. Но в связи с тенденцией универсализации языков, эта классификация уже не является строгой, поскольку языки ассемблеров приобрели средства, присущие языкам высокого уровня, а язык С++ вообще имеет признаки как высокоуровневого, так и низкоуровневого языка. Поэтому класс языка имеет смысл определять по уровню его основополагающих средств. При использовании любого языка необходимо следить за тем, чтобы все записываемые с его помощью предложения (строки) были корректны с точки зрения алфавитных конструкций (синтаксически) и имело определенный смысл (семантику). Переводом программы с исходного языка, на котором она написана, на машинный занимается программа - транслятор. В исходных текстах программ, как правило, используются комментарии, т. е. пояснительный текст, оформленный определенным образом и никоим образом не влияющий на ход выполнения программы. Для идентификации (обозначения) всех объектов, вводимых в программу, используются имена (идентификаторы). Под объектами понимаются переменные, константы, типы данных, функции и т. д. Для каждого языка четко определены правила, согласно которым вводятся обозначения. Ключевые (служебные) слова имеют однозначно определенный смысл и могут использоваться только так, как это задано в языке. Ключевые слова не могут быть переопределены, т. е. их нельзя использовать в качестве имен, вводимых программистом [1, 6, 7]. Лекция №5. Введение в язык С++. Структура и этапы создания программы на языке С++. Стандарты языка С++ Цель – получить представление о языке программирования С++, его особенностях, структуре программ и процессе их создания. Язык программирования высокого уровня C++ был разработан в США в начале 80-х годов сотрудником компании Bell Laboratories Бьерном Страуструпом (Bjarne Stroustrup) в результате расширения и дополнения языка С средствами, необходимыми для объектно-ориентированного программирования. Среди современных языков С++ относится к классу универсальных и по праву считается господствующим языком, используемым для разработки коммерческих программных продуктов. Пожалуй, лишь такой язык программирования, как Java может составлять ему конкуренцию. Разновидностью С++ является С# - новый язык, разработанный Microsoft для сетевой платформы. Несмотря на ряд принципиальных отличий, языки С++ и С# совпадают примерно на 90%. Особенно эффективно применение С++ в написании системных программ-трансляторов, операционных систем, экранных интерфейсов. В этом языке сочетаются лучшие свойства Ассемблера и языков программирования высокого уровня. Программы, выполненные на языке С++, по быстродействию сравнимы с программами, написанными на Ассемблере, но более наглядны, просты в сопровождении и легко переносимы с одного компьютера на другой. К основным особенностям языка относят следующие: • С++ предлагает большой набор операций, многие из которых соответствуют машинным командам и поэтому допускают прямую трансляцию в машинный код, а их разнообразие позволяет выбирать различные наборы для минимизации результирующего кода; • базовые типы данных С++ совпадают с типами данных Ассемблера, на преобразования типов налагаются незначительные ограничения; • объем С++ невелик, т.к. практически все выполняемые функции оформлены в виде подключаемых библиотек, также C++ полностью поддерживает технологию структурного программирования и обеспечивает полный набор соответствующих операторов; • С++ широко использует указатели на переменные и функции, кроме того, поддерживает арифметику указателей, и тем самым позволяет осуществлять непосредственный доступ и манипуляции с адресами памяти; удобным средством для передачи параметров являются ссылки; • C++ содержит в себе все основные черты объектно-ориентированных языков программирования: наличие объектов и инкапсуляцию данных, наследование, полиморфизм и абстракцию типов. При написании программ на языке С++ используются следующие понятия: алфавит, константы, идентификаторы, ключевые слова, комментарии, директивы [2, 5]. Алфавитом называют присущий данному языку набор символов, из которых формируются все конструкции языка. Язык C++ оперирует со следующим набором символов: латинские прописные и строчные буквы (А, В, С, ..., х, у, z); арабские цифры (0, 1, 2, ..., 7, 8, 9); символ подчеркивания («_»); специальные символы (список специальных символов языка C++ приведен в таблице Г.1); символы-разделители (пробелы, комментарии, концы строк и т.д.). С помощью перечисленных символов формируются имена, ключевые (служебные) слова, числа, строки символов, метки. Идентификаторы (имена) обязательно начинаются с латинской буквы или символа подчеркивания «_», за которыми могут следовать в любой комбинации латинские буквы и цифры. C++ различает прописные и строчные буквы. Не допускается использование для написания имен специальных символов и символов-разделителей. Например, _х, В12, Stack - правильно; Label.4, Root-3 - неправильно. Существуют некоторые соглашения относительно использования прописных и строчных букв в идентификаторах. Например, имена переменных содержат только строчные буквы, константы и макросы – прописные. С символа подчеркивания обычно начинаются имена системных зарезервированных переменных и констант, а также имена, используемые в библиотечных функциях. Поэтому во избежание возможных конфликтов и взаимопересечений с множеством библиотечных имен не рекомендуется использовать знак подчеркивания в качестве первого символа имени. Некоторые идентификаторы, имеющие специальное значение для компилятора, употребляются как ключевые слова. Их употребление строго определено, и они не могут использоваться иначе. Список зарезервированных слов в C++ приведен в таблице Г.2. Числа, обозначающие целые и вещественные значения, записываются в десятичной системе счисления. Перед любым числом может стоять знак «+» или «-». В вещественном числе целая часть числа отделяется от его дробной части точкой. Вещественные числа, содержащие десятичную точку, должны иметь перед ней или после нее, по крайней мере, по одной цифре. Имя метки перехода представляет собой символьно-цифровую конструкцию, например, metkal, pass, cross15, и в программе не объявляются. Строка символов — это последовательность символов, заключенная в кавычки. Например, «Строка символов». Различают два вида комментариев. Любая последовательность символов, заключенная в ограничивающие скобки /* */, в языках С/С++ рассматривается как многострочный комментарий, например, /*Главная программа*/. В языке С++ дополнительно имеется еще один вид комментария – однострочный: все символы, следующие за знаком // (двойной слеш) до конца строки, рассматриваются как комментарий, например, //Главная программа. В основном, используют комментарий стиля С++ (//), а комментарий стиля C (/* */) применяют для временного отключения больших участков программы. Следует помнить, что комментарии должны пояснять, не что это за операторы, а для чего они здесь используются. Программа, записанная на языке С/C++, обычно состоит из одной или нескольких функций. Функция – это самостоятельная единица программы, созданная для решения конкретной задачи, которая может оперировать данными и возвращать значение. Структура программы представлена на рисунке 5.1. Каждая программа на языке C++ начинается с директивы препроцессора #include, которая подключает заголовочный файл (*.h), содержащий прототипы функций, которые сообщают компилятору информацию о синтаксисе функции, например, # include Заголовочный файл обычно содержит определения, предоставляемые компилятором для выполнения различных операций. Заголовочные файлы записаны в формате ASCII, их содержимое можно вывести для просмотра с помощью любого текстового редактора из каталога INCLUDE. Препроцессор просматривает программу до компилятора, подключает необходимые файлы, заменяет символические аббревиатуры в программе на соответствующие директивы и даже может изменить условия компиляции. Каждая программа на C++ содержит, по крайней мере, одну функцию – main(), которая автоматически вызывается при запуске, может вызывать другие имеющиеся в программе функции и обычно имеет вид: void main ( ) Подключение заголовочных файлов Определение функций программы Определение главной функции Начало тела главной функции Операторы функции Вызов функций программы Конец тела главной функции Рисунок 5.1 – Структура программы на языке С++ Обычную функцию необходимо вызывать (обращаться к ней) программно, в ходе выполнения кода. Функция main() вызывается операционной системой, и обратиться к ней из кода программы невозможно. Слово void служит признаком того, что программа не возвращает конкретного значения. В случае возврата значения операционной системе перед функцией main() указывается слово int, а в конце тела этой функции помещается выражение return() или return0. После определения главной функции следуют операторы программы, которые заключены в группирующие фигурные скобки { }. Каждый оператор оканчивается точкой с запятой (;), указывающей на его завершение. Программа выполняется по строкам, в порядке их расположения в исходном коде, до тех пор, пока не встретится вызов какой-нибудь функции, тогда управление передается строкам этой функции. После выполнения функции управление возвращается той строке программы, которая следует за вызовом функции [2, 5, 10]. Лекция №6. Представление данных в языке С++. Оператор присваивания. Арифметические операции. Директивы препроцессора Цель – получить представление о стандартных типах данных, порядке выполнения операций, изучить особенности оператора присваивания и использования препроцессора. Определяя данные, необходимо предоставить компилятору информацию об их типе, тогда ему будет известно, сколько места нужно выделить (зарезервировать) для хранения информации и какого рода значение в ней будет находиться. В С++ определены пять базовых типов данных: символьные (char), целые (int), вещественный с плавающей точкой (float), вещественный с плавающей точкой двойной длины (double), а также пустой, не имеющий значения тип (void). На основе перечисленных типов строятся все остальные. Простейшим приемом является использование модификаторов типа, которые ставятся перед соответствующим типом: знаковый (signed), беззнаковый (unsigned), длинный (long) и короткий (short). В таблице Г.3 приведены все возможные типы с различными комбинациями модификаторов с указанием диапазона изменения и занимаемого размера в байтах. При многократном использовании в программе типов данных с различными комбинациями модификаторов, например, unsigned short int, легко сделать синтаксические ошибки, во избежание которых в С++ предусмотрена возможность создания псевдонима (синонима) с помощью ключевого слова typedef. Например, строка typedef unsigned short int USHORT; создает новый псевдоним USHORT, который может использоваться везде, где нужно было бы написать unsigned short int. Переменная – это имя, связанное с областью памяти, которая отведена для временного размещения хранимого значения и его последующего извлечения. Для длительного (постоянного) хранения значений переменных используются базы данных или файлы. В С++ все переменные должны быть объявлены до их использования. Объявление предполагает наличие имени переменной и указание ее типа. Однако следует иметь в виду, что нельзя создать переменную типа void. Основная форма объявления переменных имеет вид тип <список_переменных>; В этом объявлении: тип – один из существующих типов переменных; <список_переменных> может состоять из одной или нескольких переменных, разделенных запятыми. Например, int x, e, z; float radius; long double integral; Можно объявлять переменные и одновременно присваивать им начальные значения, т.е. инициализировать их. Например, int min=15; float p1=1.35; Переменная называется глобальной, если она объявлена вне каких-либо функций, в том числе функции main(). Такая переменная может использоваться в любом месте программы (за исключением глобальных статических переменных), а при запуске программы ей присваивается нулевое значение. Переменная, объявленная внутри тела функции (одного блока), является локальной и может использоваться только внутри этого блока. Вне блока она неизвестна. Важно помнить, что: • две глобальные переменные не могут иметь одинаковые имена; • локальные переменные разных функций могут иметь одинаковые имена; • локальные переменные в одном блоке не могут иметь одинаковые имена. Данные в языках программирования могут представляться также в виде констант. Константы используются в тех случаях, когда программе запрещено изменять значение какой-либо переменной. Для определения константы традиционным способом используется #define, которая просто выполняет текстовую подстановку. Например, #define StudentsOfGroup 15 В данном случае константа StudentsOfGroup не имеет конкретного типа и каждый раз, когда препроцессор встречает имя StudentsOfGroup, он заменяет его литералом 15. Поскольку препроцессор запускается раньше, компилятор никогда не увидит константу, а будет видеть только число 15. Наиболее удобным способом определения констант является следующий: const тип имя_константы = значение_константы; Этот способ облегчает дальнейшее сопровождение программы и предотвращает появление ошибок. Так как определение константы содержит тип, компилятор может проследить за ее применением только по назначению (в соответствии с объявленным типом). Например, const int Diapazon=20; Литеральные константы (литералы) – это значения, которые вводятся непосредственно в текст программы. Поскольку после компиляции нельзя изменить значения литералов, их также называют константами. Например, в выражении int MyAge=19; имя MyAge является переменной типа int, а число 19 – литеральной константой, которой нельзя присвоить никакого иного значения. Символьная константа состоит из одного символа, заключенного в апострофы: ‘q’, ‘2’, ‘$’. Например, const char month=’December’; . К символьным константам относятся специальные символы (в том числе управляющие, список приведен в таблице Г.1). Строковые константы состоят из последовательности символов кода ASCII, заключенной в кавычки, оканчивающейся нулевым байтом. Конец символьной строки (нулевой байт) обозначается символом NULL ('\0'). Перечислимые константы позволяют создавать новые типы данных, а затем определять переменные этих типов, значения которых ограничены набором значений константы. Для создания перечисляемой константы используется ключевое слово enum, а запись имеет вид: enum имя_константы {список_значений_константы}; Значения константы в списке значений разделяются запятыми. Например, enum COLOR {RED, BLUE, GREEN, WHITE, BLACK}; Каждому элементу перечисляемой константы соответствует определенное значение. По умолчанию, первый элемент имеет значение 0, а каждый последующий - на единицу большее. Каждому элементу константы можно присвоить произвольное значение, тогда последующие инициализируются значением на единицу больше предыдущего. Например, enum COLOR {RED=100, BLUE, GREEN=200, WHITE=300, BLACK}; В этом примере значение BLUE=101, BLACK=301. Существует механизм явного задания типов констант с помощью суффиксов. Для констант целого типа в качестве суффиксов могут использоваться буквы u, l, h, L,H, а для чисел с плавающей точкой – l, L, f, F. Например, 12h 34H - short int 23L -273l - long int 23.4f 67.7E-24F - float 89uL 89Lu 89ul 89 LU - unsigned short Выражение в языке С++ представляет собой некоторую допустимую комбинацию операций и операндов (констант, переменных или функций). Перечень операций языка C++ приведен в таблице Г.4. Все перечисленные операции выполняются традиционным способом, за исключением операции деления. Особенность операции деления заключается в том, что если оба операнда целого типа, то она даст целый результат, например, 3/2 даст 1. Для получения действительного результата необходимо иметь хотя бы один действительный операнд, например, 3/2.0 даст 1.5. Для каждой операции языка определено количество операндов: а) один операнд – унарная операция, изменяющая знак, например, унарный минус –х; б) два операнда – бинарная операция, например, операция сложения х+у; в) три операнда – операция условие ?:, она единственная. Каждая операция может иметь только определенные типы операндов. Каждая бинарная операция имеет определенный порядок выполнения: слева направо или справа налево. Наконец, каждая операция имеет свой приоритет. Приоритет и порядок выполнения операций приводятся в таблице Г.4. Часто в выражениях используются математические функции языка C++, которые находятся в библиотеке math. Чтобы воспользоваться этими функциями в начало программы необходимо включить заголовочный файл . Основные математические функции приводятся в таблице Г.5. Все выражения являются операторами, которые в языке предназначены для описания действий. Любой оператор может быть помечен меткой. Операторы отделяются друг от друга точкой с запятой (;). В любом месте программы, где может быть размещен один оператор, можно разместить составной оператор, называемый блоком. Блок содержит несколько операторов, которые выполняются как одно выражение, ограничивается фигурными скобками {}, но не заканчивается точкой с запятой (;). Объявление переменной в программе означает всего лишь выделение места в памяти компьютера для ее размещения. Программа же должна позволять оперировать данными. В этом процессе наиболее важна операция присваивания, которая выглядит следующим образом: переменная = выражение. Операция присваивания заменяет значение операнда, расположенного слева от знака «=», значением, вычисляемым справа от него. При этом могут выполняться неявные преобразования типа. Знак «=» в С/С++ - это знак присваивания, а не равенства. В отличие от других языков, где присваивание – оператор по определению, в С/С++ существуют понятия «операция присваивания» и «оператор присваивания». Операция «превращается» в оператор, если в конце выражения поставить точку с запятой, например, ++x – это выражение, а ++х ; - это оператор. Оператор присваивания удобно использовать при инициализации переменных, например, j=k;. Кроме того, в С/C++ операция присваивания может использоваться в выражениях, которые включают в себя операторы сравнения или логические операторы, например, if ((x=x+5)>0) cout<<"Вывод";. Еще одной особенностью использования операции присваивания в С/С++ является возможность многократного присваивания, которое выполняется справа налево. Например, для того, чтобы присвоить значение 2*k нескольким переменным, можно воспользоваться операцией: x=y=z=2*k. В языке С/C++ имеются дополнительные операции присваивания +=, -=, *=, /= и %=. При этом величина, стоящая справа, добавляется (вычитается, умножается, делится или делится по модулю) к значению переменной, стоящей слева. Например, вместо оператора х=х+5; можно записать х+=5;. Причем, операция х+=5 выполняется быстрее, чем операция х=х+5. Очень часто в программах к переменным добавляется (или вычитается) единица. Увеличение значения на 1 называется инкрементом (++), а уменьшение на 1 - декрементом (--). Например, оператор с=с+1; эквивалентен оператору с++;, оператор с=с-1; эквивалентен оператору с--;. Операторы инкремента и декремента существуют в двух вариантах: префиксном и постфиксном. Префиксные операции увеличивают (уменьшают) значение переменной на единицу, а затем используют это значение. Например, оператор х=++у; эквивалентен выполнению двух операторов у=у+1; х=у;. В этом примере сначала происходит увеличение на единицу значения переменной у, а затем присваивание этого значения переменной х. Постфиксные операции сначала используют значение переменной, после чего увеличивают (уменьшают) его. Например, оператор х=у--; эквивалентен выполнению двух операторов х=у; у=у-1;. В этом примере переменная х получает значение у, после чего значение у уменьшается на единицу. Вообще в выражениях лучше использовать операнды одного типа, но С++ допускает преобразование типов, то есть если операнды принадлежат к разным типам, то они приводятся к некоторому общему типу. Приведение выполняется в соответствии со следующими правилами: а) автоматически производятся лишь те преобразования, которые превращают операнды с меньшим диапазоном значений в операнды с большим диапазоном значений, т.к. это происходит без какой-либо потери информации; б) выражения, не имеющие смысла (например, число с плавающей точкой в роли индекса), не пропускаются компилятором еще на этапе трансляции; в) выражения, в которых могла бы потеряться информация (например, при присваивании длинных целых значений более коротким или действительных значений целым), могут вызвать предупреждение (warning), но они допустимы. В отличие от других языков программирования в С++ для любого выражения можно явно указать преобразование его типа, используя унарный оператор, называемый приведением типа. Выражение приводится к указанному типу по перечисленным правилам конструкцией вида (имя типа) выражение; Например, (int) i=2.5*3.2; . Однако пользоваться этим оператором можно лишь в том случае, если вполне осознаются цель и последствия такого преобразования [2, 5, 10]. Лекция №7. Функции ввода/вывода. Основные конструкции языка С++ Цель – получить представление о функциях «ввода-вывода», используемых в С++, а также ознакомиться с особенностями использования основных конструкций языка. В любой достаточно сложной программе можно выделить линейные фрагменты. Фрагмент программы имеет линейную структуру, если все операции в нем выполняются последовательно, друг за другом, и может содержать операторы присваивания, математические функции, арифметические операции, функции «ввода-вывода» данных и другие операторы, не изменяющие общего порядка следования операторов. Редкая программа обходится без операций «ввода-вывода». В языке С были реализованы две новаторские идеи: средства «ввода-вывода» были отделены от языка и вынесены в отдельную библиотеку stdio (стандартная библиотека «ввода-вывода»), а также была реализована концепция процесса «ввода-вывода», независимого от устройств. Именно поэтому язык С++, унаследовавший черты своего «прародителя», имеет большой набор функций «ввода-вывода»данных различных типов. Для реализации форматного «ввода-вывода» часто используются две функции printf и scanf, подключаемые с помощью заголовочного файла . Функцию printf можно использовать для вывода любой комбинации символов, целых и вещественных чисел, строк, беззнаковых целых, длинных целых и беззнаковых длинных целых. Она описывается следующим образом: printf (“управляющая_строка”, список_аргументов);. Список аргументов – это последовательность констант, переменных или выражений, значения которых выводятся на экран в соответствии с форматом управляющей строки, которая определяет количество, тип аргументов и обычно содержит следующие объекты: обычные символы, выводимые на экран без изменений; спецификации преобразования, каждая из которых вызывает вывод на экран значения очередного аргумента из последующего списка аргументов; управляющие символьные константы (список наиболее используемых констант приводится в таблице Г.1). Спецификация преобразования начинается с символа % и заканчивается символом преобразования (таблица Г.6), между которыми могут записываться: • знак «минус», указывающий на то, что выводимый текст выравнивается по левому краю, по умолчанию, выравнивание происходит по правому краю; • строка цифр, задающая минимальный размер поля вывода; • точка, являющаяся разделителем; • строка цифр, задающая точность вывода; • символ l, указывающий, что соответствующий аргумент имеет тип long. Например, printf("\nВозраст Эрика - %d. Его доход $%.2f", age, income); Предполагается, что целой переменной age (возраст) и вещественной переменной income (доход) присвоены какие-то значения. Последовательность символов \n переводит курсор на новую строку, поэтому последовательность символов «Возраст Эрика» будет выведена с начала новой строки. Символы %d являются символами преобразования формата (спецификацией) для переменной age. Затем следует литерная строка «Его доход $» и символы %.2f - спецификация для значения переменной income, а также указание формата для вывода только двух цифр после десятичной точки. Функция ввода данных scanf описывается аналогично функции printf: scanf (“управляющая_строка”, список_аргументов); Аргументы функции scanf должны быть указателями на соответствующие значения (более подробно указатели будут рассмотрены позже), для чего перед именем переменной записывается символ &. Как и в функции printf, управляющая строка содержит спецификации преобразования и используется для установления количества и типов аргументов. В ней допустимо использование пробелов, символов табуляции и перехода на новую строку, которые игнорируются при вводе. В управляющей строке спецификации преобразования должны быть отделены теми же разделителями, что и при вводе с клавиатуры. Например, scanf (“%d %f %c”, &i, &a, &ch); Программы на С++ не имеют дело ни с устройствами, ни с файлами - они работают с потоками. Ввод информации осуществляется из входного потока, вывод производится в выходной поток, которые связаны с устройством или с файлом. В C++ концепция независимого от устройств «ввода-вывода» получила дальнейшее развитие в виде объектноориентированной библиотеки «ввода-вывода» iostream, в которую входят объект cout для вывода данных на экран и объект cin, используемый для ввода информации [7, 8]. Оператор вывода cout выглядит следующим образом: cout<<переменная1<<...<<переменнаяN; Знак “<<” называется операцией вставки, которая вставляет символы в выходной поток. Для перевода курсора в начало следующей строки в операторе cout часто используется символ endl (конец строки), например, cout<
Статья: Технологии программирования
Найди решение своей задачи среди 1 000 000 ответов
Найти решение задачи
«Технологии программирования» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Найди решение своей задачи среди 1 000 000 ответов
Найти

Тебе могут подойти лекции

Смотреть все 493 лекции
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot