А. Нейбауэр. Моя первая программа на C/C++.

ГЛАВА 1

ОСНОВЫ ПРОГРАММИРОВАНИЯ

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

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

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

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

Компьютерная программа

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

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

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

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

А теперь давайте немного подробнее рассмотрим наше определение программы.

Как дать компьютеру инструкции о том, что точно он должен сделать? Ключевым здесь является слово точно: каждая инструкция должна быть точной, нельзя пропустить ни одного шага. Возьмем жизненную ситуацию. Когда прохожий спрашивает у вас дорогу к местному почтовому отделению, вы ему отвечаете: «Пройдите два квартала, а затем поверните налево по Франклин-стрит». Говоря так, вы не сомневаетесь, что он увидит здание почты и зайдет туда.

Замечания по Си++

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

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

пройти два квартала на север;
повернуть налево на 90 градусов;
пройти 50 футов прямо;
повернуть налево на 90 градусов;
подняться на четыре ступеньки;
открыть дверь и войти.

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

* Точнее, не сам компьютер, а программа-транслятор с языка, на котором составлен исходный текст, в данном случае— компилятор Си или Си++. (Прим.ред.)

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

Инструкции необходимо задавать в правильном порядке. Когда вы даете компьютеру инструкцию выполнить процедуру A, B, а затем C, то именно в таком порядке он их и выполнит. Компьютер не может подумать «Стоп-стоп! Мне кажется, что тут какая-то ошибка, может мне стоит все-таки сперва повернуть на Франклин-стрит?» Разумеется, компьютер можно заставить принимать решения. Составленная нами программа может решать: «Если зарплата работника больше 50 тысяч долларов, то берем 25% налога, а если меньше, то только 15%», но происходить это будет только в том случае, если мы заранее дадим компьютеру инструкции, когда принимать решение и какой именно вариант допускается выбрать в каждом конкретном случае.


Рис. 1.1. Микропроцессор управляет всем, что происходит в компьютере

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

Языки программирования

Третье требование к программе— это язык, который понятен компьютеру.

Глубоко в недрах компьютера находится микропроцессор. Микропроцессор— это интегральная микросхема, которая управляет всем, что происходит в компьютере (рис.1.1).

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

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

Электрические сигналы, с которыми имеет дело компьютер, могут иметь только два состояния (в зависимости от уровня напряжения): высокий уровень напряжения— электрический сигнал есть (состояние «включен») либо низкий уровень— электрический сигнал отсутствует (состояние «выключен»). Для того чтобы выполнить любую задачу, мы задаем микропроцессору последовательность сигналов в состоянии «включен» или «выключен». На рис.1.2 для примера приведена последовательность состояний электрических сигналов, необходимая для того, чтобы напечатать символ «А»*.

Для того чтобы задавать инструкции компьютеру на самом низком уровне, используется цифра 0, означающая состояние «выключен», и цифра 1,

* Здесь и далее на рисунках приведены не конкретные последовательности машинных команд, а лишь дано общее представление о них. (Прим.ред.)



Рис. 1.2. Ряд последовательных сигналов «включен» или «выключен»говорит микропроцессору, что ему делать, в данном случае—взять символ из памяти и послать на принтер

означающая состояние «включен». Мы называем это двоичными цифрами (битами)* или двоичными кодами, так как они основаны на двоичной системе счисления, в которой, как известно, все числа представлены только при помощи комбинаций нулей и единиц.

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

* От английского binary digit, bit. (Прим.перев.)




Рис. 1.3. Транслятор с языка ассемблера преобразует инструкциив двоичные коды

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

Ассемблер представляет задачу, адресованную непосредственно микропроцессору, используя мнемонические коды. Мнемонические коды— это несложные для запоминания слова или аббревиатуры, представляющие завершенное задание для микропроцессора. Например, код MOV указывает компьютеру на то, что некую информацию следует переместить из одной области памяти в другую, а код JMP указывает, что необходимо перейти в другую область памяти. Таким образом, вместо того, чтобы составлять последовательные ряды 0 и 1, программист на ассемблере может использовать мнемонические коды, подобные приведенным выше, каждый из которых представляет собой восемь или более бит.

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


Рис. 1.4. Сравнение языка Си, ассемблера и двоичных кодов

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

