Структура программы на языке С

 

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

// пример программы,

/* иллюстрирующий цепочки операций присваивания

для переменных разного типа

*/

#include <iostream>

using namespace std;

int main(void)

{

double d;

float f;

int i;

cout<<"Hello!\n";

cout<<"Enter double d, float f, int i \n";

cin>>d>>f>>i;

cout<<"double d="<<d<<endl;

cout<<"float f="<<f<<endl;

cout<<"int i="<<i<<endl;

d=f=i=1/3;

cout<<"double d="<<d<<endl;

cout<<"float f="<<f<<endl;

cout<<"int i="<<i<<endl;

i=f=d=1./3.;

cout<<"double d="<<d<<endl;

cout<<"float f="<<f<<endl;

cout<<"int i="<<i<<endl;

return 1;

}

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

// пример программы,

/* иллюстрирующий цепочки операций присваивания

для переменных разного типа

*/

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

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

После начальных комментариев в программе находится директива #include:

#include <iostream>

Она называется директивой, поскольку указывает препроцессору команду, которую необходимо выполнить – в данном случае вставить содержимое файла <iostream> в программу перед ее компиляцией. Файл <iostream> называется файлом заголовков (или заголовочным файлом), потому что обычно он появляется в начале программного файла. В действительности точнее было бы назвать <iostream> заголовком, так как согласно стандарту ANSI C++ заголовок не обязательно должен содержаться в файле. Заголовочный файл <iostream> включает определения, которые понадобятся для того, чтобы можно было использовать операторы ввода-вывода C++. Если не включить в программу содержимое <iostream>, то она не сможет скомпилироваться, поскольку в этом случае не будут определены некоторые определения, находящихся в указанном файле. Существует довольно большое количество заголовочных файлов, поставляемых с MS VS C++, которые охватывают широкий круг возможностей. Знакомство со многими из них происходит в процессе изучения средств языка.

Оператор #include – это одна из директив препроцессора. Редактор MS VS 2008 распознает их и окрашивает в голубой цвет в окне редактирования. Как уже было сказано в главе 2, директивы препроцессора – это команды, выполняемые на фазе предварительной обработки программы компилятором, которая выполняется перед тем, как исходный код будет скомпилирован в объектный код. По мере необходимости далее будут представлены и другие директивы препроцессора.

Стандартная библиотека – это широкий набор процедур, предназначенных для решения многих часто встречающихся задач, например, обработка операторов ввода-вывода и выполнение базовых математических вычислений. Поскольку существует довольно большое количество таких процедур, а наряду с ними – и других именованных сущностей, есть вероятность нечаянного использования для собственных целей имен, совпадающих с одним из имен, определенных в стандартной библиотеке. Пространство же имен (namespace) – это механизм C++, предназначенный для предотвращения таких проблем, связанных с дублированием имен, применяемых в программе для разных целей. Это происходит за счет того, что определенное множество имен, вроде имен стандартной библиотеки, ассоциируется с общим именем семейства, которое и представляет собой пространство имен.

using namespace std;

Каждое имя, определенное в коде, появляющемся внутри пространства имен, включает в себя имя этого пространства имен. Все средства стандартной библиотеки ISO / ANSI C++ определены внутри пространства имен по имени std, поэтому каждый элемент стандартной библиотеки, к которому можно обратиться в программе, имеет свое собственное имя и дополнительно наименование пространства имен – std – в качестве квалификатора. Имена cout и endl определены в стандартной библиотеке, поэтому их полные имена выглядят как std::cout и std::endl. Два двоеточия, отделяющие имя пространства имен от имени элемента, образуют операцию, называемую операцией разрешения контекста. Применение полных имен в программе делает код несколько громоздким, поэтому было бы неплохо использовать их простые имена без квалификатора – имени пространства имен std. Две строки программы, которые следуют за директивой #include <iostream>, как раз и обеспечивают упомянутую возможность.

Функция main ()

Общий вид функции main() можно представить следующим образом:

int main(void)

{

return 1;

}

Функция main() в примере состоит из заголовка int main(void) и всего остального, начиная с открывающей фигурной скобки { и до соответствующей закрывающей фигурной скобки }. Фигурные скобки заключают в себе исполняемые внутри функции операторы, которые все вместе называются телом функции.

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

Операторы программы

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

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

double d;

float f;

int i;

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

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

Хорошим тоном в программировании считается размещение только одного оператора в строке, поскольку это облегчает понимание кода (хороший тон в программировании предполагает такое кодирование, которое упрощает понимание кода и снижает вероятность ошибок). К тому же такое представление предоставляет эффективный инструмент для отслеживания логических ошибок с помощью отладчика – встроенной в среду MS VS 2008 возможности пошагового выполнения программы. Отладчик позволяет выполнять программу построчно, то есть, если в одной строке находится один оператор, то пооператорно, а если в одной строке несколько операторов, то они выполняются все сразу, что затрудняет поиск ошибок.

Следующие два оператора в рассматриваемой программе:

cout<<"Hello!\n";

cout<<"Enter double d, float f, int i \n";

