Введение в язык Си
Язык "C" − это универсальный язык программирования, для которого характерны экономичность выражения, современный поток управления и структуры данных, богатый набор операторов. Язык "C" не является ни языком "очень высокого уровня", ни "большим" языком, и не предназначается для некоторой специальной области применения. Но отсутствие ограничений и общность языка делают его более удобным и эффективным для многих задач, чем языки, предположительно более мощные.Язык Си наряду с тем, что он позволяет освоить хороший стиль программирования, так же как более простые и менее мощные языки высокого уровня (Бейсик, Паскаль), даёт возможность программисту осуществлять непосредственный доступ к ячейкам памяти и регистрам компьютера, требуя при этом знания особенностей функционирования ЭВМ. В этом Си схож с языком низкого уровня — ассемблером. Поэтому язык Си иногда называют ассемблером высокого уровня, хотя на самом деле он представляет собой гораздо более мощное средство решения трудных задач и создания сложных программных систем.
Язык "C", первоначально предназначавшийся для написания операционной системы "UNIX" на ЭВМ DEC PDP-11, был разработан и реализован на этой системе Деннисом Ричи. Операционная система, компилятор с языка "C" и по существу все прикладные программы системы "UNIX" (включая все программное обеспечение, использованное при подготовке этой книги) написаны на "C". Коммерческие компиляторы с языка "C" существуют также на некоторых других ЭВМ, включая IBM SYSTEM/370, HONEYWELL 6000, INTERDATA 8/32. Язык "C", однако, не связан с какими-либо определенными аппаратными средствами или системами, и на нем легко писать программы, которые можно пропускать без изменений на любой ЭВМ, имеющей "C"-компилятор.Выбор С в качестве базового языка для С++ объясняется следующими его достоинствами:
– универсальность, краткость и относительно низкий уровень;
– адекватность большинству задач системного программирования;
– он идет в любой системе и на любой машине;
– полностью подходит для программной среды UNIX.
В Си существуют свои проблемы, но в языке, разрабатываемом "с нуля" они появились бы тоже, а проблемы Си, по крайней мере, хорошо известны. Более важно то, что ориентация на Си позволила использовать язык "Си с классами" как полезный (хотя и не очень удобный) инструмент в течение первых месяцев раздумий о введении в Си классов в стиле Симулы.
С++ стал использоваться шире, но по мере роста его возможностей, выходящих за пределы Си, вновь и вновь возникала проблема совместимости. Ясно, что отказавшись от части наследства Си, можно избежать некоторых проблем. Это не было сделано по следующим причинам:
– существуют миллионы строк программ на С, которые можно улучшить с помощью С++, но при условии, что полной переписи их на язык С++ не потребуется;
– существуют миллионы строк библиотечных функций и служебных программ на С, которые можно было бы использовать в С++ при условиях совместимости обоих языков на стадии связывания и их большого синтаксического сходства;
– существуют сотни тысяч программистов, знающих С; им достаточно овладеть только новыми средствами С++ и не надо изучать основ языка;
– поскольку С и С++ будут использоваться одними и теми же людьми на одних и тех же системах многие годы, различия между языками должны быть либо минимальными, либо максимальными, чтобы свести к минимуму количество ошибок и недоразумений. Описание С++ было переработано так, чтобы гарантировать, что любая допустимая в обоих языках конструкция означала в них одно и то же.
Практически все используемые в мире ключевые программные средства, в том числе компиляторы, операционные системы, СУБД, системы телекоммуникаций написаны на Си++. Не вызывает сомнений подавляющее превосходство Си++ в области встроенных систем и индустрии компьютерных игр (Doom III, StarCraft и др.). На Си++ реализованы ведущие поисковые Web-системы и крупнейшие Web-порталы: Google, Yahoo, Amazon и др. Создатель Си++ Бьерн Страустроп приводит следующие аргументы в пользу языка: «Си++ является наилучшим языком для многих приложений, где требуется системное программирование, имеются определенные ограничения по ресурсам и выдвигаются серьезные требования к производительности. Одним из примеров служит Google, другим — встроенные системы для миниатюрных устройств».
Язык Си был разработан американцем Деннисом Ритчи в исследовательском центре Computer Science Research Center of Bell Laboratories корпорации AT&T в 1972 г. Первоначальная реализация Си была выполнена на ЭВМ PDP-11 фирмы DEC для создания операционной системы UNIX. Позже он был перенесен в среду многих операционных систем, обособился и существует независимо от любой из них. Программы, написанные на языке Си, как правило, можно перенести в любую другую операционную систему или на другой компьютер либо с минимальными изменениями, либо вовсе без них.
Первое описание языка Си дал его автор Деннис Ритчи совместно с Брайном Керниганом в книге «Язык программирования Си». Однако, описание не было строгим и содержало ряд неоднозначных моментов. Разработчики трактовали язык по-разному. Фактически, долгое время стандартом языка служила его реализация в UNIX. Сейчас существуют десятки реализаций языка программирования Си. Они поддерживают разные диалекты языка.
В 1983 г. при Американском Институте Национальных Стандартов (American National Standart Institute — ANSI) был создан комитет по стандартизации языка Си. В 1989 г. был утверждён окончательный вариант стандарта. Однако на сегодняшний день большинство реализаций языка Си не поддерживают стандарт в полном объёме.
Программирование для универсальных компьютеров начиналось с программирования в машинных кодах, затем появились и начали своё развитие языки высокого уровня, затем Дейкстрой были развиты принципы структурного программирования, на смену структурному программированию пришло объектное программирование и в настоящее время активно развивается визуальное программирование.
Применение структурного программирования позволяет увеличить скорость написания программ и облегчить отладку написанной программы. В настоящее время существует два способа написания программ: снизу вверх и сверху вниз. При написании программы снизу вверх приступить к отладке программы невозможно, не написав полностью всю программу. При написании программы сверху вниз на любом этапе написания программы она может быть оттранслирована и выполнена, при этом можно отследить все алгоритмические действия программы, написанные к этому времени. Процесс написания программы не отличается от процесса создания алгоритма. Более того, эти этапы создания программы можно объединить. Выполняемое алгоритмическое действие отображается в названии подпрограммы.
Начиная с языка Симула-67, в программировании наметился новый подход, который получил название объектно-ориентированного программирования (ООП). Его руководящая идея заключается в стремлении связать данные с обрабатывающими эти данные процедурами в единое целое - объект. Характерной чертой объектов является инкапсуляция (объединение) данных и алгоритмов их обработки, в результате чего и данные, и процедуры во многом теряют самостоятельное значение. Фактически объектно-ориентированное программирование можно рассматривать как модульное программирование нового уровня, когда вместо во многом случайного, механического объединения процедур и данных акцент делается на их смысловую связь.
Всякая реальная задача при её решении разбивается на множество подзадач, имеющих логически завершенную структуру (т.е. свои исходные данные, свой результат). Каждая из подзадач программируется отдельно, возможно, разными программистами, и затем на последнем этапе все эти модули объединяются в одну программную систему. Для двух модулей можно указать следующую связь: первому модулю во время работы может потребоваться результат работы второго модуля, без которого первый не может получить собственный результат. В этом случае в первом модуле организуется так называемое обращение ко второму модулю, при котором первый передает часть своих данных в качестве исходных второму модулю и затем должен принять результат работы второго модуля. Эта передача данных – один из самых сложных механизмов связи модулей. Такое взаимодействие двух модулей приводит к тому, что объединенная программная система имеет иерархическую структуру по связям между модулями.
К основным принципам структурного программирования относятся:
1) структура создаваемой системы должна соответствовать структуре реальной решаемой задачи.
2) структура обрабатываемых в программе системных данных должна соответствовать структурам реальных данных.
3) модули, образующие программную систему должны составляться по правилам модульного программирования
а) текстовый модуль есть последовательность управляющих программных структур (присваивание, условие – if, цикл и выбор по ключу)
б) в модуле должны отсутствовать метки и оператор GOTO
в) в модуле должны активно использоваться комментарии на русском языке. (в Вasic – REM текст, в Рascal – {комментарии}) Активно – это комментировать каждую управляющую структуру. Наиболее оптимальное - использование у-10 операторов.
г) операторы, записываемые внутри управляющей структуры должны записываться с отступом в 2-3 позиции.
for-
if-
else-
while-
do-
case-
Правила записи программы на языке Си
Программа на языке Си состоит из одной или более подпрограмм, называемых функциями. Каждая функция в языке Си имеет свое имя. В любой программе одна из функций обязательно имеет имя main. Имя функции — это коллективное имя группы объявлений и операторов, заключенных в фигурные скобки. За именем функции в круглых скобках указываются параметры функции.
Пример функции
/*Первая программа на Си. */ #include <stdio.h> main() { printf("\n Здравствуй,язык Си!"); } |
Результат работы программы
Здравствуй, язык Си!
Программа перед обработкой компьютером должна быть помещена в файл на диске. Обычно этот файл имеет расширение <.c>.
Рассмотрим типичную структуру файла с программой на языке Си и правила его оформления на следующем простом примере:
/* Включить описания функций стандартного ввода-вывода */
#include <stdio.h>
/* Включить описания математических функций */
#include <math.h>
/* Другие включаемые файлы */
.
.
.
/* Собственно текст программы */
void main(void) /* заголовок главной функции */
{
float num; /* описание типов данных */
/* Исполняемые операторы -* */
num=2.345; /*Присвоим переменной num значение 2.345 */
printf("sin(%f)=%f\n", num, sin(num)); /* Вывод на экран */
}
Любой файл начинается с директив #include, вставляющих в текст программы так называемые заголовочные файлы, которые содержат описания функций, используемых в этом файле. В нашем примере это описания стандартных функций ввода-вывода <stdio.h> и математических функций <math.h>.
Далее следует заголовок главной функции программы main, операторы описания типов данных и исполняемые операторы.
При выполнении программы, созданной на языке Си, операционная система компьютера всегда передаёт управление в программу на функцию с именем main. Обычно, хотя это не обязательно, функция main стоит первой в тексте программы. Следующие за именем функции круглые скобки играют важную роль. В них указываются параметры (аргументы), которые передаются в функцию при обращении к ней. В данном случае операционная система не передаёт в функцию main никаких параметров, поэтому список аргументов в круглых скобках пустой. В фигурные скобки { } заключены описания и операторы, которые обеспечивают вывод на экран компьютера сообщения «Здравствуй, язык Си!».
В общем случае программа содержит несколько функций. Пример программы из нескольких функций:
#директивы препроцессора main() {...} function_1(...) {...} function_2 (...) {...} function_n (...) {...} |
Функция main может вызывать для выполнения любую другую функцию. Функции function_1, function_2,..., function_nмогут вызвать любую функцию, кроме функции main. Функцию main нельзя вызывать изнутри программы, она является управляющей.
Директивы #include должны всегда начинаться с новой строки, остальные же операторы программы могут иметь произвольное положение в файле вплоть до записи в одну строку. При записи не допускается разрывать слова, числа, двухсимвольные операции.
Пробелы используются для отделения слов друг от друга и для придания тексту большей выразительности и могут использоваться везде, за исключением случаев, описанных в предыдущем абзаце. Там, где допускается один пробел, можно поставить любое их количество.
В любом месте программы, там, где может стоять пробел, допускается записывать комментарии.
/* Это комментарий */
// Это тоже комментарии.
Пара символов //, отмечающих начало однострочного комментария, при выполнении программы игнорируется текст до конца строки, начиная с этих символов.
Комментарии должны помогать понять смысл выполняемых программой действий и являются обязательной ее частью. При написании комментариев следует придерживаться ряда простых истин:
– программы читаются людьми, компьютеру комментарии не нужны;
– всегда необходимы вводные комментарии, в которых указывается назначение программы, ее автор, дата написания и изменения, краткое описание алгоритма, входных и выходных данных, основных переменных и вызываемых функций;
– комментарии должны содержать дополнительную информацию, а не перефразировать программу;
– комментарии должны быть расположены так, чтобы программа не была менее наглядной;
– неправильные комментарии хуже, чем их отсутствие.
Стиль программирования, расположение операторов в строках, использование пробелов, выбор имен переменных и т.д. должны быть направлены на то, чтобы сделать программу более понятной людям, ее читающим.