В настоящее время большинство программистов работают с языками высокого уровня, где инструкции задают с помощью человеческих слов, а не мнемонических кодов или 0 и 1. Каждое слово представляет практически завершенную операцию, а не одно задание для микропроцессора. Например, функция языка Си puts()* указывает компьютеру, что некая информация должна быть выведена на дисплей. Для выполнения этой же функции может потребоваться использование большого количества мнемонических кодов ассемблера и сотен бит.

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

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

* От английского put string. (Прим.перев.)

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

Компиляторы

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

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

Рис. 1.5 иллюстрирует принцип действия компилятора. В сущности, компилятор— это компьютерная программа, которая (с помощью другой программы, называемой компоновщиком) преобразует все ваши инструкции в двоичные коды таким образом, чтобы программа могла быть выполнена компьютером.


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

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

Замечания по Си++

Вскоре вы сможете убедиться, что Си++ является надмножеством языка Си. Это означает, что программу, которая компилируется транслятором Си, можно обрабатывать и компилятором Си++.

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

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

Расширения имен файлов

При работе большинство компиляторов языка Си требуют, чтобы исходный файл с текстом программы имел расширение .C, и присваивают объектному файлу расширение .OBJ, или иногда .О.

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

Си, Си++, Паскаль, Кобол и Фортран— это примеры компилирующих языков.

Интерпретатор

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

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


Рис. 1.6. Интерпретатор преобразует инструкции языка высокого уровняв двоичные коды во время каждого запуска программы

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

Компьютерный интерпретатор работает сходным образом. Из рис.1.6 видно, что он переводит каждую инструкцию и сразу выполняет ее. Программа, обрабатываемая интерпретатором, существует только в виде исходного текстового файла. Язык BASIC, который поставляется с операционной системой MS-DOS, является примером интерпретирующего языка.

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

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

Замечания по Си++

Запомните, все что говорится в этой книге относится как к Си, так и к Си++. Вместо того чтобы постоянно ссылаться на оба языка Си/Си++, мы часто будем упоминать только Си. Это не значит, что вы изучаете только Си, вы изучаете оба языка одновременно.

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

Почему Си/Си++?

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

Скорость

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

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

Переносимость

Разумеется, можно создавать очень быстро работающие программы, если писать их на ассемблере. Однако мнемонические ассемблерные коды не одинаковы для каждого семейства микропроцессоров. Если бы вы написали на ассемблере программу для IBM PC или совместимого с ним компьютера, а затем решили выполнить те же самые процедуры на Apple Macintosh, вам пришлось бы переписать всю программу.

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

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

Структурирование

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

Библиотеки функций

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

* Использование автором термина «команда» в качестве синонима термина «ключевое слово» не является традиционным. (Прим.перев.)



Рис. 1.7. Инструкции, обеспечивающие выполнение функцииберутся из библиотеки в процессе компоновки программы

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

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

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

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


Рис. 1.8. Процесс компиляции/компоновки

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

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

Рис. 1.8 кратко иллюстрирует процесс компиляции/компоновки.

Файлы заголовков, в отличие от библиотечных файлов, не откомпилированы. Так же как и ваш исходный файл с текстом программы на Си, их можно читать, печатать на принтере и редактировать. Однако вам следует остерегаться вносить изменения в файлы заголовков, поставляемые с компилятором. Если вы сделаете ошибку, то компилятор больше не сможет генерировать для них объектные коды.

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

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

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

Необходимые пояснения

Язык Си был разработан Деннисом М. Ритчи в 1972 году и подробно описан в книге Ритчи и Брайана В. Кернигана «Язык программирования Си». Реализация Си в соответствии с правилами, изложенными в книге, рассматривается как K&R стандарт Си (по именам Кернигана и Ритчи). K&R-Си является, по-видимому, минимальной стандартной реализацией, так что любая программа, написанная с использованием правил K&R-Си, будет успешно транслироваться любым компилятором Си.

Во многих отношениях, однако, стандарт не был исчерпывающе определен, так что разработчики компиляторов стали усовершенствовать и развивать язык, каждый по-своему. Чтобы избежать путаницы, Американский Институт Национальных Стандартов* в 1983 году разработал новый стандарт, названный

* American National Standards Institute. (Прим.перев.)

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

