Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
68
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

0

Вступ

Київський національний університет імені Тараса Шевченка

О.С. БИЧКОВ

Основи

сучасного

програмування

Підручник

УДК 004.432.2(075.8)

ББК 018.1я73

Б39

Рецензенти:

д-р техн. наук, проф. А.П. Власюк,

д-р техн. наук, проф. А.О. Сяський

Затверджено Вченою радою Київського національного університету імені Тараса Шевченка 5 березня 2007 року

Б39

Бичков, О.С.

Основи сучасного програмування : підручник / О.С. Бичков. – К.: Видавничо-поліграфічний центр "Київський університет", 2008. – 272 с.

ISBN 978-966-439-189-1

Розглянуто основи технології програмування, принципи типізації даних, зображення чисел у комп’ютері. Описано технологію програмування мовами Сі, Сі++, автоматну технологію. Класичний стиль викладу навчального матеріалу, що ґрунтується на численних прикладах, дозволяє розібратися самостійно в усіх конструкціях Сі++ та оволодіти певними прийомами й навичками програмування без залучення додаткової інформації.

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

УДК 004.432.2(075.8)

ББК 018.1я73

Гриф надано Міністерством освіти і науки України (лист № 1.4/18-г-1523 від 20.09.07)

Навчальне видання

Олексій Сергійович БИЧКОВ

ОСНОВИ СУЧАСНОГО ПРОГРАМУВАННЯ

Підручник

Редактор Н. Земляна

Оригінал-макет виготовлено Видавничо-поліграфічним центром "Київський університет"

Підписано до друку 26.12.08. Формат 70х1001/16. Вид. № 256. Гарнітура Bookman Old Style.

Папір офсетний. Друк офсетний. Наклад 200. Ум. друк. арк. 21,93. Обл.-вид. арк. 19,43. Зам. № 28-4632.

Видавничо-поліграфічний центр "Київський університет"

01030, Київ, б-р Т. Шевченка, 14, кімн. 43 (38044) 239 3222; (38044) 239 3172; факс (38044) 234 0105

e-mail: vydav_polygraph@.univ.kiev.ua

WWW: http:// vpc.univ.kiev.ua

Свідоцтво внесено до Державного реєстру ДК № 1103 від 31.10.02

ISBN 978-966-439-189-1 © Бичков О.С., 2008

© Київський національний університет імені Тараса Шевченка, ВПЦ "Київський університет", 2008

Передмова

Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного

У наш час існує велика кількість програмного забезпечення для автоматизації праці науковців. Це такі програмні продукти, як Maple, Mathematica, MathCad. Однак часто виникає необхідність самостійного написання бібліотек програмного забезпечення для заданої замовником предметної галузі. Для цього потрібні прикладні програмісти високого рівня кваліфікації.

У пропонованому підручнику викладено основи проектування програмного забезпечення. Матеріал базується на мовах Сі та Сі++.

Деякі розділи мають універсальний характер, їхнє засвоєння дозволить читачу надалі ефективно використовувати інші мови програмування. Це розділи, присвячені складності алгоритмів, типізації даних, поданню даних у комп'ютері (цікавий факт невиконання асоціативного закону арифметики), машинному нулю, машинній точності обчислень, програмістським умовам зупинки обчислення нескінченних сум і добутків, оптимальній реалізації обчислень, автоматній технології програмування. Наведено також алгоритми обробки інформації на різних структурах даних: простих, структурованих, усіляких видах зв'язних списків.

До книги додається електронний варіант довідника функцій мови С.

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

Автор висловлює щиру подяку Турбалу Юрію Васильовичу за допомогу в підготовці підручника, а також рецензентам за корисні поради.

ВСТУП

Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного програмування Основи сучасного

Н. Вірт визначає поняття програмування як "алгоритми  дані  програми". Іншими словами можна сказати, що програма – це інструмент для виконання деяких дій над деякими даними. Що таке програмування? Це наука чи мистецтво? Давно була запропонована правильна відповідь – "технологія". А головна ідея будь-якої технології – створення таких умов, коли реалізація процесу мінімально залежить від суб'єктивних факторів. Зокрема, це означає, що сучасні засоби програмування мають забезпечувати максимальний захист від можливих помилок розробника.

Відповідно до семантики слова "технологія" під технологією програмування розумітимемо сукупність виробничих процесів, що приводять до створення необхідного програмного продукту, та їхній опис. Отже, технологія програмування – це сукупність методів і засобів розробки (написання) програм і порядок їх застосування.