представляют собой операторы стандартного потокового вывода, которые посылают указанные две текстовые константы в виде отдельных строк. Первый из них посылает слово «Hello!» отдельной строкой, в командную строку на экране. В C++ источник ввода и место назначения вывода называется потоком (stream). Имя cout специфицирует стандартный выходной поток, а операция << указывает, что все, что находится справа от него, должно быть направлено в выходной поток cout. Операция << указывает направление потока данных – от переменной или строки, находящейся справа, в направлении выходного места назначения, расположенного слева от него. Поток с именем cout в языке С ассоциирован с экраном (монитором) компьютера. Таким образом, в рассматриваемых операторах cout значения, представленные константными текстовыми строками, пересылаются в поток, идентифицированный словом cout. В итоге данные, переданные в cout, выводятся на экран в командной строке окна консольного приложения программы.

Значение имени cout и операции << определены в заголовочном файле стандартной библиотеки <iostream>, который был добавлен в код программы с помощью директивы #include в самом ее начале, cout – имя из стандартной библиотеки, а потому относится к пространству имен std. Без директивы using это имя не могло бы быть распознано компилятором, за исключением случая указания его в полной квалифицированной форме – std::cout. Поскольку cout предназначено для того, чтобы представлять стандартный выходной поток, то оно не может быть использовано для других целей, например, в качестве имени переменной. Очевидно, что использование одного и того же имени для различных элементов может стать причиной путаницы.

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

cin>>d>>f>>i;

Ввод с клавиатуры реализуется через стандартный поток cin, при этом используется операцию извлечения из потока >>. Чтобы считать с клавиатуры значениях сразу нескольких переменных, необходимо производить разделение имен этих переменных в операторе ввода также через оператор >> (как показано в примере). Операция извлечения >> указывает в каком направлении передаются данные – в данном случае, из cin в каждую из трех переменных по очереди. Любые ведущие пробелы пропускаются и первое целое значение, введенное с клавиатуры, поступает в переменную. Так происходит потому, что оператор ввода выполняется слева направо. Любые пробелы, следующие за значением переменной, игнорируются и воспринимаются как разделитель, второе введенное значение считывается и записывается в следующую переменную и т.д. Между следующими друг за другом значениями должны быть пробельные символы (консольное приложение позволяет использовать для этого пробелы, клавишу Tab и клавишу Enter), чтобы их можно было разделить. Операция потокового ввода завершается после нажатия клавиши Enter (если были введены все значения переменных) и выполнение программы продолжается со следующего оператора. При вводе значений могут возникать ошибки, если введены некорректные данные, но для корректной работы программы будем предполагать, что данные вводятся правильно.

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

Важно! Справа от оператора >> может стоять только имя переменной. Никаких выражений, констант или функций записывать в операторе cin нельзя.

cout<<"double d="<<d<<endl;

cout<<"float f="<<f<<endl;

cout<<"int i="<<i<<endl;

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

d=f=i=1/3;

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

Далее происходит вывод на экран новых значений переменных, потом новое присваивание и так далее.

Последний оператор программы выглядит следующим образом:

return 1;

Этот оператор прекращает выполнение функции main() и завершает программу. Управление возвращается операционной системе. В приведённой программе этот оператор не нужен, так как программа не предназначена для контакта с операционной системой компьютера, но хорошим тоном при программировании на языке С считается, когда любая функция имеет возвращаемое значение (если оно не требуется, то это код «хорошего» завершения программы). В данном случае return 1; – это и есть всего лишь дань хорошему тону.

Результат работы программы выглядит так, как показано на рис. 18.

 

Рис. 18. Результат работы программы

 

Задание! Попробуйте самостоятельно проанализировать значения, выведенные на экран консольного приложения в 6 последних строках (последняя строка была автоматически добавлена системой MS VS 2008, поэтому не подлежит рассмотрению и её вывод на экран не представлен в коде программы).

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

Обратим отдельное внимание на присутствие в тексте программы наравне с другими символами символов пробела. Пробел (whitespace) – термин, используемый в C++ для обозначения символов пробела, табуляции, новой строки, новой страницы и комментариев. Пробелы служат разделителями одной части оператора от другой и позволяют компилятору идентифицировать, где заканчивается один элемент оператора, например, такой как int, и начинается другой. В остальных случаях пробелы игнорируются и никакого влияния не оказывают.

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

С другой стороны, если взглянуть на следующий оператор:

i=f=d=1./3.;

то можно заметить отсутствие пробелов внутри оператора. Таким образом, пробельный символ не является обязательным, хотя при желании может быть включен в состав оператора. Дело в том, что бинарные операции = и / воспринимаются компилятором не как буквы или цифры (обычные символы), поэтому он может отделить их от окружения и без использования пробелов. Аналогично никакие пробельные символы не нужны вокруг знаков других операций, определённых в языке С, хотя они могут добавляться для улучшения читабельности кода программы.

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

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

Важно! В C++ присутствуют зарезервированные слова, которые называются ключевыми словами и имеют специальное значение внутри языка. Редактор MS VS 2008 подсвечивает их определенным цветом на этапе ввода текста программы. По умолчанию ключевые слова окрашиваются в синий цвет. Если ключевое слово, которое было введено, не окрашивается соответствующим образом, значит, оно было введено неправильно.

Необходимо помнить, что ключевые слова, как и весь язык C++, «чувствителен» к регистру (слово, начинающееся со строчной и заглавной буквы имеет разное значение). Например, приведённая выше программа содержит ключевые слова int и return. Если они же были записаны как Int или Return, то это не считалось бы ключевыми словами и компилятор не распознал бы их как таковые.