Язык программирования, известный как Си++— это надмножество языка Си. Реально он не является новым языком, так как включает все операторы и средства языка Си, добавив только некоторые новые. Изучая Си, вы по большей части одновременно изучаете и язык Си++. Преимущество Си++ в том, что он позволяет с большей легкостью разрабатывать большие сложные программы за счет более модульного подхода и некоторых других усовершенствований. Кроме того, Си++ является языком объектно-ориентированного программирования.

Что такое объектно-ориентированное программирование

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

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

Карточка члена клуба
	Имя
	Адрес
	Телефон
	Статус

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

	Взять карточки
	Найти карточку Смита
	Изменить адрес на Западная Авеню, 12

Взять карточки Найти карточку Доу Изменить телефон на 555-1234
Взять карточки Найти карточку Джонса Изменить статус на «выбыл»

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

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

	Клубная Карточка
		Имя
		Адрес
		Телефон
		Статус
		Изменить адрес
		Изменить телефон
		Изменить статус

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

Клубная карточка: Изменить адрес (Смит, Западная Авеню, 12)
Клубная карточка: Изменить телефон (Доу, 555-1234)
Клубная карточка: Изменить статус (Джонс, выбыл)*

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

Что Си может и чего не может

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

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

* В оригинале:
Member_cards.change_address(Smiths, 12 West Avenue)
Member_cards.change_phone(Doe, 555-1234)
Member_cards.change_status(Jones, inactive)
что практически выглядит как инструкция Си++. (Прим.перев.)

Этапы программирования

Разработка программы— это логический процесс. Если вы не пожалеете времени и проследите как осуществляется этот процесс с начала и до конца, то сможете успешно программировать на Си. Давайте рассмотрим последовательность этапов создания программы.

План программы

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

Для примера, предположим, вы хотите написать программу расчета налога на продажи. Что она должна делать?

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

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

Теперь рассмотрим вывод. Результат вычислений должен быть выведен на экран.

Итак, последовательные этапы программы таковы:
ВВОД Указать пользователю, что он должен ввести сумму продаж.
  Показатель вводится с клавиатуры.
Указать компьютеру величину налога на продажи, взимаемого в вашем штате.
ОБРАБОТКАУмножить сумму продаж на ставку налога.
ВЫВОДОтобразить результат на экране монитора.

Текст программы

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

Компиляция программы

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

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

Компоновка программы

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

Тестирование программы

Итак, теперь можно запускать программу. Если все было сделано правильно, программа будет выполняться без проблем. Но могут иметь место ошибки двух типов: ошибки выполнения и логические ошибки.

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

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

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

Рассмотрим снова программу расчета величины налога на продажи. Положим, вы сделали ошибку и указали, что величину объема продаж надо не умножить на ставку налога, а разделить. У компилятора и компоновщика нет возможности узнать, что вы сглупили, так что процесс компиляции и компоновки, по-видимому, пройдет благополучно. Но, к несчастью, запустив программу, вы обнаружите, что величина 6% налога для 100 долларов составила 1666.66 доллара! Ксожалению, многие логические ошибки не столь очевидны, и отыскать их крайне сложно.

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

Изучение основ программирования

Осваивая программирование, вы приобретаете два важных навыка.

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

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

Чтобы создавать компьютерные программы, необходимы оба эти навыка. К счастью, вы изучаете их оба одновременно.

Что нужно, чтобы писать программы

Чтобы написать программу на Си или Си++, необходимы редактор, компилятор и компоновщик.

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

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

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

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

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

Си/Си++ и ваше будущее

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

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

Вопросы

  1. В чем состоит различие между компилятором и интерпретатором?
  2. Различаются ли между собой компиляторы языка Си?
  3. В чем отличие языка ассемблера от языков высокого уровня?
  4. Что такое исходный файл с текстом программы?
  5. В чем различие ошибок компиляции и ошибок выполнения?
  6. В чем преимущества языка Си? Объясните.
  7. Какова последовательность этапов создания программы?

Упражнения

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

** Все приведенные в книге примеры могут быть собраны с помощью любого компилятора, поддерживающего стандарт ANSI Си. В том числе, с помощью широко распространенных в нашей стране компиляторов фирмы Borland, начиная с версии Borland C 1.0 и выше. (Прим.перев.)

Содержание | Верх страницы | Далее=>