Прийнято вважати, що основними типами людської інтелектуальної діяльності, що вивчається в інформатиці, є:

 математичне моделювання (фіксація результатів пізнавального процесу у вигляді математичної моделі);

 алгоритмізація (реалізація причинно-наслідкових зв'язків та інших закономірностей у вигляді направленого процесу обробки інформації за формальними правилами);

 програмування (реалізація алгоритму на ЕОМ);

 виконання обчислювального експерименту (здобуття нового знання про явище, що вивчається, або об'єкт за допомогою обчислення на ЕОМ);

 розв'язання конкретних задач, що належать до об'єктів та явищ, описуваних початковою моделлю.

Обізнаність з основ програмування не зробить людину програмістом. Програмним проектам властива складність, що є зовсім не випад­ковою властивістю, а необхідністю. Увесь розвиток технології програмування можна розглядати як подолання хаосу при дослідженні складних систем.

Програмування як технологія у своєму розвитку пройшло кілька етапів. Програмування в машинних кодах із прямим доступом до пам'яті застосовувалося, в основному, у математичних формулах, розв'язанні задач чисельного аналізу. Використовувалась інтуїтивна технологія програмування: майже відразу приступали до складання програми за техніч­ним завданням. Написанню послідовності машинних команд передувало складання операторної схеми, що відображала послідовність операторів і переходи між ними. Це привело до появи так званого операторного програмування. Програма "збиралася" із дрібних деталей, окремих операцій і мала достатньо просту структуру: область гло­бальних даних і підпрограми.

Зі збільшенням обсягів програм стали виділяти їхні окремі частини й оформляти як підпрограми. Певну кількість таких підпрограм об'єд­нували у бібліотеки й потім викликали із робочих програм. Це поклало початок процедурному програмуванню – велика програма подавалася сукупністю підпрограм. Одна з підпрограм була головною, з неї починалося виконання програми. Процедурний підхід вимагав структуризації майбутньої програми, розділення її на окремі процедури. При розробці окремої процедури про інші процедури треба було знати лише їх призначення і спосіб виклику.

Із поступовим розширенням сфери застосування комп'ютерної техніки ускладнюється процес програмування. Ставиться й успішно розв'язується задача створення мов, які спрощують етап власне кодування алгоритмів. Зростання складності програм приводить до появи технології структурного програмування. Здійснюються спроби формалізувати програмування як наукову дисципліну. З'являються роботи видатних учених Е. Дейкстри, Ч. Хоара, Е. Йодана, у яких розробляються формальні аспекти науки програмування. Е. Дейкстра підкреслював, що саме структуризація стане основою радикального підвищення ефективності програм за рахунок можливості автоматичного виділення однакових фрагментів, розпаралелювання процесів, конвеєрної обробки тощо.

У свою чергу, Е. Йодан розглядав структурне програмування, перш за все, з погляду всього процесу розробки, починаючи від проектування й завершуючи тестуванням і документуванням. Зазначимо, що структурні методи написання програм становлять фундамент технології низхідного, поетапного програмування, тобто безпосередньо пов'язані з питаннями керування проектом у цілому.

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

Розглянемо один із напрямів деревоподібного підходу, який називається низхідним програмуванням. Його суть полягає в розбитті великої задачі на менші, незалежні підзадачі, які можуть розглядатися окремо. Таким чином, ми переходимо від загального розгляду проблеми, що розв'язується, до розгляду специфічних підзадач.

Спочатку будується структура задачі у вигляді дерева. Далі почергово програмуються підзадачі, починаючи із самого верхнього рівня. Після того, як усі підзадачі запрограмовані, проводиться їх почергове тестування й налагодження в такому самому порядку. При цьому вся необхідна вхідна інформація формується своєчасно. Кожна підзадача, у даному випадку – підпрограма, тестується при нормальних вихідних даних, які виробляються іншими підпрограмами.

Зауважимо, що багато великих систем не мають верхнього рівня. Наприклад, у системі керування базою даних важко, а інколи й неможливо, виділити функцію, яка є її найважливішою ланкою.

Низхідне програмування не перешкоджає створенню загальних підпрограм, які використовуються багатьма іншими програмами, але й не стимулює цей процес. Ідея об'єднання повторно використовуваних підпрограм у систему виявляється у висхідному підході, що є альтернативою низхідному.

Суть висхідного програмування: спочатку будується структура задачі у вигляді дерева; потім по черзі програмуються підзадачі, починаючи з найнижчого рівня, у такому порядку, щоб для кожної підзадачі, яка програмується, були вже запрограмовані всі підзадачі, до яких вона може звертатися.

За висхідного тестуванняі для кожної підпрограми (крім головної) доводиться створювати провідну програму, яка має підготувати для тестованої підпрограми необхідний стан інформаційного середовища та провести звернення до неї. Це приводить до великого обсягу налагоджувального – додаткового – програмування.

Основні правила успішного застосування цієї технології:

 формалізований і строгий опис програмістом входів функцій і виходів усіх модулів програми й системи;

 узгоджена розробка структур даних і алгоритмів;

 обмеження обсягу підпрограм.

Даною технологією зумовлюється певний принцип декомпозиції та ієрархічна структура програми.

Низхідне й висхідне програмування можна узагальнити як структурне. Основоположником структурного програмування вважається Е. Дейкстра. Його революційна для свого часу робота вийшла друком 1965 року та здійснила переворот у думках багатьох.

Низхідне програмування найкраще застосовується до проблем, що мають чітко виражений ієрархічний характер. На жаль, більшість реальних проблем його не мають. Зауважимо, що фокусування на функціональності (розбиття на підзадачі й методи їх розв'язання) допускає абстрагування від даних.

Теоретичними основами структурного програмування є:

 формальні системи теорії обчислюваності, загальні рекурсивні функції, системи Поста, алгоритми Маркова, лямбда-числення Черча;

 аналіз програм за низхідною схемою, декомпозиція, заснована на розбитті задач за рівнями 0, 1,..., к.

У класичній роботі С. Бома й Г. Джакопіні показано, що ієрархічна структура, розбита на рівні, може бути реалізована в мові, що включає лише три керувальні конструкції. За Бомом і Джакопіні, для реалізації програм потрібні такі основні складові:

 функціональний блок (конструкція проходження);

 конструкція узагальненого циклу;

 конструкція двійкового, або дихотомічного, розв'язання.

Характерними рисами структурного програмування є:

 простота та ясність (коментування);

 використання лише базових конструкцій;

 відсутність багатоцільових функціональних блоків;

 відсутність невиправдано складних арифметичних і логічних конструкцій;

 розташування в рядку програми не більше одного оператора мови програмування;

 змістовність імен змінних.

Структурний підхід аналізує й оперує, перш за все, діями, які необхідно виконувати з даними. Проте кожна реальна задача із часом доповнюється новими даними, проблемами, модифікується. Низхідний підхід створює хорошу програмну модель лише для початкових вимог до розв'язання задачі. Тому подібна архітектура поступово втрачає пристосовність до розв'язання задач.

Подальший розвиток структурного програмування спричинив появу його різновиду – модульного програмування. Незалежні фрагменти задачі оформляються як модулі.

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

Створюються бібліотеки модулів, розробляється механізм їхнього включення до програми. Модуль повинен мати строго визначений інтерфейс і приховану частину, одну точку входу й одну – виходу. Зароджуються та здійснюються ідеї розділення специфікації й реалізації модулів, використання модулів, що приховують структури даних.

Модульна програма має деревоподібну структуру. У вузлах такого дерева розміщуються програмні модулі, а напрямлені дуги показують їх підлеглість. Модульна структура програми включає сукупність специфікацій модулів, що її створюють. Специфікація програмного модуля містить синтаксичну специфікацію його входів, що дозволяє побудувати використовуваною мовою програмування синтаксично правильне звернення до нього й функціональну специфікацію модуля – опис семантики функцій, що виконуються ним за вхідними даними.

Основою структурного та модульного програмування є декомпозиція. Однак, оскільки вона лише торкається функціональних аспектів, то і вплив структури даних на розв'язання втрачається.

Програмування, пройшовши наївну й формальну фазу розвитку (якщо трохи переформулювати Д. Гільберта), вступає у фазу практичну. Наведемо цитату з книги Г. Майєрса [11]: "Низхідне функціональне проектування погано адаптується до розробки великих програмних систем. Низхідне проектування залишається корисною парадигмою для малих програм та індивідуальних алгоритмів.., але воно практично не масштабується на великі системи. Сенс не в тому, що Ви не можете розробляти систему зверху вниз: можете. Але, виторговуючи для себе короткочасну зручність за тривалу негнучкість, Ви некоректно нагромаджуєте одну функцію над іншою і (досить часто) функціональний інтерфейс над важливішими параметрами системи. Ви випускаєте з уваги аспект даних, і Ви жертвуєте можливістю багатократного використання".

Сучасний розвиток теорії програмування полягає у створенні програмних проектів, що базуються на об'єктно-орієнтованому підході. Це привело до створення візуальних середовищ швидкої розробки проектів, заснованих на компонентній ієрархії.

Розвиток підходу, заснованого на компонентній ієрархії, ще не завершився. Зараз він перебуває на стадії, коли розробку проекту можна починати не зі складання формальних специфікацій, а зі створення макета програми, тобто користувач і програміст можуть виробити єдине розуміння того, що має робити програма.

Розглянуті вище технології програмування фокусують увагу окремо на операціях і даних. Основна відмінність між структурним, модульним і сучасним підходами до проектування програмного забезпечення полягає в тому, що вони відповідають на різні питання: "Що робить програма" і "Що робиться з...". Це привело до формування технології, відомої як об'єктно-орієнтоване програмування.

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

Інкапсуляція. Поєднання даних з допустимими операціями над ними привело до нового типу даних – об'єкта. З об'єктом можна працювати лише так, як указано в інструкціях, і здійснювати лише операції, закладені в його описі. Насправді об'єкт є змінною визначеного користувачем типу. Здається дивним, що об'єкт, який об'єднує коди й дані, можна розглядати як змінну. Проте для об'єктно-орієнтованого програмування це саме так. Опосередковане звернення до даних дозволяє уникнути в багатьох випадках непередбачених, небажаних змін параметрів.

Успадковування. Дана властивість полягає в успадковуванні харак­теристик одного об'єкта іншим. Для цього один з об'єктів оголошується нащадком іншого, який, у свою чергу, стає предком цього нового об'єкта. Нащадок успадковує всі параметри свого предка та його операції (методи), тому повторно описувати їх немає необхідності, а використовувати можна. Це істотно спрощує запис схожих об'єктів, якщо встановити між ними спадковий зв'язок.

Поліморфізм. Це властивість, яка дозволяє одне й те саме ім'я використовувати для розв'язання двох і більше схожих, але різних задач. Він дає змогу в об'єктно-орієнтованому програмуванні використовувати одне ім'я для задання загальних для класу дій. Виконання кожної конкретної дії визначається типом даних. У загальнішому значенні концепцією поліморфізму є ідея "один інтерфейс – множина методів". Це означає, що можна створити загальний інтерфейс для групи близьких за значенням дій. Перевага поліморфізму полягає в тому, що він допомагає спрощувати програми. Вибір же конкретної дії, залежно від ситуації, покладається на компілятор. Ключовим у розумінні поліморфізму є те, що він дозволяє маніпулювати об'єктами різної міри складності шляхом створення загального для них стандартного інтерфейсу для реалізації схожих дій.

Об'єктно-орієнтоване проектування – це методологія проектування, що сполучає в собі процес об'єктної декомпозиції і прийоми зображення логічної й фізичної, а також статичної й динамічної моделей проектованої системи.

Розглянемо основні ідеї об'єктно-орієнтованого підходу:

 програма є моделлю деякого реального процесу;

 об'єкт описується набором параметрів, значення яких визначають стан об'єкта, і набором операцій (методів), які може виконувати об'єкт;

 об'єкти, описані одним і тим самим набором параметрів і здатні виконувати один і той самий набір дій, належать до класу однотипних.

З погляду мови програмування, клас об'єктів можна розглядати як тип даного, а окремий об'єкт – як дане цього типу. Визначення програмістом власних класів об'єктів для конкретного набору задач дозволяє описувати окремі задачі в термінах самого класу задач. Таким чином, об'єктно-орієнтований підхід припускає, що при розробці програми мають бути визначені класи використовуваних у програмі об'єктів і побудовані їх описи, потім створені необхідні об'єкти й визначена взаємодія між ними.

Однак на об'єктно-орієнтованому програмуванні розробка нових технологій не завершилася. Зараз на його базі розвивається нова технологія – COM.

COM (Component Object Model) розшифровується як "компонентна об'єктна модель". Суть цієї технології полягає в тому, що програми будуються із компонент, які складаються з об'єктів. Таким чином, можна сказати, що ця технологія "виросла" з модульного та об'єктно-орієнтованого підходу до побудови програм. Новизною можна вважати те, що компонентами й об'єктами є не початкові тексти, що не включаються та компілюються сумісно з проектом, не бібліотеки стандартних програм, що приєднуються лінкером, а безпосередньо виконувані бінарні файли. Їх не треба зв'язувати з проектом – достатньо зареєструвати в операційній системі, щоб зробити доступними для будь-якої програми. Вони застосовуються у програмі без використання операцій складання модуля.

Технологія COM розповсюджує переваги об'єктно-орієнтованого програмування, доступні програмісту на рівні початкового тексту, на двійковий рівень.

Слід також приділити увагу технології, що набирає обертів –.NET, хоча її не можна розглядати як чисто програмістську. Вона скоріше є своєрідною платформою для розв'язання сучасних задач. Використання суфікса .NET може не лише вказувати на наявність у продукті конкретних нових технологій, але й відображати напрям його розвитку. Однак у цьому підручнику ми не розглядатимемо детально дві останні технології.

1