Основы программирования и баз данных
Автор: Пользователь скрыл имя, 24 Октября 2013 в 16:22, курс лекций
Описание работы
Цель курса – максимально просто и интересно рассказать об основных поня-
тиях, используемых в программировании, и заложить прочный фундамент для
дальнейшего изучения современных IT-дисциплин. В этом пособии описываются
все ключевые моменты курса, приводятся все необходимые формальные определе-
ния, предлагаются некоторые примеры, разбираемые в курсе, и иллюстрации к тео-
ретическим конструкциям.
Содержание
. Введение....................................................................................................................... 3
2. Области применения программирования ................................................................. 4
3. Ключевые понятия и определения............................................................................. 7
4. Виды и типы данных................................................................................................. 14
5. Архитектура ЭВМ и принцип фон Неймана.......................................................... 18
6. Разработка программного обеспечения .................................................................. 21
7. Языки программирования ........................................................................................ 25
8. Структуры данных..................................................................................................... 30
9. Базы данных и их проектирование.......................................................................... 36
Работа содержит 1 файл
Москва — 2012
Основы программирования и
баз данных
Методическое пособие
Седых Игорь Вячеславович
2
Оглавление
1. Введение....................................................................................................................... 3
2. Области применения программирования ................................................................. 4
3. Ключевые понятия и определения............................................................................. 7
4. Виды и типы данных................................................................................................. 14
5. Архитектура ЭВМ и принцип фон Неймана.......................................................... 18
6. Разработка программного обеспечения .................................................................. 21
7. Языки программирования ........................................................................................ 25
8. Структуры данных..................................................................................................... 30
9. Базы данных и их проектирование.......................................................................... 36
10. Приложения ............................................................................................................ 42
Приложение 1. Краткий обзор языка программирования Си....................................................... 42
Приложение 2. Основные команды языка SQL, создание запросов............................................ 47
Приложение 3. Перевод чисел в разных системах счисления...................................................... 48
3
1. Введение
Методическое пособие, которое Вы держите в руках, сопровождает курс
«Основы программирования и баз данных» в Центре компьютерного обучения
«Специалист».
Цель курса – максимально просто и интересно рассказать об основных поня-
тиях, используемых в программировании, и заложить прочный фундамент для
дальнейшего изучения современных IT-дисциплин. В этом пособии описываются
все ключевые моменты курса, приводятся все необходимые формальные определе-
ния, предлагаются некоторые примеры, разбираемые в курсе, и иллюстрации к тео-
ретическим конструкциям.
Пособие и курс разработаны на базе общего курса автора по программирова-
нию для студентов и школьников гуманитарных направлений различных учебных
заведений. Изложение материала построено «от простого к сложному», начиная с
самых общих понятий и заканчивая примерами несложных программ. Такое по-
строение пособия позволяет дать полное представление об основах современных
информационных технологий, не загружая читателя излишними подробностями и
ненужными усложнениями.
Собранная в курсе информация – это объединение самых разных сведений из
различных областей, таких как программирование, математическая логика, архи-
тектура ЭВМ, базы данных, проектирование программного обеспечения и других.
В этом заключается уникальность курса – окончив его, можно с уверенностью про-
должать обучение по любому направлению, связанному с современными информа-
ционными технологиями. Данное пособие поможет систематизировать полученные
на занятиях курса знания и закрепить их. Кроме того, оно является интересным и
полезным справочным материалом, своего рода «первым учебником» для будущих
IT-специалистов.
Само собой разумеется, что курс «Основы программирования и баз данных»
является лишь первым этапом на пути будущего программиста к цели. Это своего
рода предисловие к книге под названием «Мой путь программиста». Введением в
нее будет начало изучения понравившегося Вам языка, главами – основная работа.
Ну а этот курс – лишь рассказ о том, о чем будет Ваша книга. Об огромном и инте-
ресном мире информационных технологий.
4
2. Области применения программирования
Начало изучения любой дисциплины заключается в ответе на главный вопрос
– с чем Вам придется иметь дело, когда Вы начнете в этой области работать. Вот и
получается, что первый вопрос, на который нам придется найти ответ – что такое
программирование? Чаще всего в нашей стране на этот вопрос дают неверный от-
вет, говоря, что программирование – это набор программ. Связано это с очень сла-
бым распространением у нас узконаправленных IT-дисциплин и, естественно, не-
хваткой работающих в них специалистов. Набор программ обычно относится к
дисциплине под названием «кодинг» или, более правильно, кодирование. На самом
деле, кодирование является лишь частью программирования, наряду с анализом,
проектированием, компиляцией, тестированием и отладкой, сопровождением.
Программирование – это решение задач при помощи ЭВМ, или процесс со-
здания компьютерных программ. В общем случае, программирование решает во-
просы программного управления различным оборудованием, будь то суперкомпь-
ютер или программируемая стиральная машина. Таким образом, одним из важней-
ших этапов в выборе будущего приложения своих способностей для любого про-
граммиста будет определение круга задач. В первую очередь такой выбор начина-
ется с области программирования. Для того чтобы разобраться в том, какие области
программирования бывают, нужно обратиться к истории появления компьютеров.
Эра автоматизации расчетов началась в 1642 г., когда Блез Паскаль изобрел
устройство, позволявшее механически выполнять сложение чисел, а в 1673 г. Гот-
фрид Вильгельм Лейбниц сконструировал арифмометр, возможности которого
были расширены до четырех основных ариф-
метических действия (сложения, вычитания,
умножения и деления). Эти устройства позд-
нее получили широкое распространение, и, в
частности, в Англии в XIX веке даже суще-
ствовала профессия «компьютер» – человек,
работающий с арифмометром. Основной зада-
чей этих людей был расчет морских навигаци-
онных таблиц. Естественно, что точность та-
ких расчетов была довольно низкой, а скорость
работы невысокой. Работу этих людей нужно
было автоматизировать, но сделать это без со-
здания программируемого устройства было
невозможно. Самым первым таким механиз-
мом стала разностная машина Бэббиджа, со-
зданная в 1822-м году (Рисунок 1). Машина
приводилась в движение ручкой (по принципу арифмометра), но движение ее бара-
банов могло быть запрограммировано в зависимости от решаемой задачи. К сожа-
лению, разработки Бэббиджа не дошли до успешного финала. Получив от Британ-
ского правительства огромные деньги на постройку полноценной расчетной маши-
ны (около 17 тысяч фунтов стерлингов – в то время этих денег хватило бы на по-
Рисунок 1 – Разностная машина
5
стройку трех крупных военных кораблей) он и представить себе не мог, с какими
трудностями столкнется. Его проекту так и не суждено было завершиться. Однако
когда к двухсотлетию со дня рождения Чарльза Бэббиджа на основе его оригиналь-
ных работ в лондонском Музее науки была собрана работающая копия разностной
машины № 2, оказалось, что этот механизм мог проводить довольно сложные вы-
числения с гораздо более высокой точностью, чем ожидалось.
Следующее серьезное применение компьютеры получили во время Второй
Мировой войны. Оно было связано со взломом фашистских шифров. Специфика-
цию компьютера разработали профессор Макс Ньюман и его коллеги; сборка
Colossus Mk I, как назвали эту машину, выполнялась в исследовательской лабора-
тории Почтового департамента Лондона под управлением инженера Томми Флау-
эрса и заняла 11 месяцев. Компьютер был построен на основе вакуумных ламп, что
позволяет считать его первой электронно-вычислительной машиной (ЭВМ). Созда-
телем алгоритмов для этой машины был Алан Тьюринг – талантливый математик, в
итоге заложивший основы многих современных компьютерных наук, один из груп-
пы ученых, взломавших код Энигма. Использовался Колосс для взлома кода, гене-
рируемого шифровальной машиной Lorenz SZ 40/42, которая использовалась в пе-
реговорах высшего командования противника. К сожалению, проект был настолько
секретным, что о его существовании не было ничего известно до конца XX-го века,
из-за чего найти упоминания об этой машине крайне сложно. Утверждается, что ни
один из десяти построенных для разных целей «Колоссов» не дожил до наших
дней.
После войны компьютерные технологии, несмотря на всю секретность проек-
тов, начали активно развиваться. Американский ENIAC, который часто называют
первым электронным компьютером
общего назначения, публично дока-
зал применимость электроники для
масштабных вычислений. Создан-
ная под руководством Джона Мо-
учли и Дж. Преспера Эккерта, эта
машина была в 1000 раз быстрее,
чем все другие машины того време-
ни. Его основой послужили 18 000
вакуумных трубок, или электрон-
ных ламп (Рисунок 2), а первая про-
грамма была запущена в ноябре
1945 г., хотя официально об изобре-
тении было сообщено на год позже,
в начале 1946 г., когда проект рас-
секретили. В то время, многие исследователи были убеждены в том, что лампы бу-
дут сгорать очень часто, и «ЭНИАК» будет слишком много времени простаивать в
ремонте, и потому будет практически бесполезен. Тем не менее, на реальной ма-
шине удавалось выполнять несколько тысяч операций в секунду в течение не-
Рисунок 2 – ENIAC
6
скольких часов, до очередного сбоя из-за сгоревшей лампы. «Программа» для этой
машины определялась состоянием соединительных кабелей и переключателей, что
было серьезным прорывом со времени механических вычислительных устройств,
но, конечно же, проигрывало машинам с хранимой программой, появившимся поз-
же. В наше время принято считать «ЭНИАК» скорее калькулятором, нежели ком-
пьютером, но нельзя отрицать тот факт, что его изобретение стало ключевым мо-
ментом в разработке вычислительных машин, прежде всего из-за огромного приро-
ста в скорости вычислений, но также и по причине появившихся возможностей для
миниатюризации.
Успех первой ЭВМ означал начало новой эры в развитии вычислительных
устройств. После «ЭНИАК» новые компьютеры стали появляться чаще и станови-
лись все быстрее. В процессе разработок первых ЭВМ к работе был привлечен из-
вестный американский математик Джон фон Нейман, который вскоре сумел сфор-
мулировать пять основных принципов функционирования универсальных вычис-
лительных устройств, которые мы обсудим далее. На этих принципах, как на фун-
даменте, основывались в дальнейшем все последующие поколения машин. Осо-
бенно важен принцип программного управления. Именно из этого принципа выте-
кает определение программы в ее классическом понимании – как последовательно-
го набора команд, выполняемых процессором. Отсюда возникает и необходимость
в подготовке специально обученных людей, которые бы знали, какие команды и в
какой последовательности нужно применять для решения определенной задачи.
Это приводит к становлению программирования, как одного из видов деятельности
человека.
За период с 1948 по 1975 года сменяются три так называемых поколения ком-
пьютеров. За это время происходит миниатюризация ЭВМ в процессе перехода от
вакуумных ламп к транзисторам (изобретенным в 1947 году и внедренным в пяти-
десятые годы), а затем к интегральным схемам (1958 год) и изобретению микро-
процессора (1971 год, микропроцессор Intel 4004). В это время наиболее известны-
ми производителями компьютеров были американские
компании IBM, Apple, Dell, Compaq. Свои разработки ве-
лись и в СССР, но они, к сожалению, проигрывали зару-
бежным аналогам в производительности. Почти все ком-
пьютеры, производившиеся до 70-х годов XX века, имели
очень простой текстовый интерфейс, который мы сейчас
можем назвать терминалом. Это были обычные тексто-
вые сообщения, выводимые компьютером на принтер или
экран монитора. Управление осуществлялось с клавиату-
ры посредством ввода текстовых команд, что, естествен-
но, очень усложняло работу с такими ЭВМ. Первым в
мире компьютером, имевшим графический пользователь-
ский интерфейс и операционную систему с «рабочим
столом», стал Xerox Alto (Рисунок 3). Это удивительно,
но именно он стал первым полностью персональным
компьютером в современном понимании этот термина. В то время как наиболее
Рисунок 3 – Xerox Alto
7
известные в наши дни производители, вроде IBM, создавали сложные и громоздкие
ЭВМ для инженерных расчетов, именно Xerox, почти неизвестная тогда компания,
придумала дизайн ПК, который используется и сегодня. Xerox Alto даже имел ма-
нипулятор «мышь», без которого современный компьютер просто невозможно себе
представить.
В январе 1984 года компания Apple выпустила первый серийный персональ-
ный компьютер с «мышью», реализовавший идею Xerox Alto в промышленном
масштабе, названный Apple Macintosh. С этого времени работа с компьютером ста-
новится все проще и все доступнее самым разным людям. Естественно, что это
требует создания все большего количества разнообразных программ, решающих
при помощи ЭВМ самые разные задачи. Вот и получается, что началось примене-
ние компьютеров с решения математических задач, а закончилось почти неограни-
ченными возможностями современной техники и программного обеспечения. Если
подвести итог тому, как развивались компьютеры и программы, то можно выделить
пять ключевых областей, в которых они применяются для решения задач в наши
дни:
1. «Математика». Имеется в виду написание функциональных частей про-
грамм; то, что заставляет приложение быть не просто картинкой на экране
монитора, но еще выполнять различные математические действия, вос-
производить музыку и видео, сжимать и шифровать данные и т.д.
2. Системное программирование. В эту область можно отнести задачи со-
здания операционных систем, написание интерфейсов для управления
компьютерным «железом» – различными устройствами. Главная цель этой
области задач – максимально упростить работу человека с компьютером и
выполнять различные технические операции над ЭВМ.
3. Прикладное программирование. Самая большая область задач – создание
программ, решающих повседневные задачи – текстовых и графических
редакторов, мультимедийных приложений, словарей и баз данных, а также
многого другого.
4. WEB-программирование. Написание программного обеспечения для сети
Интернет и создание сайтов.
5. Скриптовые языки высокого уровня. Написание программ, предназначен-
ных для автоматизации и управления работой существующих программ,
написания дополнительных модулей в программных пакетах.
3. Ключевые понятия и определения
После того, как мы выяснили, что программирование – это решение задач с
помощью ЭВМ, то и начнем мы с определения задачи. Само по себе определение
термина «задача» – более философское, нежели конкретное понятие. Чтобы не
углубляться в такие изыскания, мы остановимся не на самом определении, а на том,
8
что такое решение задачи применительно к программированию. И самое главное –
это, конечно же, из каких этапов оно состоит.
Первым этапом решения является постановка задачи. Постановка задачи
может быть устной, может быть письменной – это не столь принципиально – глав-
ное то, что на этом этапе должно быть четко определено, что дано, и что требуется
найти. Так, если задача конкретная, то под постановкой задачи понимают ответ на
два вопроса: какие исходные данные известны и что требуется определить. Если
задача обобщенная, то при постановке задачи понадобится еще ответ на третий во-
прос: какие данные допустимы. В итоге постановка задачи обычно включает в себя
формулировку условия, определение конечных целей решения, определение формы
выдачи результатов, описание используемых и конечных данных. Постановка зада-
чи определяет требования, которые предъявляются к конечному программному
продукту.
В связи с тем, что постановка задачи может быть некорректной или вообще
ошибочной, обязательным является второй этап – анализ задачи. Этот этап позво-
ляет определить, можно ли в принципе решить задачу в указанных при постановке
рамках. Кроме того, на этом этапе Вы также можете определить, какие пути реше-
ния выбрать, с какими данными и как работать, какой язык программирования ис-
пользовать и т.д. На втором этапе обязательным является формальная постановка
задачи или техническое задание, предназначенное для описания жестких условий, в
которых решение будет происходить.
Третьим этапом является проектирование. Это важнейший этап в решении
любой задачи. Именно во время этого этапа происходит детальная разработка всех
основных элементов будущей программы, включая все модули, интерфейс, функ-
циональные решения и прочее. Этот этап занимает большую часть времени в ре-
шении любой задачи. По качественно созданному проекту написать программу
легко и что самое главное – программирование по готовому проекту практически
механическая деятельность, а значит, этот процесс можно контролировать при по-
мощи нормативов и норм, ускоряя процесс создания программного обеспечения
(ПО).
Только после проектирования приступают к реализации. Этот этап, как пра-
вило, занимает минимум времени в решении задачи. Его основная цель – непосред-
ственная разработка программы, решающей поставленную задачу. Именно в этот
момент кодеры набирают программу, работая вместе с проектировщиками и тести-
ровщиками, создавая готовый продукт.
Заключительным этапом решения задачи является модификация и обновление
созданного ПО. Этот этап нужен для того, чтобы Ваш продукт всегда был совре-
менным и востребованным на рынке.
Итак, самым важным этапом в этом процессе является проектирование. Одно
из наиболее часто встречающихся понятий, связанных с проектированием задач
любого класса, это алгоритм. Это понятие является фундаментальным в информа-
тике, его происхождение связано с математикой и именем персидского учёного Абу
9
Абдуллаха Мухаммеда ибн Муса аль-Хорезми (787-850). В своей книге «Об индий-
ском счете» он сформулировал правила записи натуральных чисел с помощью
арабских цифр и правила действий над ними столбиком. Эта его книга, будучи пе-
реведенной на латинский язык получила название Algoritmi de numero Indorum
(«Алгоритмы о счёте индийском»). У самого понятия «алгоритм» несколько опре-
делений. Алгоритм можно определять неформально, в применении к программиро-
ванию, математике и даже для обычной жизни. В конечном итоге, алгоритм – это
формально описанная последовательность действий, которые необходимо выпол-
нить для получения требуемого результата. В классическом понимании компью-
терные алгоритмы могут содержать только три вида последовательностей команд.
Линейная структура команд, разветвленная структура и циклическая. Все команды,
описанные в алгоритме, выполняются всегда только в описанном порядке без ка-
ких-либо отклонений.
Линейная структура процесса вычислений предполагает, что для получения
результата необходимо выполнить некоторые операции в определенной последова-
тельности. Например, для определения площади треугольника по формуле Герона
необходимо сначала определить полупериметр треугольника, а затем по формуле
его площадь.
Разветвленная структура процесса вычислений предполагает, что конкрет-
ная последовательность операций зависит от значений одного или нескольких па-
раметров. Например, если дискриминант квадратного уравнения не отрицателен, то
уравнение имеет два корня, а если отрицателен, то действительных корней нет.
Циклическая структура процесса вычислений предполагает, что для получе-
ния результата некоторые действия необходимо выполнить несколько раз. Напри-
мер, для того, чтобы получить таблицу значений функции на заданном интервале
изменения аргумента с заданным шагом, необходимо соответствующее количество
раз определить следующее значение аргумента и посчитать для него значение
функции.
Существует огромное число различных видов алгоритмов. Особую роль вы-
полняют прикладные алгоритмы, предназначенные для решения определённых
прикладных задач. Важную роль играют рекурсивные алгоритмы (алгоритмы, вы-
зывающие сами себя до тех пор, пока не будет достигнуто некоторое условие воз-
вращения). Начиная с конца XX – начала XXI века активно разрабатываются па-
раллельные алгоритмы, предназначенные для вычислительных машин, способных
выполнять несколько операций одновременно. К сожалению, существуют такие за-
дачи, создание алгоритма для которых невозможно. Такие задачи обычно называют
алгоритмически неразрешимыми.
Обычно алгоритмы записывают в виде текста – нечто вроде плана действий.
Но этот способ не всегда удобен и понятен. Поэтому очень часто используют более
наглядные графически нотации для изображения алгоритмов. Наиболее популяр-
ным и несложным для изучения способом такого изображения алгоритмов являют-
ся блок-схемы. Этот способ довольно старый, но по-прежнему очень часто исполь-
10
зуется, особенно в обучении программированию. В блок-схемах приняты специ-
альные обозначения, укажу некоторые из них:
Наименование
Обозначение
Функция
Блок начало-конец
Элемент отображает вход из внешней среды или выход
из нее (наиболее частое применение − начало и конец
программы).
Блок вычислений
Выполнение одной или нескольких операций, обработка
данных любого вида (изменение значения данных, фор-
мы представления, расположения).
Логический блок
Отображает участок ветвления алгоритма с одним вхо-
дом и, как правило, двумя альтернативными выходами,
из которых только один может быть выбран после вы-
числения условий, определенных внутри этого элемента.
Предопределенный
процесс
Символ отображает выполнение процесса, состоящего из
одной или нескольких операций, который определен в
другом месте программы. Например – вызов процедуры
или функции.
Данные
(ввод-вывод)
Преобразование данных в форму, пригодную для обра-
ботки (ввод) или отображения результатов обработки
(вывод).
Используя указанные обозначения, мы можем наглядно показать, как выгля-
дят все три классических процесса в алгоритмах:
В приведенных на Рисунок 4 примерах легко узнаются линейная структура
(схема 1), ветвление (схема 2) и цикл (схема 3). Особо жестких требований к изоб-
ражению элементов блок-схем нет. Однако при их создании стараются придержи-
ваться общепринятых обозначений. Стрелочки между действиями в блок-схемах
рисовать не обязательно, т.к. блок-схемы обычно читают сверху вниз.
К сожалению, в современном программировании блок-схемы не всегда мож-
но использовать из-за сложности современных языков программирования. Блок-
схемы можно использовать только для структурных языков программирования или
Схема 1
Схема 2
Схема 3
Рисунок 4 – Примеры блок-схем
11
же структурных участков кода. Понятие структурного кода мы обсудим позже.
Чаще всего в современном программировании используют псевдокод.
Понятие псевдокода связано с идеей создания универсального языка для об-
щения программистов, пишущих на разных языках. Универсального переводчика с
одного языка на другой не существует, а работать таким людям над одним проек-
том вместе бывает нужно очень часто. Вот и появляется компактный (зачастую не-
формальный) язык описания алгоритмов, использующий ключевые слова «выду-
манных» языков программирования. Псевдокод не может быть полноценным уни-
версальным языком, т.к. он обычно опускает некоторые несущественные для опи-
сания алгоритма детали и специфический синтаксис тех или иных языков програм-
мирования, программировать на таком языке нельзя. Псевдокод широко использу-
ется в учебниках и научно-технических публикациях, а также на начальных стади-
ях разработки компьютерных программ. В итоге написания такого кода програм-
мист получает промежуточную форму между повседневным языком и языком про-
граммирования, что позволяет упростить понимание алгоритма и облегчить про-
цесс дальнейшего переноса алгоритма на машину. Наиболее часто псевдокод пи-
шут очень похожим на язык Pascal, что, в общем-то, не принципиально и синтаксис
псевдокода может быть любым. О таком синтаксисе программисты договариваются
сами друг между другом, и он может быть написан на любом языке – русском, ан-
глийском, итальянском и т.д. Единого, «международного», псевдокода не суще-
ствует, потому что языки программирования слишком сильно отличаются друг от
друга.
Вот мы и подошли к, пожалуй, ключевому термину в нашем курсе. К поня-
тию программы. Начинается любая программа с постановки задачи и разработки
алгоритма, проектирования решения этой задачи. А затем начинается программи-
рование. Но что такое программа, из каких частей она состоит?
Программа – это готовое решение задачи для ЭВМ. У любой современной
программы есть несколько принципиальных компонентов. Прежде всего, это функ-
циональное наполнение программы – «математика» – то, без чего любая программа
будет просто красивой картинкой на экране монитора без каких-либо реакций на
действия пользователя. Иногда эта часть программы даже выносится в виде одного
или нескольких отдельных, самостоятельных файлов. Вторая часть программы –
это ее интерфейс. Многие современные программы рассчитаны на обычных поль-
зователей и поэтому должны обладать удобным и простым способом управления
ими. Эти возможности пользователям и дает интерфейс. Обычно считается что ин-
терфейс – это как раз та самая красивая картинка с кнопками, редакторами и про-
чими графическими атрибутами современных операционных систем. Но интерфейс
не обязан быть графическим. Он также может быть текстовым. Программы с таким
интерфейсом обычно вызываются из командной строки (более правильно – консо-
ли или терминала) продвинутыми пользователями и администраторами. И третья
часть программы – то, что отвечает за ее функционирование и общее устройство –
архитектура программного обеспечения.
12
Довольно важный вопрос в определении компонентов программы – будут ли
внешние ресурсы, без которых программа не работает, также ее частью? Например,
библиотеки DirectX, без которых не запускается ни одна современная компьютер-
ная игра для компьютеров под управлением Microsoft Windows. С одной стороны
программисты игр не пишут этой библиотеки, а лишь используют ее, с другой сто-
роны, без нее игра не запустится. Вот и получается, что с одной стороны это вроде
бы часть Вашей программы, а вроде бы и нет. Давайте считать, что если некий
внешний ресурс для своей программы Вы пишите самостоятельно, то он – часть
Вашей программы. А если вы только используете его – то его наличие просто ста-
новится обязательным условием ее работы.
Опишем теперь этапы создания программы. В общем случае любая програм-
ма начинает существование в виде исходного кода. Очень часто
исходный код называют программой. Это неаккуратно. Поэтому
мы будем придерживаться правильной терминологии и называть
первый этап исходным кодом или «исходником». Исходный код
программы – это обычный текстовый документ, который можно
набрать в любом текстовом редакторе, но делать это гораздо
удобнее можно в специальной среде языка программирования,
которая позволяет не только писать программы, но и упрощает
поиск ошибок и часто ускоряет процесс написания кода. Исход-
ный код представляет собою перевод алгоритма (записанного в
любом виде – блок-схема, псевдокод и т.п.) с повседневного
языка в термины формального языка программирования. Полученный текст испол-
няться компьютером не может. Машина просто не поймет, что в файле написано.
Для того чтобы программа смогла заработать, ее «исходник» нужно перевести в
понятный машине язык. Он зазывается машинным кодом или программой. Для это-
го действия нужен компилятор – важнейшая часть любого языка программирова-
ния, переводящая исходный код в машинный. Если в процессе создания Вы ис-
пользуете компилятор, то это означает, что Ваш язык програм-
мирования компилируемый. В процессе компиляции могут воз-
никнуть ошибки, называемые обычно ошибками компиляции или
синтаксическими ошибками. Эти ошибки совсем не страшные –
обычно их очень легко исправить, особенно, если учесть тот
факт, что такие ошибки особо отмечаются компилятором
(вплоть до строки, где такая ошибка произошла). Гораздо
страшнее логические ошибки, эффект которых проявляется в
программах, которые работают, но либо дают неверный резуль-
тат, либо сбоят в процессе решения задачи. Искать такие ошиб-
ки очень сложно и в их поиске обычно сильно помогает исполь-
зование систем отладки или debug сред языков программиро-
вания.
Получается, что в классических языках программирования
можно нарисовать условную схему, показывающую шаги, кото-
рые проходит программа при создании (см. Рисунок 6). Но такая схема не един-
Исходный код
Компиляция
Машинный код
Рисунок 6 – Схема
компиляции
Машинный код
Объектный код
Исходный код
Компиляция
Рисунок 5 – Объ-
ектный код
13
ственная. Существуют более простая ситуация и более сложная. Сначала опишем
более сложную схему. В ней появляется дополнительный шаг, называемый объ-
ектным кодом (см. Рисунок 5). Объектный код, часто называемый объектным мо-
дулем или объектным файлом, это особым образом преобразованный компилято-
ром исходный код программы. Фактически он является промежуточным представ-
лением исходного кода программы, содержащий в себе особым
образом подготовленный код, который может быть объединён с
другими объектными файлами при помощи редактора связей
(компоновщика или линковщика, если опираться на зарубежную
терминологию) для получения готового машинного кода. Объ-
ектный код объединяет готовый универсальный машинный код и
данные, созданные программистом, что позволяет собирать го-
товую программу даже из исходных кодов, написанных на раз-
ных языках программирования. Частично, именно благодаря
объектному коду (а если быть более точным, то библиотекам объектных кодов) мы
можем писать программы на разных языках и использовать в своей работе коды
друг друга. Немаловажно также и то, что объектный код позволяет упросить и
ускорить процесс написания сложных программ. Некоторые компиляторы языков
программирования создают объектный код автоматически, для некоторых компи-
ляторов эта возможность компилятора включается отдельно. Никаких специальных
программ для создания объектного кода не требуется.
Некоторые языки программирования, например скриптовые, являются ин-
терпретируемыми. Это и есть та самая простая ситуация создания программы, о
которой шла речь выше. Программы, написанные на таких языках нельзя запустить
без интерпретатора – программы, которая и выполняет написанный Вами код (см.
Рисунок 7). Получается, что такие программы сильно зависят от установленного на
компьютере программного обеспечения. Например, программы, написанные на
языке 1С, работают только в системе 1С; для того, чтобы увидеть не текст на языке
html, а красивый сайт, требуется интернет-браузер и т.д. Интерпретируемые языки
программирования – одни из самых простых для изучения. Конечно же, не из-за
того, что эти языки программирования простые, а из-за того, что количество до-
ступных команд в них ограничено возможностями интерпретатора. Среди класси-
ческих языков программирования также были интерпретируемые языки програм-
мирования – это классический Бейсик.
В конце главы хотелось бы сформулировать ряд важных и полезных для изу-
чения информационных технологий терминов и понятий. Прежде всего, определим
понятие информации. Информация – скорее философское понятие, обозначающее
сведения о чем-либо, независимо от формы их представления. С точки зрения ком-
пьютера информацией являются все данные, которые попадают в его память. На
основе этого понятия можно определить термин логическое выражение. Логиче-
ским выражением является любая информация, значение которой в каждый момент
времени может быть однозначно определено как истинное или ложное. И еще не-
сколько классических определений:
Рисунок 7 - Интер-
претация
Исходный код
Интерпретация
14
1. Операнд – аргумент операции, данное, которое обрабатывается командой.
Может быть достаточно сложным, например комбинацией других операн-
дов или функцией.
2. В большинстве языков программирования низкого и высокого уровня (эти
термины мы сформулируем в 7-ой главе) определён набор встроенных
операций отношения, позволяющих строить «простые» логические выра-
жения. А также арифметические операции над операндами для выполне-
ния четырех базовых математических действий: сложения, вычитания,
умножения и деления.
3. Идентификатором называется последовательность цифр и букв, а также
специальных символов, при условии, что первой стоит буква или специ-
альный символ. В программировании идентификаторы (или имена) ис-
пользуются для обращения к специальным объектам внутри программы.
4. Переменная в программировании это именованное имя памяти. У пере-
менной в любом языке программирования всегда есть три части: иденти-
фикатор, которым пользуется программист; место в оперативной памяти,
которое будет заполняться компьютером в процессе выполнения програм-
мы; адрес, позволяющий обращаться напрямую к памяти в программе.
5. Константа в программировании – способ адресования данных, изменение
которых программой запрещено. Константы бывают разного вида – это
бывают неизменимые переменные, а также обычные статичные объекты –
например, символьные или числовые константы.
4. Виды и типы данных
Рассказ о типах данных и способах их представления на компьютере нужно
начать с небольшого уточнения. Любая информация, которая в том или ином виде
попадает в компьютер, сохраняется в нем в виде специальных наборов цифровой
информации, кодируемой в двоичной форме числа. Таким образом, в конце концов,
все данные, с которыми вы работаете, на компьютере преобразуются в числа и чис-
ловой формат данных – основной способ хранения информации в компьютере.
Другими важными типами данных являются числовой и логический (булевский).
Внутри современного компьютера нет более сложных устройств, чем наборы
огромного количества выключателей, которые могут находиться в двух состояни-
ях: включено и выключено. В этом смысле современный компьютер ничем не от-
личается от устройств Бэббиджа или от машины ЭНИАК. Хотя современные ЭВМ
гораздо сложнее с технической точки зрения и могут выполнять миллиарды опера-
ций в секунду – их принципиальное устройство остается таким же, как и 10, 20 и
даже 30 лет назад. Повышение мощности современно компьютера достигается за
счет повышения количества операций в секунду. К сожалению, до бесконечности
таким способом повышать мощность нельзя. Это соображение приводит к появле-
нию параллельных алгоритмов, вероятностных алгоритмов, нейронных сетей и т.д.
15
Основной вид информации в ЭВМ, таким образом, это числа или сигналы 1 и
0. Для операций над такими объектами чаще всего прибегают к понятиям матема-
тической логики – науки, которая занимается изучением логических выражений.
Поэтому давайте довольно подробно остановимся на том, что такое логика, и как
устроены логические операции. Основные правила таких действий определяет ал-
гебра логики – раздел математики, в котором изучаются логические операции над
высказываниями (или, как мы их называем, логическими выражениями). Высказы-
вания, как и логические выражения, могут быть истинными, ложными или содер-
жащими истину и ложь в разных соотношениях, причем значение высказывания в
любой момент времени может быть однозначно вычислено.
Основных операций математической (и программной) логики, с которыми
нужно познакомиться в начале изучения программирования, немного. Их три. Да-
дим этим операциям определения и приведем примеры их использования.
1. Отрицание – смысл этой операции в изменении значения высказывания на
противоположное. Например: построение цикла «работать до тех пор, по-
ка не достигнут конец файла».
2. Конъюнкция – также называется логическим "И", логическим умножени-
ем, или просто "И". Операция, применяемая к двум высказываниям и
имеющая истинное значение в том и только в том случае, когда оба выска-
зывания истины. Например: точка на числовой прямой лежит внутри от-
резка, когда ее координата меньше правой границы отрезка и больше ле-
вой границы.
3. Дизъюнкция – также называется логическим "ИЛИ", логическим сложени-
ем, или просто "ИЛИ". Операция, применяемая к двум высказываниям и
имеющая ложное значение в том и только в том случае, когда оба выска-
зывания ложны. Например: если число не делится на 2 или на 3, то оно не
делится на 6.
В компьютерной логике ключевыми константами являются логический ноль
(ложь) и логическая единица (истина). Наиболее формально эти операции можно
выписать в виде следующих таблиц:
Отрицание
Конъюнкция
Дизъюнкция
A
НЕ A
1
0
0
1
A
B
A И B
1
1
1
1
0
0
0
1
0
0
0
0
A
B
A ИЛИ B
1
1
1
1
0
1
0
1
1
0
0
0
Описанных логических операций, несмотря на их внешнюю простоту, доста-
точно для создания практически любых логических выражений в программирова-
нии. Они могут быть очень сложными, но такое построение всегда возможно.
16
Для хранения любых типов данных в компьютере используется двоичная си-
стема счисления, кодирующая любую информацию в виде 1 и 0. Таким образом, в
конечном итоге, компьютер работает с данными исключительно в виде двоичной
их записи. Более того, десятичная система счисления на компьютере не использу-
ется вообще. Из используемых в компьютере систем счисления для удобства про-
граммирования стоит также выделить восьмеричную и шестнадцатеричную систе-
мы счисления. Мы не будем подробно сейчас останавливаться на переводе чисел из
одной системы счисления в другую, т.к. это сухая и скучная информация. Отметим
лишь то, что компьютер, в конечном итоге, работает именно в двоичной системе
счисления и переводит все вводимые Вами числа сразу, не дожидаясь сохранения
информации в памяти.
1. Чем меньше значений существует в системе, тем проще изготовить отдель-
ные элементы, оперирующие этими значениями. В частности, две цифры
двоичной системы счисления могут быть легко представлены многими физи-
ческими явлениями: есть ток – нет тока, индукция магнитного поля больше
пороговой величины или нет и т. д.
2. Чем меньше состояний у технического элемента, тем выше помехоустойчи-
вость и тем быстрее он может работать. Например, чтобы закодировать три
состояния через величину индукции магнитного поля, потребуется ввести два
пороговых значения, что не будет способствовать помехоустойчивости и
надёжности хранения информации.
3. Двоичная арифметика является довольно простой. Простыми являются таб-
лицы сложения и умножения – основных действий над числами.
Теперь давайте рассмотрим два вида наиболее важных и часто используемых
в программировании типов данных – чисел и символов.
Память ЭВМ построена из запоминающих элементов, обладающих двумя
устойчивыми состояниями, одно из которых соответствует нулю, а другое – едини-
це. Таким физическим элементом представляется в памяти ЭВМ каждый разряд
двоичного числа (бит). Совокупность определенного количества этих элементов
служит для представления многоразрядных двоичных чисел и составляет разряд-
ную сетку ЭВМ. В любой ЭВМ биты организованы в байты – каждый байт являет-
ся объединением 8 бит, каждый байт пронумерован. Номер байта называется его
адресом.
Самым важным (и, одновременно, простым) типом данных на компьютере
является, конечно, числовой формат данных. Для понимания того, как числа хра-
нятся в компьютере, необходимо отметить, что любая информация на машине, в
конечном итоге, кодируется в двоичной системе счисления. Таким образом, числа
на компьютере также хранятся в своей двоичной записи – как целые, так и дроб-
ные. Организация хранения целых чисел особого труда не представляет – такие
числа просто переводят из десятичной системы счисления в двоичную и сразу за-
писывают в память. Для компьютерного представления целых чисел обычно ис-
пользуется несколько различных типов данных, отличающихся друг от друга коли-
17
чеством разрядов. Чаще всего используется восьми-, шестнадцати- и тридцати-
двухразрядное представление чисел (один, два или четыре байта соответственно).
Для целых чисел существуют два представления: беззнаковое (только для не-
отрицательных целых чисел) и со знаком. Очевидно, что отрицательные числа
можно представлять только в знаковом виде. Различие в представлении целых чи-
сел со знаком и без знака вызвано тем, что в ячейках одного и того же размера в
беззнаковом типе можно представить больше различных положительных чисел,
чем в знаковом. В ЭВМ в целях упрощения выполнения арифметических операций
применяют специальные коды для представления чисел. Использование кодов поз-
воляет свести операцию вычитания чисел к операции поразрядного сложения кодов
этих чисел. В записи целых чисел используют прямой и дополнительный коды, ко-
торые позволяют записывать любые целые числа в нужном формате. Диапазон
представления целых чисел в ЭВМ зависит от разрядности остановленной опера-
ционной системы.
Гораздо сложнее обстоят дела с вещественными числами. Их нужно хранить
специально – т.к. базово компьютер поддерживает работу только с целочисленны-
ми данными. Это означает тем самым, что такие числа придется обработать перед
сохранением в памяти в особый формат. Современных форматов хранения веще-
ственных чисел два – число с фиксированной и с плавающей точкой.
Формат чисел с фиксированной точкой наиболее простой. Его реализация
подразумевает, что целая и дробная части одного вещественного числа хранятся
отдельно как целые числа в памяти компьютера. Однако этот метод, несмотря на
явное удобство использования, наглядность и простоту обработки данных, является
не очень удачным. Недостатком представления чисел в формате с фиксированной
запятой является небольшой диапазон представления величин, недостаточный для
решения математических, физических, экономических и других задач, в которых
используются как очень малые, так и очень большие числа. Немногие языки про-
граммирования предоставляют встроенную поддержку чисел с фиксированной за-
пятой, поскольку для большинства применений двоичное или десятичное пред-
ставление чисел с плавающей точкой проще и достаточно точно. Числа с плаваю-
щей точкой из-за их большего динамического диапазона устроены гораздо удобнее,
и, что немаловажно в сложных расчетах, для них не нужно предварительно зада-
вать количество цифр после запятой. В этом формате положение точки в записи
числа может изменяться в зависимости от выбранного представления числа. Назва-
ние плавающая точка происходит от того, что точка в позиционном представлении
числа может быть помещена где угодно относительно цифр в строке, это положе-
ние запятой указывается отдельно во внутреннем представлении числа. Таким об-
разом, представление числа в форме с плавающей запятой может рассматриваться
как компьютерная реализация экспоненциальной записи чисел, в которой может
быть записано любое число. Реализация математических операций с числами с
плавающей запятой в вычислительных системах может быть как аппаратная, так и
программная.
Рассмотрим, как выглядит произвольное число A в таком виде:
18
Здесь m – мантисса числа, q – основание системы счисления (для компьюте-
ра равно двум) и p – степень числа. Также в этом формате требуется указать знак
мантиссы – отвечающий за знак самого числа A. В современных операционных си-
стемах диапазон хранения в формате с плавающей точкой составляет от
степени до
степени. И это не учитывая специальных форматов увеличенной
точности.
Другим, не менее важным форматом данных является символьный тип дан-
ных. На самом деле появившийся как обычный целочисленный формат. Дело в том,
что в программировании изначально символов не было. Они просто не были нуж-
ны. Но с появлением мониторов, позволяющих отображать результаты работы про-
грамм, а также операционные системы и символы псевдографики, появилась необ-
ходимость и в символах. Переменные символьного типа, как правило, могут хра-
нить только одиночный символ. В памяти такая переменная занимает 1 байт, соот-
ветственно может принимать 256 различных значений (на самом деле в памяти
хранятся лишь коды символов – которые соответствуют инструкциям как именно
изображать символы на экране). Зависимость между кодами символов и самими
символами устанавливается операционной системой. Однако традиционно первые
128 из них – это так называемые ASCII-символы. Первые 32 символа называются
управляющими (например, признак конца строки, подача звукового сигнала, пере-
вод курсора на новую строку), остальные изображаемыми. К сожалению, стандарт
ASCII не стал универсальным, и в современном мире для стандартизации символов
была создана специальная таблица – UNICODE (Юникод). При помощи этого стан-
дарта появилась возможность записать в универсальном виде практически любые
возможные символы. Более того, Юникод может расширяться без потери универ-
сальности почти безгранично. Достигается это за счет особого вида этой таблицы
символов. По мере изменения и пополнения таблицы символов системы Юникода
и выхода новых версий этой системы (эта работа ведётся постоянно), выходят и
новые стандарты. Актуальная на 2012 год версия имеет номер 6.1. Стандарт и
устройство Юникода позволяет работать с более чем 2 млрд. символов и, несмотря
на то, что принято использовать лишь 1 112 064 символов для совместимости с ко-
дировкой UTF-16, этого более чем достаточно. В настоящее время используется
«всего» около 110 тысяч символов.
5. Архитектура ЭВМ и принцип фон Неймана
Продолжая рассказ о типах данных, очень важно отметить, почему информа-
ция, хранящаяся в компьютере, может быть систематизирована и отнесена к раз-
личным видам данных. Почему современные компьютеры на программном уровне
устроены похожим образом? За счет чего компьютеры хранят информацию одина-
ково? Почему текстовые документы переносятся с компьютера на компьютер оди-
наково? Что если компьютер сам обрабатывает информацию и кодирует ее по-
своему? Переносимость информации на разные компьютеры, одинаковая интер-
19
претация ее в программах возможна благодаря принципам Джона фон Неймана. В
соответствии с его принципами создаются современные компьютеры и программы,
именно благодаря им современные компьютеры на программном уровне устроены
одинаково.
1. Принцип двоичного кодирования. Согласно этому принципу, вся ин-
формация, поступающая в ЭВМ, кодируется с помощью двоичных
сигналов (двоичных цифр, битов) и разделяется на единицы, называ-
емые словами.
2. Принцип однородности памяти. Программы и данные хранятся в
одной и той же памяти, поэтому компьютер не различает, что хра-
нится в данной ячейке памяти – число, текст или команда. То есть,
фактически, с точки зрения компьютера, информация не имеет
смысла. За обработку информации отвечают программы.
3. Принцип адресуемости памяти. Структурно основная память состо-
ит из пронумерованных ячеек. Процессору в произвольный момент
времени доступна любая ячейка. Отсюда следует возможность да-
вать имена областям памяти так, чтобы к запомненным в них значе-
ниям можно было впоследствии обращаться или менять их в процес-
се выполнения программ с использованием присвоенных имен.
4. Принцип программного управления. Программа состоит из набора
команд, выполняющихся процессором автоматически в определен-
ной последовательности, однозначно определяемой программой.
5. Принцип жесткости архитектуры. Первой выполняется команда,
заданная пусковым адресом программы. Обычно это адрес первой
команды программы. Адрес следующей команды однозначно опре-
деляется в процессе выполнения текущей команды и может быть
либо адресом следующей по порядку команды, либо адресом любой
другой команды. Процесс вычислений продолжается до тех пор, по-
ка не будет выполнена команда, предписывающая прекращение вы-
числений.
Компьютеры, построенные на перечисленных принципах, относятся к типу
фон-неймановских. Почти все современные компьютеры относятся именно к этому
типу компьютеров. Существуют и другие машины, не удовлетворяющие некото-
рым принципам фон Немана, но они являются специальными и в обычной жизни не
встречаются.
Конечно, любому программисту также важно знать, как именно устроен ком-
пьютер «изнутри». Не только для того, чтобы знать его основные компоненты, но
также и для того, чтобы представлять, с чем именно ему приходится работать. Ар-
хитектура современного компьютера также была разработана фон Нейманом. В
1946 году вместе с Г. Гольдстейном и А. Берксом он написал и выпустил отчет
"Предварительное обсуждение логической конструкции электронной вычислитель-
ной машины". Поскольку имя фон Неймана как выдающегося физика и математика
20
было уже хорошо известно в широких научных кругах, все высказанные положения
в отчете приписывались ему. Более того, архитектура первых двух поколений ЭВМ
с последовательным выполнением команд, на
основе которой строятся и современные ком-
пьютеры,
получила
название
"фон-
неймановской архитектуры ЭВМ" (см. Рису-
нок 8).
В данной схеме отмечен только один
вид памяти – оперативной. На самом деле,
конечно, в современных компьютерах видов
используемой памяти гораздо больше. Всю
память в компьютере можно разделить на две
большие группы – ОЗУ (оперативно запоми-
нающие устройства) и ПЗУ (постоянно запо-
минающие устройства). Чаще всего програм-
мист работает с оперативной памятью и с
информацией на внешних носителях – фай-
лами.
Как правило, вся информация на компьютере хранится следующим образом:
в ОЗУ хранятся те данные, с которыми в данный момент работает компьютер. В
ПЗУ – то, что нужно сохранить надолго. Информация, хранящаяся в ОЗУ компью-
тера, уничтожается при отключении питания от такой памяти. Самое простое раз-
деление такой памяти может быть на две категории – кэш процессора и оператив-
ную память. Ряд моделей центральных процессоров обладают собственным кэшем,
для того чтобы минимизировать доступ к оперативной памяти, которая медленнее,
чем регистры. Кэш-память может давать значительный выигрыш в производитель-
ности в случае, когда тактовая частота оперативной памяти значительно меньше
тактовой частоты процессора. Тактовая частота для кэш-памяти обычно почти сов-
падает с частотой процессора. Кэш центрального процессора разделён на несколько
уровней, в универсальном процессоре в настоящее время число уровней может до-
стигать трех. Самой быстрой памятью является кэш первого уровня, являющийся
неотъемлемой частью процессора, поскольку эта память расположена на одном с
ним кристалле и входит в состав функциональных блоков. Объём обычно невелик
— не более 384 Кбайт. Вторым по быстродействию является кэш второго уровня,
обычно он тоже расположен на кристалле и его объём может колебаться от 128
Кбайт до 1−12 Мбайт для современных процессоров. Кэш третьего уровня наиме-
нее быстродействующий, но он может быть очень внушительного размера – более
24 Мбайт, причем, несмотря на его низкое быстродействие, по сравнению с други-
ми уровнями кэш-памяти, он все равно быстрее оперативной памяти. Иногда суще-
ствует и четвертый уровень кэша, который обычно расположен на отдельной мик-
росхеме, такой кэш появляется, как правило, в высокопроизводительных серверах и
суперкомпьютерах.
Рисунок 8 – Архитектура ЭВМ
Оперативная память
Процессор
Устройство
управления
Устройство
ввода
Устройство
вывода
21
Оперативная память – это основной вид ОЗУ в компьютере. В ней временно
хранятся данные и команды, необходимые программам, запущенным на компьюте-
ре, а также процессору, для выполнения предписанных операций. Основное требо-
вание к оперативной памяти – достаточно высокое быстродействие и большой объ-
ем хранимой информации. Содержащиеся в оперативной памяти данные доступны
только тогда, когда на модули памяти подаётся напряжение. Прекращение подачи
питания на модули памяти, даже кратковременное, приводит к искажению либо
полной потере содержимого памяти.
Основным видом ПЗУ является, конечно же, магнитный диск. На основе этой
технологии долгое время строились такие носители информации как дискеты,
жесткие диски и т.д. Более современными носителями информации являются оп-
тические диски, а также флэш-память. Все эти виды носителей информации поз-
воляют хранить данные, даже когда питание от них отключено.
6. Разработка программного обеспечения
Вопросы проектирования программного обеспечения – одни из самых важ-
ных вопросов в программировании. Проектирование позволяет существенно сокра-
тить время разработки ПО, уменьшить число ошибок. Но – обо всем по порядку.
Прежде всего, нужно отдельно отметить цели и задачи, которые ставятся пе-
ред программированием в каждой области его применения. Назначение програм-
мирования во всех областях на самом деле одинаково: упростить и облегчить рабо-
ту специалистов, разработать новые инструменты для повышения эффективности
решения задач. Цели программирования – разные. В математике – это создание как
можно более точного и быстро работающего кода. В системном программировании
– написание компактных, умело работающих с аппаратными ресурсами машины,
операционных систем и других системных оболочек. В прикладном программиро-
вании – сделать так, чтобы программы выполняли как можно больше задач и были
легкими в применении. И так далее. В любой области программирования можно с
легкостью выделить те требования, что предъявляются к программам.
Вне зависимости от целей и назначения программирования, разработка про-
граммного обеспечения, по большому счету, идет всегда в соответствии с некими
общими правилами и этапами создания программ. Формально об этом нам могут
рассказать этапы разработки и версии ПО. Начнем с описания числового формата
версии программы. На самом деле для отслеживания изменений в программах и
сообщении пользователям о том, с какой программой они сейчас работают (более
новой, или уже устаревшей, например) было создано большое количество схем
присвоения номеров версиям программного обеспечения. Версии пробовали нуме-
ровать целыми числами, что оказалось неудобно из-за невозможности разделить
важные и не очень важные изменения. Иногда используют буквенные обозначения,
текущие даты, Дональд Кнут нумерует версии системы компьютерной вёрстки ΤΕΧ
последовательными приближениями числа
, но это уже, конечно, экзотика.
Наиболее распространенный и современный способ нумерации – это использова-
22
ние специального формата, в котором легко отражаются все изменения в програм-
ме, как важные и заметные пользователю, так и «внутренние» – интересные больше
программистам:
1.2.3.4
В этом обозначении у каждого из четырех чисел есть свой смысл, определя-
ющий значимость перемен между стадиями разработки ПО. В данном случае при-
няты такие правила: первое число (обозначенное цифрой 1) может быть изменено
только тогда, когда код программы практически полностью изменен, когда про-
грамма претерпела существенные изменения, заметные пользователю. Мы можем
назвать это число основной официальной версией продукта. Второе число (обозна-
ченное цифрой 2) обычно используется для указания на текущие обновления про-
граммы, заметные и важные, но не приводящие к кардинальному изменению про-
граммной оболочки. Мы можем назвать это число промежуточной официальной
версией продукта. Третье число (обозначенное цифрой 3) изменяется обычно неза-
метно для пользователя и связано с внутренними изменениями в программе. Ино-
гда такие изменения довольно важны для программистов, но могут не иметь ника-
кого значения с точки зрения пользователей. Мы можем назвать это число внут-
ренней версией продукта. Наименее значимым для пользователя является четвертое
число (обозначенное цифрой 4), оно изменяется при незначительных переменах в
интерфейсе программы, внешних ресурсах, документации. Очень часто четвертое
число отражает дату последнего обновления программы или изменения дополни-
тельных модулей (как, например, обновление антивирусных баз). Как правило, его
называют номером сборки или билдом (от английского обозначения build). Такой
подход позволяет пользователям (и даже потенциальным последователям создате-
лей программы), оценить, насколько было протестировано в реальных условиях
данное программное обеспечение, насколько современной является используемая
версия. Зачастую при изменении версий ПО возникают конфликты, связанные с
тем, что существенные изменения программ разработчики уже могут снова прода-
вать, а менее важные – должны предоставлять бесплатно. Иногда желание зарабо-
тать денег перевешивает ответственность перед пользователями и в создании но-
меров версий приводит к намеренным ошибкам в изменении версий. Например,
разработчики могут изменить номер версии, даже если ни одна строчка кода не бы-
ла переписана, лишь для того чтобы создать ложное впечатление, что были внесе-
ны значительные изменения в код программы. Или просто перерисовать иконки в
интерфейсе ПО и сказать, что это отражает существенное изменение функционала
программы. Доказать их неправоты в этих случаях очень сложно.
Типичная нумерация в данной схеме может выглядеть так (опуская неприн-
ципиальное четвертое число): 0.9, 0.9.1, 0.9.2, 0.9.3 – для начала работы над про-
граммой; 1.0, 1.0.1, 1.0.2, 1.1, 1.1.1 – для эволюций первой версии; 2.0, 2.0.1, 2.0.2,
2.1, 2.1.1, 2.1.2, 2.2 – для второй и т. д. Разработчики порой перескакивают от вер-
сии 5.0 сразу к 5.5, для того чтобы обозначить добавление нескольких значимых
функций в программе, однако их недостаточно, чтобы изменить главный номер
версии. Не все согласны с такой практикой и подобные скачки используются редко.
23
Очень часто промежуточные версии не выпускаются, в этом случае версии про-
граммы всегда целые и означают накопление существенных изменений для выхода
новой версии продукта. Так, например, часто поступает компания Adobe со своими
продуктами. В большинстве программного обеспечения, первая официальная вер-
сия программного продукта имеет версию 1, но это не правило, а скорее некая об-
щепринятая практика.
Другой подход использования главных и второстепенных номеров версий за-
ключается в добавлении буквенно-цифровой последовательности, определяя тем
самым стадию разработки релиза: «альфа», «бета», «релиз-кандидат». На самом
деле эти обозначения позволяют не только увидеть, с какой версией идет работа, но
и понять, на какой стадии находится разработка программы. В разработке про-
граммного обеспечения стадии разработки программного обеспечения используют-
ся для описания степени готовности программного продукта и могут применяться
для любых версий создаваемого ПО, но наиболее важны в момент, когда выпуска-
ется первая версия программы. Стадия разработки может отражать количество реа-
лизованных функций, запланированных для определённой версии программы, сте-
пень их готовности, уровень доступности программы пользователю (бесплатная
пробная версия или готовое платное ПО). Стадии либо могут быть официально
объявлены и регламентируются разработчиками, либо иногда этот термин исполь-
зуется неофициально для описания состояния продукта. В любом случае, использо-
вание специальных обозначений в номере версии, как правило, требует написания
соответствующего лицензионного соглашения. Этапы разработки присваиваются
любому создаваемому программному обеспечению, как правило, в виде следую-
щих названий:
1. Пре-альфа версия. Начальная стадия разработки – момент, когда про-
грамма только начинает разрабатываться или модернизироваться из
существующей стабильной версии. На этом этапе новый программный
продукт содержит множество ошибок, и может не обладать полным
функционалом, но показывает, в какую сторону двигаются разработчи-
ки. Такое название присваивают программам, прошедшим стадию раз-
работки, для первичной оценки функциональных возможностей в дей-
ствии.
2. Альфа версия. Внутреннее тестирование – стадия начала тестирования
программы в целом специалистами-тестерами, обычно не разработчи-
ками программного продукта, но, как правило, внутри организации,
разрабатывающей продукт. На этой стадии могут добавляться новые
функциональные возможности. Программы, находящиеся на первых
двух стадиях разработки, могут применяться только для ознакомления
с будущими возможностями и не становятся доступны пользователям.
3. Бета версия. Публичное тестирование – стадия активного тестирова-
ния и отладки программы, прошедшей первые этапы, если они были.
Программы этого уровня могут быть использованы другими разработ-
чиками программного обеспечения для испытания совместимости. Их
24
могут начинать демонстрировать пользователям, зачастую набирая
добровольных тестировщиков среди них (как часто бывает с компью-
терными играми). Программы на этом этапе разработки по-прежнему
могут содержать достаточно большое количество ошибок. Бета-версия
ПО не является финальной версией, и публичное тестирование произ-
водится на страх и риск пользователя, разработчик не несёт никакой
ответственности за ущерб, причинённый в результате использования
бета-версии. Этим часто пользуются создатели программ, предоставляя
пользователям только бета-версии продукта. Например, разработчики
ICQ в 2003-м году использовали это, выпустив бета-версию програм-
мы. Финальной версии ICQ 2003 так и не появилось, вместо этого два
года спустя вышли версии ICQ 4 и ICQ 5. Многими сообществами при-
знано, что 2003 версия продукта была самой «глючной» и с самым
большим содержанием рекламы за всю историю этого мессенджера.
4. Релиз-кандидат или rc (от англ. release candidate) – стадия-кандидат на
то, чтобы стать итоговой. Программы этой стадии прошли комплексное
тестирование, благодаря чему были исправлены все найденные крити-
ческие ошибки, тем не менее, некоторые ошибки могут быть выявлены
на этом этапе. Как правило, релиз-кандидаты используются для презен-
тации новых продуктов и часто создаются исключительно для марке-
тинговых целей.
5. Релиз или RTM (от англ. release to manufacturing промышленное изда-
ние) – издание продукта, готового к тиражированию и продаже. Это
стабильная версия программы, как правило, не содержащая ошибок,
прошедшая все предыдущие стадии.
Следует отметить, что стадии Бета и Альфа, выносимые иногда «на суд об-
щественности», не являются показателями нестабильности данной версии про-
граммы, т.к. присваиваются программе один раз или один раз за серию (изменения
в первом числе в номере версии), они могут присваиваться нескольким релизам
подряд. Важной характеристикой использования таких схем обозначения версий и
этапов является соблюдение идентичности стадий разработки версий. Например,
нельзя вносить никаких изменений между последней бета-версией и первым релиз-
кандидатом или последним релиз-кандидатом и готовым продуктом. Если это сде-
лано, необходимо выпустить другую версию на более низкой стадии разработки,
чтобы не прерывать нумерацию вносимых изменений в программу. В случае если в
процессе использования программы пользователями в ней обнаруживаются новые
ошибки, то их также устраняют, выпуская заплатки или патчи. Наряду с обновле-
ниями программы они тоже вносят изменения в версию продукта.
Теперь можно сформулировать некоторые правила и законы проектирования
программного обеспечения. Проектирование ПО – это целая наука и, конечно, все
рассказать в рамках короткого курса невозможно, но некоторые интересные факты
мы обсудим. Проектированию подлежат все три составных части программы – ин-
терфейс, функциональная часть и архитектура. Причем в каждой области, проекти-
25
рование – серьезная и сложная задача, требующая разработки специалистами в
данной области, также проектирование – неотъемлемая часть программирования.
Существуют разные подходы к проектированию ПО, как «ручные» так и автомати-
зированные. Если проект несложный, то его можно спроектировать просто «на бу-
маге», набросав план дальнейших действий и разрабатывая программу в соответ-
ствии с ним. Но если создаваемая программа сложна и состоит из большого числа
компонентов, то в этом случае часто прибегают к помощи вспомогательных про-
грамм. Одним из наиболее известных производителей такого специализированного
ПО является компания IBM Rational Software. Этой компанией были разработаны
различные средства автоматизации проектирования программных продуктов и баз
данных, в том числе RUP (Rational Unified Process). В основе Rational Unified Pro-
cess лежат следующие принципы:
раннее обнаружение и непрерывное (до окончания проекта) устранение
основных рисков, связанных с разработкой ПО;
концентрация на выполнении требований технического задания;
ожидание изменений в требованиях, проектных решениях и реализации
в процессе разработки;
компонентная архитектура ПО, реализуемая и тестируемая на ранних
стадиях проекта;
постоянное обеспечение качества на всех этапах разработки проекта;
работа над проектом в команде, в которой ключевая роль принадлежит
проектировщикам.
RUP – это, в своем роде, пособие по проектированию, оно помогает создавать
новые виды программного обеспечения, уменьшая риски, сокращая сроки выпол-
нения работ и т.п. Немного внимания мы обязательно уделим проектированию в
главе 9 – когда будем обсуждать вопросы проектирования баз данных. Теперь нуж-
но перейти к, пожалуй, самой важной главе и части курса – обсуждение разновид-
ностей языков программирования.
7. Языки программирования
Прежде, чем начинать рассказ о том где, в каких областях и для решения ка-
ких задач используются языки программирования, необходимо рассказать о спосо-
бах деления языков программирования на общепринятые в мире группы.
Одно из таких разделений – на низкоуровневые и высокоуровневые языки
программирования. Низкоуровневый язык программирования – это такой язык про-
граммирования, программы на котором пишутся непосредственно для процессора
или операционной системы. При этом, как правило, такие языки дают возможность
работать непосредственно с командами процессора или машинными кодами. Кроме
машинных команд языки программирования низкого уровня могут предоставлять
дополнительные возможности, такие как макроопределения (все чаще называемые
26
в последнее время макросами), а также возможность использования специальных
команд или инструкций. При помощи инструкций в таких языках появляется воз-
можность управлять процессом трансляции машинных кодов, создавая более
осмысленные тексты программ, понятные не только знакомым с процессорными
командами специалистам, но и программистам более широкого круга. Часто эти
языки позволяют работать вместо конкретных ячеек памяти с переменными, но при
этом язык может зависеть от особенностей конкретного семейства процессоров.
Классический пример одного из самых низкоуровневых языков – язык ассемблера,
(группа языков ассемблера – что более корректно). Если говорить о более «продви-
нутых» языках, то к низкоуровневым языкам можно отнести и некоторые классиче-
ские языки программирования, например, Си (хоть это и не совсем аккуратно). К
плюсам таких языков можно отнести чрезвычайно высокую скорость работы полу-
чающегося кода, оптимальное использование и оптимальная работа с машинными
ресурсами. Минусы низкоуровневых языков – довольно высокая сложность исход-
ного кода и наличие жестких ограничений на создаваемый код.
Высокоуровневый язык программирования – язык программирования, разра-
ботанный для быстроты и удобства использования программистом. Их главное от-
личие и преимущество перед низкоуровневыми языками – это абстракция, то есть
введение особых конструкций языка, кратко описывающих такие структуры дан-
ных и операции над ними, описания которых на машинном коде (или другом низ-
коуровневом языке программирования) могут быть очень громоздкими и сложны-
ми для понимания даже опытными программистами. Высокоуровневые языки поз-
воляют не только облегчить решение сложных задач, но и существенно упростить
процесс написания программного обеспечения, благодаря использованию, возмож-
но, менее универсальных, зато более понятных и простых программных решений.
К сожалению, тот факт, что высокоуровневые языки программы довольно далеки
от аппаратной реализации компьютера, имеет свои минусы. Например, код, форми-
руемый такими языками, работает гораздо медленнее низкоуровневых аналогов,
программы получаются менее эффективными, на таких языках нельзя писать про-
граммные инструкции к используемому оборудованию (драйверы) и т.д. Почти все
современные языки программирования могут быть отнесены в категорию высоко-
уровневых. Причем многие из них, например, скрипты, еще и зависят от установ-
ленного на компьютере программного обеспечения (Java, PHP, 1С). История высо-
коуровневых языков программирования, как считается, началась в 40-х годах про-
шлого века, но наиболее широкое распространение эти языки получили с создани-
ем Фортрана в 1957 году.
Еще одно деление языков программирования в современности может уже
считаться устаревшим, но оно позволяет лучше понять разницу между еще двумя
специальных терминами – блоками и модулями. Блочный язык программирования –
язык, в котором вся программа делится на части (подпрограммы), находящиеся в
определенной иерархической связи друг с другом. Эти участки кода называются
блоками и должны содержаться в одном файле. Блочная структура программы поз-
воляет при распределении памяти отводить одни и те же поля памяти машины для
хранения величин, описанных в блоках, которые не пересекаются, что приводит к
27
существенной экономии памяти во время работы программы. Модульные языки
программирования разделяют программу на модули – отдельные файлы, в которых
хранятся законченные фрагменты кода. Это деление было популярно в 60-70-х го-
дах прошлого века, когда формировались такие языки программирования как Си,
Фортран, Паскаль, Кобол, Ада и другие. Однако оно очень быстро исчерпало себя,
и современные языки программирования являются блочно-модульными. То есть,
позволят хранить подпрограммы как в блоках, так и в отдельных модулях.
Наиболее важным делением языков программирования является деление по
принципу используемых методологий программирования. Методология (или тех-
нология) программирования описывает совокупность правил, идей, методов, спо-
собов осуществления программистской деятельности. В зависимости от выбранной
методологии различаются исходный код программы, способы создания ПО, ис-
пользуемые ресурсы и внешний вид конечного продукта. Мы опишем несколько
наиболее важных и популярных методологий.
Методология структурного программирования в самой краткой формули-
ровке есть проектирование методом «сверху вниз» (или методом нисходящего про-
ектирования), т.е. написание текста программы от общего к частному, от наиболее
общих шагов алгоритма к максимально подробной детализации каждого шага.
Программирование для универсальных компьютеров начиналось с программирова-
ния в машинных кодах, затем появились и начали своё развитие языки высокого
уровня. Еще не так давно использование языков высокого уровня было невозможно
из-за малого объема внутренней памяти программ. Однако с развитием компью-
терных технологий появилась потребность унифицировать процесс разработки
программного обеспечения и ускорить его. Применение структурного программи-
рования позволяет существенно увеличить скорость написания программ, умень-
шить сложность кода, сократить число ошибок и облегчить отладку написанной
программы. Данная методология программирования была предложена в 70-х годах
XX века Э. Дейкстрой, и, впоследствии, разработана и дополнена Николаусом Вир-
том – автором известной книги «Алгоритмы и структуры данных», описывающей
основные идеи разработки алгоритмов в программировании, построения эффектив-
ных и надежных программ. В соответствии с данной методологией любая про-
грамма представляет собой набор блоков или модулей, подчиненных общей иерар-
хической схеме. Виртом были предложены следующие законы, которые легли в ос-
нову структурного программирования:
1. Любая программа представляет собой структуру, построенную из трёх
типов базовых конструкций, повторяющих свои аналоги из классиче-
ских алгоритмов:
a. последовательное исполнение – однократное выполнение опера-
ций в том порядке, в котором они записаны в тексте программы;
b. ветвление – однократное выполнение одной из двух или более
операций, в зависимости от выполнения некоторого заданного
условия;
28
c. цикл – многократное исполнение одной и той же операции до тех
пор, пока выполняется некоторое заданное условие (условие про-
должения цикла).
2. В программе базовые конструкции могут быть вложены друг в друга
произвольным образом, но никаких других средств управления после-
довательностью выполнения операций не предусматривается. Таким
образом, некоторые специальные команды языков программирования –
например, оператор безусловного перехода (goto) формально не явля-
ются разрешенными.
3. Повторяющиеся фрагменты программы (или же логически завершен-
ные участки кода) могут оформляться в виде подпрограмм (процедур
или функций).
4. Разработка программы ведётся пошагово, методом нисходящего проек-
тирования.
Опишем основные преимущества такого подхода. Прежде всего, в случае
применения структурного программирования сначала пишется текст основной про-
граммы, в котором вместо каждого связного логического фрагмента текста встав-
ляется вызов подпрограммы, которая будет выполнять этот фрагмент. В результате
основной исходный код становится более компактным, более понятным. Вместо
помещённого в подпрограмму фрагмента в код просто вставляется инструкция вы-
зова подпрограммы. Зачастую для ускорения разработки кода и упрощения отладки
вместо настоящих, работающих, подпрограмм в программу вставляются пустые
подпрограммы, не выполняющие никаких действий, не нагружающие результиру-
ющий машинный код. Если полученная программа работает правильно и без сбоев,
программист продолжает написание кода, постепенно заменяя все подпрограммы-
заглушки на реально работающие. В этом случае гарантируется работоспособность
программы на каждом из этапов разработки. Программисту не приходится работать
со всем текстом программы сразу – только с отдельными небольшими фрагмента-
ми. В случае возникновения необходимости внесения изменений такие изменения
вносятся, не затрагивая части программы, непосредственно не связанные с ними.
Это еще больше повышает надежность разработки кода. К сожалению, несмотря на
все плюсы, структурное программирование имеет и свои минусы. Программы, ко-
торые пишутся таким методом, всегда конкретные. Они нацелены на решение
определенных задач, что не очень удобно при разработке программного обеспече-
ния для современных графических операционных систем. В этих задачах чаще тре-
буется универсальность подхода, сборка программ из уже готовых «кирпичиков» –
абстрактных участков кода, ускоряющих разработку ПО.
Такие возможности предоставляет более современная методология програм-
мирования. Объектно-ориентированное программирование (часто сокращаемое до
ООП) – методология программирования, в основу которой положены понятия объ-
ектов и классов. Появление и развитие ООП начинается с 60-х годов прошлого века
(язык Simula 67, появившийся в 1967 году). Тем не менее, наиболее широко и полно
идеи этой методологии развились позже – к 80-м годам XX века, т.к. изначально
29
идеи ООП не были восприняты как нечто очень важное и принципиальное для раз-
вития программирования. Здесь огромную роль сыграли Алан Кэй и Дэн Ингаллс,
создав язык Smalltalk. Именно он стал первым широко распространённым объект-
но-ориентированным языком программирования, на основе идей этого языка Бьерн
Страуструп разрабатывал наиболее популярный в современном программировании
язык Си++. В настоящее время большинство программных проектов реализуются в
стиле ООП, благодаря возможности с большой скоростью разрабатывать новые
проекты из фактически уже готовых элементов – классов. Принципы, положенные
в основу ООП, очень просты – мы живем в мире объектов. Есть автомобили, дома,
компьютеры, и многое другое, что обладает не только своими уникальными осо-
бенностями, но и общими чертами. Существуют абстрактные объекты – числа,
символы, кнопки на поверхности современного графического приложения. Все они
могут быть описаны абстрактно, а затем каждый конкретный объект появляется из
такого абстрактного описания. Каждый объект характеризуется своими атрибутами
и выполняемыми действиями, все их можно универсальным образом описать в ви-
де класса – абстрактной конструкции, выражающей общие черты каждого уни-
кального объекта. Понятно, что написание программ, использующих уже готовые
классы, идет в несколько раз быстрее, чем если бы каждый объект пришлось опи-
сывать уникальным способом. Основными понятиями ООП становятся несколько
принципов, описывающих уникальную организацию таких языков программирова-
ния:
1. Абстракция данных. Все программы строятся на основе классов – аб-
страктных конструкций, отображающих общие свойства конкретных
объектов. Объекты представляют собой упрощенное, идеализированное
описание реальных сущностей предметной области.
2. Инкапсуляция. Согласно этому принципу, любой класс должен рас-
сматриваться как чёрный ящик – пользователь класса должен видеть и
использовать только интерфейсную часть класса (т. е. список «внеш-
них» декларируемых свойств и методов класса) и не вникать в его
внутреннюю реализацию. Тем самым повышается простота использо-
вания классов и надежность их использования, без опасений сломать
что-то «внутри» класса.
3. Сокрытие данных. Неотделимая часть ООП, логичное следствие ин-
капсуляции, управляющая областями видимости. Ограничивает доступ
к данным внутри класса.
4. Наследование. Наследованием называется возможность порождать
один класс от другого с сохранением всех свойств и методов класса-
предка и добавляя, при необходимости, новые свойства и методы.
5. Полиморфизм. Полиморфизмом называют явление, при котором функ-
ции (методу) с одним и тем же именем соответствует разный про-
граммный код (полиморфный код) в зависимости от того, объект како-
го класса используется при вызове данного метода.
30
Среди плюсов ООП однозначно нужно выделить высокую скорость разра-
ботки кода и максимальное упрощение программирования для программистов,
лишь использующих классы. Среди минусов такого подхода нужно выделить, к
сожалению, более медленную, по сравнению со структурными языками, работу ре-
зультирующего машинного кода. А также достаточно высокую сложность разра-
ботки собственно классов, для создания которых важно понимать внутреннее
устройство всех специальных механизмов ООП. Часто можно встретить фразу, что
знание других методологий не помогает в изучении ООП. Отчасти это правда.
Принципы и приемы ООП сильно отличаются от других языков программирова-
ния. Например, язык Си++ очень сильно отличается от простого Си, по большому
счету, у этих языков немного похож синтаксис. Но верно и другое – понимание
принципов структурного или какого-либо другого подхода к программированию
позволяет быстрее изучать ООП и создавать более эффективный и грамотный код.
Как я уже писал, существуют и другие, более специальные методологии про-
граммирования: логическое программирование, функциональное программирова-
ние, программирование в ограничениях и прочие. Эти методологии также приме-
няются в современном программировании, но в узком круге задач.
Давайте опишем некоторые особенности современных языков программиро-
вания, а также – какие задачи с их помощью решают. Наиболее важными для про-
граммирования и в настоящее время остаются языки программирования структур-
ные и низкоуровневые. Благодаря высокой скорости рабочего кода и возможности
работать напрямую с аппаратной частью компьютера они обеспечивают функцио-
нирования всех современных программ. Именно на этих языках пишутся функцио-
нальные части программ – «математика», без них современные операционные си-
стемы, сложное программное обеспечение, расчетные модули, архивация и шифро-
вание файлов работали бы в разы медленнее.
Важные задачи решают и высокоуровневые, как правило, объектно-
ориентированные языки. Они облегчают задачу написания интерфейсов программ,
в том числе графических. На них создаются многие современные прикладные про-
граммы и программное обеспечение для мобильных устройств. Эти языки привле-
кают к себе простой организацией процесса создания новых приложений и доста-
точно легким в изучении синтаксисом. Но внутреннее устройство таких языков
может быть достаточно сложным и их изучение – интересный и не всегда простой
процесс. К сожалению, совсем простых языков не бывает – программирование
сложная, но интересная область работы.
8. Структуры данных
Для понимания внутреннего устройства баз данных, а также того, как они
были придуманы, нужно ввести еще два понятия, широко используемых в про-
граммировании. Это специальные структуры данных, предназначенные для хране-
ния разных данных, в том числе, сложных.
31
Один из таких типов данных – массив. В создании внутренней конструкции
баз данных этот тип данных оказался самым важным. Массив – это непрерывный,
именованный набор однотипных переменных, доступ к которым осуществляется по
индексу. Индексом массива, как правило, является целое число (одно или несколь-
ко), в некоторых скриптовых языках, например JavaScript, PHP применяются также
ассоциативные массивы, в которых переменные не обязаны быть однотипными, и
доступ к ним не обязательно осуществляется по индексу, но это специфика данных
языков программирования, не имеющая никакого отношения к классическому
определению.
Наиболее часто встречающийся в программировании вид массива – одномер-
ный, который можно представить себе как просто данные, записанные в ряд. С та-
кими массивами не всегда удобно работать, но они очень эффективно хранятся в
памяти и компьютеру с ними работать удобнее. Именно они чаще всего встречают-
ся в расчетных задачах, и они же нам понадобятся для конструирования формата
файла баз данных. Также встречаются двумерные массивы, или таблицы, и трех-
мерные массивы. Массивы более высокой размерности существуют, но ими в про-
граммировании пользуются крайне редко – это ненужно и неудобно.
Основные преимущества массива заключаются в операциях, которые совер-
шаются над ними очень быстро. Прежде всего, это доступ к данным и поиск. Бла-
годаря тому, что информация в памяти хранится непрерывно, в любой момент про-
граммист может быстро получить доступ к данным по индексу массива, что позво-
ляет быстро читать и менять данные в массиве. Поиск, благодаря быстрому досту-
пу, тоже работает быстро – конечно, простой перебор не эффективен, но его всегда
можно оптимизировать. В связи с тем, что в массиве легко быстро искать данные, в
массиве легко собирать статистическую информацию (сколько в массиве одинако-
вых данных или пустых и т.д.), и сортировать данные. Все эти качества важны не
только для хранения данных в оперативной памяти, но и для баз данных. Одна про-
блема – в массиве можно хранить только одинаковые данные. А информация – раз-
ная. Но эту проблему легко обойти, для этого нужно рассмотреть еще один вид
специальных конструкций данных.
Записи – это особый вид данных, используемый наряду с массивами – это
структурированный тип, содержащий набор объектов разных типов. Составляющие
запись объекты называются ее полями. В записи каждое поле имеет свое собствен-
ное имя. Чтобы описать запись, необходимо указать ее имя, имена объектов, со-
ставляющих запись и их типы. Для нас очень важным является то, что записи поз-
воляют хранить разнотипные данные, что позволит одновременно с этим организо-
вать хранение таких данных в массиве.
Теперь принцип устройства формата файлов базы данных видно невоору-
женным глазом. Правило и в самом деле очень простое. Вся информация, которую
необходимо сохранить в базе разбивают на записи (будущие строки базы) в кото-
рых вся информация хранится в фиксированном виде – в полях (столбцы). Каждое
поле имеет фиксированный размер и бывает числовым, текстовым, датой и т.д. Всю
информацию записывают в файл в виде массива – все записи пишутся подряд, без
32
промежутков и занимают в файлах одну и ту же длину. В результате мы получаем,
что файл базы данных – это просто массив записей, хранящийся на диске, а не в
оперативной памяти. Вот такая простая идея. Она оказалась настолько удачной, что
с момента создания баз данных и развития идей их устройства (1955-1960 гг.)
принципиально этот формат не менялся. Терминология, связанная со структурой
баз данных также берется из программирования. В базах данных не используются
термины строка или столбец (более того, использование термина таблица приме-
нительно к базе данных некорректно – но это мы еще отметим), вместо этого гово-
рят запись и поле соответственно. Формальное определение базы данных может
звучать так:
1. База данных – организованная в соответствии с определёнными прави-
лами и поддерживаемая в памяти компьютера совокупность данных,
характеризующая актуальное состояние некоторой предметной области
и используемая для удовлетворения информационных потребностей
пользователей.
2. База данных – совокупность данных, хранимых в соответствии со схе-
мой данных, манипулирование которыми выполняют в соответствии с
правилами средств моделирования данных.
3. База данных – некоторый набор перманентных (постоянно хранимых)
данных, используемых прикладными программными системами какого-
либо предприятия.
4. База данных – совместно используемый набор логически связанных
данных (и описание этих данных), предназначенный для удовлетворе-
ния информационных потребностей организации.
По большому счету, все эти определения говорят об одном и том же и могут
использоваться равноправно. Существует огромное количество разновидностей баз
данных, отличающихся по различным критериям. Например, в «Энциклопедии
технологий баз данных» (Когаловский М.Р.), определяются свыше 50 видов БД.
Мы отметим некоторые, наиболее часто используемые.
1. Классификация по модели данных:
a. Иерархическая
b. Сетевая
c. Реляционная
d. Объектная и объектно-ориентированная
e. Объектно-реляционная
f. Функциональная.
2. Классификация по среде постоянного хранения:
a. Во вторичной памяти, или традиционная: средой постоянного
хранения является периферийная энергонезависимая память (вто-
33
ричная память) — как правило, жёсткий диск. В оперативную
память СУБД помещает лишь временный кэш и данные для те-
кущей обработки.
b. В оперативной памяти: все данные на стадии исполнения нахо-
дятся в оперативной памяти.
c. В третичной памяти: средой постоянного хранения является от-
соединяемое от сервера устройство массового хранения (третич-
ная память), как правило, на основе магнитных лент или оптиче-
ских дисков. Во вторичной памяти сервера хранится лишь ката-
лог данных третичной памяти, файловый кэш и данные для теку-
щей обработки; загрузка же самих данных требует специальной
процедуры.
3. Классификация по содержимому:
a. Географическая.
b. Историческая.
c. Научная.
d. Мультимедийная.
4. Классификация по степени распределения:
a. Централизованная, или сосредоточенная: БД, полностью поддер-
живаемая на одном компьютере.
b. Распределённая: БД, составные части которой размещаются в
различных узлах компьютерной сети в соответствии с каким-
либо критерием.
c. Неоднородная: фрагменты распределённой БД в разных узлах се-
ти поддерживаются средствами более одной СУБД
d. Однородная: фрагменты распределённой БД в разных узлах сети
поддерживаются средствами одной и той же СУБД.
Существуют и другие виды баз данных, более специфические, при этом, каж-
дая конкретная база данных может относиться к нескольким типам сразу. Вопросы
проектирования и работы с базами данных мы рассмотрим в главе 9. Но прежде,
обратимся еще к нескольким интересным фактам, относительно структурных видов
данных.
На основе записей можно построить специальные динамические конструкции
данных, широко используемые в создании алгоритмов расчетных и системных за-
дач. Вряд ли любому программисту понадобится разбираться в этих конструкциях,
но знать о них и представлять себе то, как они работают, безусловно, важно.
Абстрактные структуры данных предназначены для удобного хранения и
доступа к информации. Они предоставляют удобный интерфейс для типичных опе-
раций с хранимыми объектами, скрывая детали реализации от пользователя. Ко-
34
Эл1
Эл2
ЭлN
…
Эл1
Эл2
ЭлN
…
ЭлN
Эл1
…
…
ЭлN
Эл1
…
…
нечно, это весьма удобно и позволяет добиться большей модульности программы.
Среди обычных типов данных также присутствуют абстрактные структуры данных
– например, числа. Языки программирования высокого уровня (Паскаль, Си)
предоставляют удобный интерфейс для чисел: операции +, *, =, …, но при этом
скрывают саму реализацию этих операций, машинные команды. В языках объект-
но-ориентированных идут еще дальше, давая возможность создавать целые про-
граммы из абстрактных конструкций.
Динамические структуры по определению характеризуются отсутствием фи-
зической связи между элементами структуры в памяти, непостоянством и непред-
сказуемостью размера (числа элементов) структуры в процессе ее обработки. По-
скольку элементы динамической структуры располагаются по непредсказуемым
адресам памяти, адрес элемента такой структуры не может быть вычислен из адре-
са начального или предыдущего элемента, то есть элементы таких структур «ниче-
го не знают друг о друге». Для установления связи между элементами динамиче-
ской структуры используются специальные ссылки (в языке Си – указатели). Такое
представление данных в памяти называется связным. Элемент динамической
структуры состоит из двух полей:
информационного поля или поля данных, в котором содержатся те дан-
ные, ради которых и создается структура;
поле для осуществления связей, в котором содержатся одна или не-
сколько ссылок, связывающих данные элементы с другими элементами
структуры.
Когда связное представление данных используется для решения прикладной
задачи, для конечного пользователя «видимым» делается только содержимое ин-
формационного поля, а поле связок используется только программистом-
разработчиком, согласно принципам абстракции. Преимуществом такого подхода
является возможность произвольно менять
размеры структур, как угодно переставлять
связи между элементами, быстро добавлять
и удалять элементы в любое место структу-
ры. Естественно, за эти преимущества при-
ходится платить – расходом лишней опера-
тивной памяти на ссылки, более медленным
доступом к данным, чем, например, в масси-
ве, довольно сложным программированием
механизма связей. Основной минус здесь – это замедление доступа к данным. В та-
ких структурах теряет смысл индексация, принятая в массивах, получить доступ к
данным можно только посредством ссылок и последовательного просмотра всех
элементов.
Одними из наиболее важных видов динамических структур данных являются
списки. Списком называется упорядоченное множество, состоящее из переменного
числа элементов, к которым применимы операции включения, исключения (добав-
Рисунок 9 – Виды списков
35
ления и удаления элементов соответственно). Всего в программировании исполь-
зуют несколько принципиально разных видов списков, их принципиальное устрой-
ство показано на Рисунок 9. У этих списков есть специальные названия (сверху
вниз):
Линейный однонаправленный.
Линейный двунаправленный.
Циклический (кольцевой) однонаправленный.
Циклический (кольцевой) двунаправленный.
На базе списков можно построить еще более интересные конструкции: стеки,
деки и очереди, а также, деревья.
Стек – линейный список с переменной длиной, включение
и исключение элементов из которого выполняются только с од-
ной стороны списка, называемого вершиной стека, принцип ра-
боты стека часто выражают аббревиатурой LIFO (Last - In - First-
Out – «последним пришел – первым исключается»). Основные
операции над стеком – включение нового элемента (английское
название push) и исключение элемента из стека (англ. pop). Фор-
мальное описание стека – вещь скучная, лучше всего предста-
вить себе стек в виде стакана, куда складывают шарики (см. Ри-
сунок 10), тогда все законы становятся более понятными – поче-
му элементы можно добавлять и брать только «сверху» – для из-
влечения шариков из середины стека будут «мешаться стенки». Чаще всего исполь-
зуются стеки в системном программировании – именно в них операционная систе-
ма хранит информацию о переменных, используемых программами.
Дек – особый вид очереди, это такой последовательный список, в котором как
включение, так и исключение элементов может осуществляться с любого из двух
концов списка. Наиболее часто встречающийся вид очереди – очередь FIFO (First -
In - First- Out – «первым пришел – первым исключается») – это последовательный
список с переменной длиной, в котором включение элементов выполняется только
с одной стороны списка (эту сторону часто называют кон-
цом или хвостом очереди), а исключение – с другой сторо-
ны (называемой началом или головой очереди). Классиче-
ским примером очереди может быть обычная очередь или
автоматизированный конвейер.
Все эти структуры – одномерные: в них один элемент
следует за другим. Дерево – двумерная связанная структура,
на которых основаны многие из наиболее важных алгорит-
мов, например алгоритмы сжатия данных, шифрования
данных. Полное описание деревьев могло бы занять не одну
книгу, потому что они возникают во многих задачах, даже
Рисунок 10 – Стек
Рисунок 11 – Дерево
36
вне информатики, и довольно интенсивно изучаются как математический объект.
Мы рассматривать деревья подробно не будем, лишь укажем на то, какие виды де-
ревьев бывают, и опишем основные определения.
Самыми простыми из деревьев считаются бинарные деревья. Бинарное дере-
во – это конечное множество элементов, которое либо пусто, либо содержит один
элемент, называемый корнем дерева, а остальные элементы множества делятся на
два непересекающихся подмножества, каждое из которых само является бинарным
деревом. Эти подмножества называются левым и правым поддеревьями исходного
дерева. Каждый элемент бинарного дерева называется узлом дерева (см. Рисунок
11).
Также бывают красно-черные деревья, деревья поиска (используемые при
программировании DNS-серверов) и т.д.
9. Базы данных и их проектирование
В этой главе мы с Вами обсудим вопросы работы с базами данных на про-
граммном уровне и проектирования баз данных и таких программ.
Начнем с самого сложного – это самая сложная с точки разработки и самая
функциональная возможность работать с базами данных – информационная систе-
ма. Информационная система (ИС) может быть определена двумя способами – как
в широком, так и в узком смысле. В широком смысле информационная система это
совокупность технического, программного и организационного обеспечения, а
также персонала, предназначенная для того, чтобы своевременно обеспечивать
надлежащих людей надлежащей информацией. Зачастую в это определение персо-
нал не включают, что, на мой взгляд, не очень правильно. Дело в том, что большая
часть информационных систем – это очень сложное программное обеспечение и
для работы с ним нужны высококвалифицированные специалисты. Зачастую рабо-
тать с ИС может только специалист с соответствующим сертификатом. Таким об-
разом, такие люди тоже могут быть неотъемлемой частью информационной систе-
мы. Используют это определение, когда говорят про работу в информационном
пространстве компании, когда учитывают и компьютеры, и сети, и программное
обеспечение, и персонал.
В узком смысле информационной системой называют только подмножество
компонентов ИС в широком смысле, включающее базы данных, СУБД и специали-
зированные прикладные программы. Определение ИС в узком смысле используют,
когда речь идет о непосредственной работе с программой.
Какое бы из определений мы не использовали, основной задачей ИС является
удовлетворение конкретных информационных потребностей в рамках конкретной
предметной области. В связи с этим, любая ИС содержит в себе язык программиро-
вания, чтобы можно было решать в рамках этой системы на самом деле любые за-
дачи. Современные ИС состоят из двух принципиальных частей – системы управ-
ления базами данных и набора вспомогательных программ. Таким образом, совре-
37
менные ИС ассоциируются не столько с программным обеспечением, сколько с са-
мими базами данных и СУБД. Но благодаря тому, что в ИС всегда есть дополни-
тельные программы, выполняющие вспомогательные функции, их функции гораздо
шире.
В идеале в рамках предприятия должна функционировать единая корпора-
тивная информационная система, удовлетворяющая все существующие информа-
ционные потребности всех сотрудников, служб и подразделений. Однако на прак-
тике создание такой всеобъемлющей ИС слишком затруднено или даже невозмож-
но, вследствие чего на предприятии обычно функционируют несколько различных
ИС, решающих отдельные группы задач: управление производством, финансово-
хозяйственная деятельность и т.д. Часть задач бывает «покрыта» одновременно не-
сколькими ИС, часть задач — вовсе не автоматизирована. Такая ситуация получила
название лоскутной автоматизации и является довольно типичной для многих
предприятий.
В любом случае, проектирование такой системы это очень сложная задача
для разработчика – и именно на этом примере мы рассмотрим вопросы, связанные с
проектированием программного обеспечения.
Прежде всего, разработчикам программного обеспечения приходится столк-
нуться с требованиями, которые предъявляют пользователи к создаваемым про-
граммам. Если мы говорим про базы данных, то самое главное требование в совре-
менном мире – это, конечно же, обеспечение надежного и безопасного хранения
информации. Учитывая, как часто происходят кражи информации в наши дни, это
требование является самым главным и его необходимо удовлетворить в первую
очередь. Затем находят компромисс между быстродействием, надежностью пере-
дачи данных и простотой использования. Эти требования редко удается удовлетво-
рить все сразу, поэтому и приходится делать выбор.
Теперь опишем, какие задачи приходится решать в процессе проектирования
базы данных:
1. Обеспечение хранения в БД всей необходимой информации. Мы долж-
ны гарантировать, что любые новые данные, которые будут появляться
в процессе работы с базой, смогут быть сохранены в ней без изменения
ее структуры.
2. Обеспечение возможности получения данных по всем необходимым
запросам. То есть, структура и формат базы данных должны подразу-
мевать возможность поиска любой нужной информации с любыми кри-
териями выбора.
3. Сокращение избыточности и дублирования данных. Это требование
крайне важно – оно позволяет гарантировать то, что база не будет рас-
ходовать лишний объем памяти, и данные не будут повторять друг дру-
га (это опасно – может привести к путанице).
38
4. Обеспечение целостности данных (правильности их содержания). Это
требование к базе позволяет исключить противоречия в содержании
данных, исключение их потери, запись данных в неверные поля и т.д.
Как видите, задачи, решаемые в процессе проектирования, охватывают все
вопросы, связанные с хранением информации. Разработка новой информационной
системы еще и связана с созданием большого набора вспомогательных программ,
таким образом, создание информационной системы – один из наиболее сложных
видов проектирования. Опишем основные этапы проектирования:
Концептуальное (инфологическое) проектирование – построение концепции
устройства базы данных, способов организации информации и устройства про-
граммного обеспечения. Это разработка идеи – основных, общих конструкций но-
вой ИС. Такая модель создаётся без ори-
ентации на какую-либо конкретную реа-
лизацию и модель данных – без конкрети-
ки. Термины семантическая модель, кон-
цептуальная модель и инфологическая
модель являются синонимами. Конкрет-
ный вид и содержание концептуальной
модели базы данных определяется вы-
бранным способом проектирования. Чаще
всего используются графические нотации,
например, ER-диаграммы и специальные
UseCase модели. Чаще всего концептуаль-
ная модель базы данных включает в себя
описание методов работы с данными и
структуру данных, описание того, какие
пользователи будут работать с базой и т.д.
В процессе проектирования одна из клю-
чевых задач – определение того, какие пользователи, как и с чем смогут взаимодей-
ствовать с создаваемым ПО. Для решения такой задачи как раз и могут пригодиться
ER-модели и UseCase-модели. На примере покажем, как это может выглядеть. Об-
ратите внимание на Рисунок 12, на нем показано графическое представление Use-
Case модели для базы данных, скажем, электронного журнала некоего учебного за-
ведения. По этой схеме видно, что разным видам пользователей мы даем разные
возможности доступа к данным в базе. Например, студенты могут только читать
данные из базы, в то время как менеджеры (скажем, сотрудники деканата) могут
еще и редактировать информацию. Ну а самым главным является администратор,
который, помимо прочего, имеет еще и доступ к аварийной копии базы. Кстати о
наличии этой копии многие при проектировании базы забывают, в то время как для
полноценного функционирования базы ее наличие обязательно.
Для построения ER-моделей используют различные способы визуального
представления данных. Они уже гораздо сложнее UseCase диаграммы и имеют да-
student
teacher
manager
administrator
BackUp
DataBase
Рисунок 12 – UseCase модель
39
же именные названия. Выделим ряд наиболее популярных способов отображения
данных:
Нотация Питера Чена. Множества сущностей (составляющих части про-
грамм или функциональных элементов) изображаются в виде прямоугольников,
множества отношений изображаются в виде ромбов. Если сущность участвует в
отношении, они связаны линией. Если отношение не является обязательным, то
линия пунктирная. Атрибуты изображаются в виде овалов и связываются линией с
одним отношением или с одной сущностью.
Crow's Foot. Данная нотация была предложена Гордоном Эверестом под
названием перевёрнутая стрелка, однако сейчас чаще называемая Crow's Foot (во-
ронья лапка) или Fork (вилка). Согласно данной нотации, сущность изображается в
виде прямоугольника, содержащем её имя, выражаемое существительным. Имя
сущности должно быть уникальным в рамках одной модели. Связь изображается
линией, которая связывает две сущности, участвующие в отношении. Степень кон-
ца связи указывается графически, множественность связи изображается в виде сво-
его рода вилки на конце связи. Атрибуты сущности записываются внутри прямо-
угольника, изображающего сущность, и выражаются существительным в един-
ственном числе (возможно, с уточняющими словами).
Также есть и другие виды нотаций – Bachman notation, EXPRESS, IDEF1x,
UML и т.д.
Логическое (даталогическое) проектирование – создание схемы базы данных
на основе конкретной модели данных, например, реляционной модели данных. Для
реляционной модели данных даталогическая модель – набор схем отношений,
обычно с указанием первичных ключей, а также «связей» между отношениями,
представляющих собой внешние ключи. Преобразование концептуальной модели в
логическую модель, как правило, осуществляется по формальным правилам. Этот
этап может быть в значительной степени автоматизирован. На этапе логического
проектирования учитывается специфика конкретной модели данных, но может не
учитываться специфика конкретной СУБД. Этот этап – один из самых важных в
проектировании. На этом этапе, фактически, строится итоговый вариант ПО. После
этого этапа риски «провалить» проект минимальны. Для проектирования на этом
этапе также используются различные нотации, но уже гораздо более сложные, чем
на этапе концепции.
Физическое проектирование – создание схемы базы данных для конкретной
СУБД. Специфика конкретной СУБД может включать в себя ограничения на име-
нование объектов базы данных, ограничения на поддерживаемые типы данных и
т.п. Кроме того, специфика конкретной СУБД при физическом проектировании
включает выбор решений, связанных с физической средой хранения данных (выбор
методов управления дисковой памятью, разделение БД по файлам и устройствам,
методов доступа к данным), создание индексов и т.д.
Более простая программа для работы с базами данных – это СУБД или си-
стема управления базами данных. Этот вид программного обеспечения по работе с
40
БД оптимален для небольших компаний и решения небольших задач по хранению
информации. Основными функциями СУБД являются вполне конкретные задачи, в
отличии от ИС, которая может удовлетворять любые информационные потребно-
сти пользователей. Укажем функции СУБД:
1. управление данными во внешней памяти (на дисках);
2. управление данными в оперативной памяти с использованием дисково-
го кэша;
3. журнализация изменений, резервное копирование и восстановление ба-
зы данных после сбоев, создание отчетов, вспомогательные функции
для конструирования запросов;
4. поддержка языков БД (язык определения данных, язык манипулирова-
ния данными).
Обычно современная СУБД содержит следующие компоненты: ядро, которое
отвечает за управление данными во внешней и оперативной памяти, и журнализа-
цию. Систему обработки языка базы данных, обеспечивающую независящий от са-
мой системы способ извлечения данных – например, язык SQL. Систему, обеспе-
чивающую работу пользовательского интерфейса и сервисные программы (внеш-
ние утилиты), обеспечивающие ряд дополнительных возможностей.
Самая простая и компактная программа по работе с информацией – это сер-
вер баз данных. Такие программы имеют несколько отличительных черт. Они, как
правило, очень компактные и быстродействующие. Сервера всегда обладают ми-
нимальным функционалом, как правило, обеспечивая первичный доступ к данным
– красиво обработать и подать его пользователю нужно отдельно, в другой про-
грамме. Таким образом, сервера используются в качестве посредников для обра-
ботки данных другими приложениями. Цепочку, связывающую разные системы
для работы с базами данных по их сложности и уровню решаемых задач, можно
изобразить так:
Рисунок 13 – Иерархия ПО для работы с базами данных
ИС
СУБД
вспомогательные
программы
Сервер БД
вспомогательные
функции
41
Базы данных бывают разные, по способу внутренней организации данных их
можно разделить на следующие группы:
Иерархические
Сетевые
Реляционные
Объектно-ориентированные
Объектно-реляционные
Наиболее интересной и важной разновидностью баз данных являются реля-
ционные базы. Их создание требует длительного проектирования, но при этом они
позволяют решать любые задачи, предъявляемые пользователями к базам данных.
Реляционная база данных – база данных, основанная на реляционной модели дан-
ных, эта тавтология – наиболее популярное определение этого вида БД. Дело в том,
что эти базы обязаны своим появлением особому термину «реляционный», проис-
ходящему от англ. relation – отношение. Для работы с реляционными БД применя-
ют реляционные СУБД, умеющие работать не с таблицами баз данных, а с их от-
ношениями. Использование реляционных баз данных было предложено Эдгаром
Франком Коддом из компании IBM в 1970 году. Им были разработаны все термины
и правила работы с такими базами данных, которые используются и в наше время.
Основная конструкция таких баз данных – это нормальная форма, устройство от-
ношения между разными наборами данных в реляционной модели данных. Нор-
мальная форма определяется как совокупность требований, которым должно удо-
влетворять отношение. Процесс преобразования отношений в БД к виду, отвечаю-
щему нормальным формам, называется нормализацией. Нормализация предназна-
чена для приведения структуры БД к виду, обеспечивающему минимальную логи-
ческую избыточность, и не имеет целью уменьшение или увеличение производи-
тельности работы или же уменьшение или увеличение физического объёма базы
данных. Конечной целью нормализации является уменьшение потенциальной про-
тиворечивости хранимой в базе данных информации, обеспечение решения всех
задач, которые ставят пользователи перед БД, и хранение всей возможной инфор-
мации.
При том, что идеи нормализации весьма полезны для проектирования баз
данных, они отнюдь не являются универсальным или исчерпывающим средством
повышения качества проекта БД. Это связано с тем, что существует слишком
большое разнообразие возможных ошибок и недостатков в структуре БД, которые
нормализацией не устраняются. Тем не менее, этот процесс и сами реляционные
базы данных являются очень популярными для хранения информации.
В результате нормализации решения задачи хранения данных получается ре-
ляционная база в одной из нормальных форм – особых видов отношений в базе,
при которых убираются противоречия в данных. Всего таких форм семь: первая
нормальная форма (1NF), вторая нормальная форма (2NF), третья нормальная фор-
ма (3NF), нормальная форма Бойса-Кодда (BCNF), четвёртая нормальная форма
42
(4NF), пятая нормальная форма (5NF), доменно-ключевая нормальная форма
(DKNF) и шестая нормальная форма (6NF).
Все современные разработки в области баз данных в настоящее время ведут-
ся в области сетевых и распределенных баз данных. Распределенные БД представ-
ляют собою набор узлов, связанных коммуникационной сетью, в которой:
каждый узел – это полноценная СУБД сама по себе;
узлы взаимодействуют между собой таким образом, что пользователь
любого из них может получить доступ к любым данным в сети так, как
будто они находятся на его собственном узле.
Каждый узел сам по себе является системой базы данных. Любой пользова-
тель может выполнить операции над данными на своём локальном узле точно так
же, как если бы этот узел вовсе не входил в распределённую систему. Распределён-
ную систему баз данных можно рассматривать как партнёрство между отдельными
локальными СУБД на отдельных локальных узлах. Основные проблемы таких баз –
это необходимость работать с невероятно большими объемами данных, обеспечи-
вать надежность работы таких систем и безопасность хранения данных. Для разра-
ботки таких БД вводят даже особый список из дополнительных правил, всего их
двенадцать. Среди них очевидные требования – вроде независимости от операци-
онных систем или работа базы даже при отключении некоторых узлов, а также не-
тривиальные правила – независимость обработки данных от их расположения и не-
зависимость от фрагментации данных (разреженность в данных, их хранения в раз-
ных узлах распределенной БД). Эти и другие технологии работы с большими база-
ми данных в настоящее время наиболее активно развиваются как в программном,
так и в техническом смысле.
10.
Приложения
Приложение 1.
Краткий обзор языка программирования Си
В этом приложении мы кратко познакомимся с основными конструкциями
языка Си. Наша цель – показать на реальных программах существенные элементы
языка, не вдаваясь в мелкие детали, формальные правила и исключения из них. Для
этого мы должны рассмотреть некоторые несложные элементы языка: структуру
кода, примеры некоторых команд и операторов.
Единственный способ выучить новый язык программирования – это писать
на нем программы. Для того чтобы понять, как устроены структурные языки про-
граммирования крайне важно, вначале, изучить язык Си. При изучении любого
языка любой программист первой пишет всегда одну и ту же программу – которая
выводит на экран монитора сообщение «Hello World!». Простейшая Си-программа,
печатающая этот текст, выглядит так:
#include <stdio.h>
int main(void)
43
{
printf("Hello World!\n");
return 0;
}
Как запустить эту программу, зависит от системы, которую вы используете.
Мы рассмотрим в качестве примера компиляцию и запуск программы в системе
UNIX. Для компиляции подают в консоли следующую команду:
cc hello.c
Если при компиляции не возникло ошибок, то появится исполняемый файл со
стандартным именем для этой ОС – a.out. Этот файл можно запустить на выполне-
ние и на экране монитора появится текст:
Hello World!
И в конце этой строки произойдет перевод курсора на новую строку. Про-
изойдет это благодаря команде \n, которая в языке Си является специальным сим-
волом, можно так сказать, имитирующим нажатие клавиши Enter. Для того чтобы
пояснить написанный текст, дадим несколько пояснений. Программа на Си (и на
многих других структурных языках, построенных на основе Си), каких бы разме-
ров она ни была, состоит из функций и переменных. Функции содержат инструк-
ции, описывающие вычисления, которые необходимо выполнить, а переменные
хранят значения, используемые в процессе этих вычислений. Функции в Си похожи
на подпрограммы других языков программирования, в приведенной программе –
описана главная функция языка с именем main, это особое имя: любая программа
начинает работу с первой команды функции main.
Первая строка программы:
#include <stdio.h>
сообщает компилятору, что он должен использовать в компиляции информа-
цию о стандартной библиотеке ввода-вывода (standard input/output). Эта строка
встречается в начале многих исходных файлов работающих с монитором и файла-
ми Си-программ.
Единственная команда программы, заключается в вызове функции printf:
printf("Hello, world\n");
Функция вызывается по имени функции, после которого, в скобках, указыва-
ется список аргументов. Функция printf – это библиотечная функция, которая в
данном случае напечатает последовательность символов, заключенную в двойные
кавычки. Фигурные скобки в данном примере играют туже роль, что и, например,
ключевые слова begin и end в Паскале – указывают начало и конец блока програм-
мы.
Рассмотрим более сложный пример:
#include <stdio.h>
int main(void)
44
{
int a,b,c;
b=5;
c=2;
a=b+c;
printf("Result = %d\n",a);
return 0;
}
В данной программе наиболее интересными являются строки, содержащие
переменные. Прежде всего, это строка
int a,b,c;
в которой мы объявляем три переменные целого типа. Такая строка обяза-
тельна во всех структурных языках программирования, она информирует компиля-
тор о том, как в дальнейшем работать с такими переменными. В Си любая пере-
менная должна быть объявлена раньше, чем она будет использована; обычно все
переменные объявляются в начале функции перед первой исполняемой командой.
В объявлении описываются свойства переменных, которые могут состоять не толь-
ко из указания типа данных. Помимо типа данных int в Си имеется еще несколько
базовых типов для данных, это:
char – символьный тип;
long – длинное целое;
float – число с плавающей точкой;
double – с плавающей точкой с двойной точностью.
Размеры объектов указанных типов зависят от машины и разрядности опера-
ционной системы.
Любая команда программы заканчивается точкой с запятой. Некоторые ко-
манды являются вычисляемыми выражениями. Например:
a=b+c;
В этой команде происходит очевидное действие – вычисление суммы значе-
ний двух переменных b и c. Результат сохраняется в переменную a. Таких операций
в языках программирование много. Среди стандартных команд, общих для всех
языков можно выделить такие:
+ – сложение;
- – вычитание;
* – умножение;
/ – деление;
45
< – сравнение «меньше»;
> – сравнение «больше»;
<= – сравнение «меньше или равно»;
>= – сравнение «больше или равно»;
Казалось бы, в этом списке должны быть и команды сравнения на равенство,
но вот они, как ни странно, универсальными не являются и зависят от языка.
Также необходимо отметить еще две важные конструкции языка Си – это
операторы условия и цикла. Чтобы рассмотреть эти два действия, посмотрим, для
начала, на такой пример:
#include <stdio.h>
int main(void)
{
int a,b,c;
b=5;
c=0;
if (c!=0)
{
a=b+c;
printf("Result = %d\n",a);
}
else
{
printf("Error! Division by zero!\n");
}
return 0;
}
Здесь ключевую роль играет
оператор if-else, оператор условия.
В рассмотренном примере на экран
будет выведена строка
Error! Division by zero!
Поясним это. Структура опе-
ратора if может быть представлена
в виде схемы (см. Рисунок 14). В
соответствии с нею любой оператор условия работает следующим образом: если
условие, указанное в операторе выполнено, то работает блок программы, написан-
ный сразу после него. Если же условие не выполнено, то тот блок, что стоит после
if
условие
действия, выполняющиеся если
условие выполнено
else
действия, выполняющиеся если
условие не выполнено
Рисунок 14 – Структура оператора if-else
46
ключевого слова else. Вторая часть условия не обязательна – оператор if может ра-
ботать и без второй части. В связи с тем, что значение переменной c – 0 и условие,
записанное в скобках, значит «c не равно нулю», то выполняется тот блок команд,
что написан после else – а там как раз и стоит вывод на экран сообщения об ошиб-
ке.
Видов операторов цикла несколько. Универсальными и присутствующими во
всех языках программирования циклами являются циклы for, while и do-while. Мы
рассмотрим один вид – цикл перечислимого типа for. Два других вида циклов ис-
пользуются для более сложных общих задач и для простого примера не годятся.
Рассмотрим новый пример:
#include <stdio.h>
int main(void)
{
int i;
for (i=0; i<10; i++)
{
printf("i = %d\n",i);
}
return 0;
}
Здесь главную роль играет оператор цикла for. Структура записи в стиле язы-
ка Си может показаться непонятной и запутанной, но на самом деле, если подойти
к этому оператору с простой точки зрения, то данная программа делает следующее:
она печатает на экране столбец значений переменной i от 0 до 9. Начальное значе-
ние переменной задается командой
i=0
условие работы цикла командой
i<10
а шаг цикла – изменение переменной i на единицу – командой
i++
Переменная i в цикле for называется, обычно, итерационной переменной – от
английского iteration. Это общепринятое и очень популярное название для пере-
менной, которая «считает» шаги цикла. Довольно интересной в данном примере
является команда i++ – это специальная команда языка Си – она существенно
ускоряет работу программы, но, к сожалению, в других языках программирования
такие команды встречаются редко. Единственное действие, которое выполняется в
этом цикле – печать на экран сообщений со значением итерационной переменной.
Вот и получается такой результат:
i = 0
47
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
Нумерация начинается с нуля по традиции, а также из-за специфического
устройства массивов в языке Си – нумерация элементов массива в языке Си начи-
нается с нуля.
К сожалению, обсудить все особенности языка Си невозможно в этом ма-
леньком приложении – это один из самых элегантных, компактных и быстрых язы-
ков программирования. Изучать его нужно не столько для изучения языка, сколько
для понимания того, как устроены практически все современные языки програм-
мирования «изнутри».
Приложение 2.
Основные команды языка SQL, создание запросов
SQL – это специализированный язык запросов. Наиболее распространенное
заблуждение – что SQL это язык программирования. На самом деле, это язык, ко-
торый дает Вам возможность создавать и работать в базах данных, являющихся
наборами связанной информации, сохраняемой в таблицах. Присутствует во всех
системах управления базами данных и нужен для обеспечения надежного и просто-
го доступа к данным.
Удобство, простота и независимость от специфики компьютерных техноло-
гий, а также его поддержка лидерами промышленности в области технологии реля-
ционных баз данных, сделало SQL (и, вероятно, в течение обозримого будущего
оставит его) основным стандартным языком для работы с БД.
Стандарт SQL определяется ANSI и в данное время также принимается ISO.
Однако большинство коммерческих программ баз данных расширяют SQL без уве-
домления ANSI, добавляя различные особенности в этот язык, которые, как они
считают, будут весьма полезны. Иногда они несколько нарушают стандарт языка,
хотя хорошие идеи имеют тенденцию развиваться и вскоре становиться стандарта-
ми «рынка» сами по себе в силу полезности своих качеств. Чаще всего такие изме-
нения происходят в сложных информационных системах. Классические примеры –
Transact SQL и PL/SQL, используемые компаниями Microsoft и ORACLE соответ-
ственно.
В данном приложении мы не будем рассматривать все команды языка. Мы
рассмотрим список основных команд языка для работы с данными и основную ко-
манду – команду выбора. Таких основных команд всего четыре:
48
SELECT – выбрать
INSERT – вставить
UPDATE – обновить
DELETE – удалить
Наиболее важной командой языка манипулирования данными является ко-
манда SELECT. Самое главное в изучении этой команды – научиться ее использо-
вать. Синтаксис команд SQL очень простой – это будет понятно из тех примеров,
что мы рассмотрим.
1. SELECT * FROM Table1 – выбор всех данных из базы, по всем полям.
2. SELECT name, surname FROM Table1 – выбор всех имен и фамилий из ба-
зы, в результате него формируется ответ в котором идут сначала имя, по-
том фамилия.
3. SELECT * FROM Table1 WHERE surname=’Иванов’ – выбирает из базы все
данные по людям с фамилией Иванов.
4. SELECT * FROM Table1 ORDER BY surname – выбор всей информации из
базы, упорядоченной по алфавиту, по полю фамилий.
Как видите, запросы устроены крайне просто. Фактически, работает правило
«как пишется, так и читается» – главное в этих запросах не сама структура коман-
ды, а умение их писать. Поэтому изучение языка SQL, в основном, сводится к изу-
чению и умению создавать различные запросы, что выливается в отсутствие специ-
ализированных курсов по этому языку. Его изучение всегда привязывают к кон-
кретному программному обеспечению и решаемым задачам.
Приложение 3.
Перевод чисел в разных системах счисления.
Для перевода чисел из десятичной системы счисления в двоичную использу-
ют так называемый алгоритм замещения, состоящий из следующей последователь-
ности действий:
1. Делим десятичное число на 2. Частное запоминаем для следующего
шага, а остаток записываем, как младший бит двоичного числа.
2. Если частное не равно 0, принимаем его за новое делимое и повторя-
ем процедуру, описанную в шаге 1. Каждый новый остаток (0 или 1)
записывается в разряды двоичного числа в направлении от младшего
бита к старшему.
Алгоритм продолжается до тех пор, пока в результате выполнения шагов 1 и
2 не получится частное
и остаток = 1.
Например, требуется перевести десятичное число 247 в двоичный вид. В со-
ответствии с приведенным алгоритмом получим:
49
остаток 1 записывается в младший бит двоичного числа
остаток 1 записываем в следующий после младшего бита разряд двоичного
числа
остаток 1 записываем в старший разряд двоичного числа
остаток 0 записываем в старший разряд двоичного числа
остаток 1 записываем в старший разряд двоичного числа
остаток 1 записываем в старший разряд двоичного числа
остаток 1 записываем в старший разряд двоичного числа
остаток 1 записываем в старший разряд двоичного числа
Таким образом, искомое двоичное число равно
.
Аналогичным способом можно переводить числа в другие системы счисле-
ния. Например – во вторую по значения систему счисления для компьютера –
шестнадцатеричную:
1. Делим десятичное число на 16. Частное запоминаем для следующе-
го шага, а остаток записываем как младший бит шестнадцатеричного
числа.
2. Если частное не равно 0, принимаем его за новое делимое и повторя-
ем процедуру, описанную в шаге 1. Каждый новый остаток записывает-
ся в разряды шестнадцатеричного числа в направлении от младшего
бита к старшему.
Алгоритм продолжается до тех пор, пока в результате выполнения шагов 1 и
2 не получится частное
и остаток меньше 16.
50
Сам компьютер использует эти и другие алгоритмы для перевода чисел непо-
средственно сразу при их обработке. Таким образом, время, затрачиваемое на эти
процессы при расчете эффективности алгоритмов можно не учитывать.
Информация о работе Основы программирования и баз данных