Какую функцию должны содержать все программы на с
В данной главе определяются термины, которые позднее используются в данном Руководстве при описании языка С, и рассматривается структура исходного текста программы на языке С. Дается обзор некоторых характеристик языка С, которые находят свое подробное описание в других главах. В главах «Объявления» и «Функции» рассматривается синтаксис и значение объявлений и определений. Предпроцессор С и прагмы рассмотрены в разделе «Директивы предпроцессора и прагмы».
Исходная программа С это набор любого числа директив, прагм, объявлений, определений и операторов. Все эти конструкции кратко рассматриваются в последующих разделах. Чтобы эти конструкции имели смысл, они все должны иметь синтаксис, соответствующий приведенному в данном руководстве, хотя и могут следовать в программе в любом порядке (в соответствии со сформулированными в данном Руководстве правилами). Однако, порядок их появления влияет на использование переменных и функций в программе. (Дополнительная информация по данному вопросу содержится в разделе «Время и сфера действия».)
«Директива» содержит инструкции для предпроцессора С по выполнению некоторых действий над текстом программы до его компиляции.
«Прагма» дает задание компилятору выполнить конкретные действия во время компиляции.
Объявления и определения
«Объявление» устанавливает связь между именем и атрибутами переменной, функции и типом. В С все переменные должны быть объявлены до своего использования. «Определение» переменной устанавливает те же связи, что и объявление, но кроме этого переменной выделяется память. Т.о. все определения являются объявлениями, но не все объявления являются определениями. Например, объявление переменной, которое начинается со спецификатора класса хранения extern является скорее «ссылочным» объявлением, чем «определяющим». Ссылочные объявления не вызывают выделение памяти и не могут быть инициализированы. (Дополнительная информация по классам хранения содержится в главе «Объявления».)
«Объявления функций» (или «прототипы») устанавливают имя функции, ее возвращаемый тип и, возможно, ее формальные параметры. В определении функции присутствуют те же элементы, что и в ее прототипе, плюс тело функции. Если не сделать четкого объявления функции, то компилятор сам построит ее прототип на основании всей имеющейся информации при первой ссылке на функцию, является ли это ее определением или вызовом.
Объявления функций и переменных могут появляться как внутри так и вне определения функции. Любое объявление внутри определения функции считается «внутренним» (локальным). Объявление вне всех определений функций считается «внешним» (глобальным).
Определения переменных, как и их объявления, могут происходить как на внутреннем, так и на внешнем уровне. Определения функций всегда происходят на внешнем уровне.
Обратите внимание на то, что объявления типов (например, структур, об’единений и объявления typedef), которые не включают имена переменных объявленного типа, не вызывают выделения памяти.
В следующем примере показан исходный текст простой программы на С. В исходной программе определяется функция main и объявляется функция printf с прототипом. Программа использует определяющие объявления для инициализации глобальных переменных x и y. Локальные переменные z и w объявляются, но не инициализируются. Память выделяется для всех этих переменных, но только x, y, u и v имеют содержательные значения, т.к. они были инициализированы явно или неявно. Значения z и w не имеют смысла до тех пор, пока им не присваиваются значения в выполняемых операторах.
Исходную программу можно разделить на один или несколько «исходных файлов». (Например, исходный файл может содержать лишь несколько нужных программе функций.) При компилировании программы для получения общего текста нужно отдельно скомпилировать, а затем скомпоновать ее исходные файлы. Кроме того, можно использовать директиву #include для комбинирования нескольких исходных файлов в большой исходный файл до компиляции. (Информация по «включению» файлов содержится в главе «Директивы предпроцессора и прагмы».)
Исходный файл может содержать любую комбинацию полного набора директив, прагм, объявлений и определений. Нельзя разделять элементы (например, определения функций и большие структуры данных) между разными исходными файлами. Последним символом исходного файла должен быть символ новой строки.
Исходный файл не обязательно должен содержать выполняемые операторы. Например, иногда бывает полезно поместить определения переменных в один исходный файл, а их объявления — в другой файл, где они используются. Этот метод позволяет легко находить определения и вносить в них изменения. По аналогичной причине объявления констант и макросов также часто помещают в отдельные файлы, на которые при необходимости можно легко организовать ссылку.
Директивы исходного файла применяются только к этому файлу и включенным в него файлам. Более того, директива применяется только к той части файла, которая за ней следует.
Прагмы обычно воздействуют на указанную часть исходного файла. Реализация определяет заданные в прагме действия компилятора. (Руководство по компилятору подробно описывает эффект применения конкретных прагм.)
В следующем примере показана исходная программа С, состоящая из двух исходных файлов. После компиляции этих исходных файлов их можно скомпоновать и использовать, как одну программу.
Предполагается, что функции main и max находятся в разных файлах, и выполнение программы начинается с main.
Строки, которые начинаются с символа номера (#) являются директивами предпроцессора. Эти директивы информируют предпроцессор о том, что во всем исходном файле 1 нужно заменить идентификаторы ONE, TWO и THREE на указанные цифры. Однако, эти директивы никак не относятся к исходному файлу 2 (см. ниже), который будет скомпилирован отдельно и затем скомпонован с исходным файлом 1.
Каждая программа на С должна иметь главную функцию, которая должна иметь имя main. Функция main является стартовой точкой выполнения программы. Она обычно управляет выполнением программы, вызывая в нужный момент другие функции. Программа обычно заканчивает свое выполнение в конце функции main, хотя ее выполнение может быть прервано и в других точках программы в зависимости от условий ее выполнения.
Исходная программа обычно состоит из нескольких функций, каждая из которых выполняет одну или несколько конкретных задач. Функция main может вызывать эти функции для выполнения соответствующих им задач. Когда main вызывает другую функцию, она передает выполнение этой функции и ее выполнение начинается с выполнения первого оператора функции. Функция возвращает управление после выполнение оператора return или после достижения конца функции.
Можно объявить любую функцию, включая main, с параметрами. Когда одна функция вызывает другую, вызванная функция принимает значения своих параметров от вызвавшей ее функции. Эти значения называются «аргументами». Можно объявить формальные параметры в main так, что они могут принимать значения из внешней среды программы. (Чаще всего эти аргументы передаются из командной строки при выполнении программы.)
Традиционно первые три параметры функции main объявляются с именами argc, argv и envp. Параметр argc объявляется для хранения общего числа передаваемых в main аргументов. Параметр argv объявляется как массив указателей, каждый элемент которого указывает на строковое представление переданного в main аргумента. Параметр envp это указатель на таблицу строковых значений, которая устанавливает среду выполнения программы.
Операционная система присваивает значения параметрам argc, argv и envp, а пользователь вводит действительные аргументы в main. Операционная система, а не язык С, определяет преобразование при передаче аргументов в конкретной системе. Дополнительная информация по данному вопросу содержится в руководстве по компилятору.
При объявлении формальных параметров функции они должны быть объявлены при определении функции. Объявление и определение функций подробно рассмотрено в главах «Объявления» и «Функции».
Для того, чтобы понять, как работает программа на С, нужно сначала понять правила, которые определяют использование переменных и функций в программе. Для осознания этих правил важно понять три основные концепции: «блок», «время действия» и «сфера действия».
Блоки
Блок это последовательность объявлений, определений и операторов, которая заключена в скобки. В языке С есть два типа блоков. «Составной оператор» (более подробно рассмотренный в главе «Операторы») это один тип блока. Другой тип блока это «определение функции», которое состоит из тела функции и связанного с ней «заголовка» (имя функции, возвращаемый тип и формальные параметры). Блок может содержать в себе другие блоки за тем исключением, что блок не может содержать определения функции. О блоках внутри других блоков говорят, что они «вложены» в них.
Заметим, что хотя все составные операторы заключаются в скобки, не все заключенное в скобки есть составной оператор. Например, хотя спецификации массивов, структур и перечислимых элементов могут быть заключены в скобки, они не рассматриваются в качестве составного оператора.
Время действия
«Время действия» это период выполнения программы, в котором существует переменная или функция. Все функции программы существуют на всем протяжении выполнения программы.
Время действия переменной может быть внутренним (локальным) или внешним (глобальным). Элемент с локальным временем действия («локальный элемент») хранит и определяет значение только в блоке, в котором он был определен или объявлен. Локальному элементу всегда выделяется новое место в памяти каждый раз, когда программа входит в блок, и хранимая величина теряется, когда программа выходит из блока. Если время действия переменной глобально (глобальный элемент), то он хранит и определяет значение на всем протяжении выполнения программы.
Следующие правила определяют, имеет переменная глобальное или локальное время действия:
— Переменные, которые объявлены на внутреннем уровне (в блоке) обычно имеют локальное время действия. Можно задать для переменной в блоке глобальное время действия, если указать в ее объявлении спецификатор класса хранения static. После объявления static переменная будет хранить в себе значение от одного вызова блока до другого. Однако, к ней можно будет обратиться только в данном блоке или из вложенных в него блоков. (Доступ к элементам рассматривается в следующем разделе. Информацию о спецификаторах класса хранения можно найти в главе «Объявления».)
— Переменные, которые объявлены на внешнем уровне (вне всех блоков программы) всегда имеют глобальное время действия.
Сфера действия
«Сфера действия» элемента определяет ту часть программы, в которой на него можно сослаться по имени. Элемент доступен только в своей сфере действия, которая может быть ограничена (в порядке усиления ограничений) файлом, функцией, блоком или прототипом функции, в котором она появляется.
В С только имя метки всегда имеет сферой своего действия функцию. (Дополнительная информация по меткам и их именам содержится в главе «Операторы».) Сфера действия любого другого элемента определяется уровнем, на котором производится его объявление. Объявленный на внешнем уровне элемент имеет сферой своего действия весь файл и доступен из любого места файла. Если его объявление происходит в блоке (включая список формальных параметров в определении функции), то сфера действия элемента ограничивается данным блоком и вложенными в него блоками. Имена формальных параметров в списке параметров прототипа функции имеют сферу действия только от объявления параметра до конца объявления функции.
Хотя элемент с глобальным временем действия и «существует» на всем протяжении выполнения исходной программы (например, внешне объявленная переменная или локальная переменная, объявленная с ключевым словом static), он может и не быть доступен из всех частей программы.
Про элемент говорят, что он «глобально доступен», если он доступен или можно сделать соответствующее объявление для доступа к нему, из всех исходных файлов, составляющих программу. (Дополнительная информация по организации доступа между исходными файлами, известной как «компоновка», содержится в главе «Объявления».)
- Переменные, которые были объявлены или определены на глобальном уровне (т.е. вне всех блоков программы) доступны от точки их объявления или определения до конца исходного файла. Можно использовать соответствующие объявления для того, чтобы эти переменные стали доступны и из других исходных файлов, как это описано в «Классах хранения». Однако, объявленные на глобальном уровне переменные со спецификатором класса хранения static доступны только в том исходном классе, в котором они были определены.
- В общем случае, переменные, которые объявлены или определены на локальном уровне (т.е. внутри блока) доступны всем вложенным блокам. Однако, в этом случае говорят о «вложенности» доступа. Например, блок, который вложен в другой блок, может содержать объявления переменных, идентификаторы (имена) которых могут совпадать с переменными внешнего блока. Такие переопределения доминируют только во внутреннем блоке. После выхода из внутреннего блока будет восстановлено определение внешнего блока.
- Функции с классом хранения static доступны только в том исходном файле, где они были определены. Все другие функции доступны глобально. (Дополнительная информация по объявлениям функций содержится в разделе «Определения функций и Прототипы».)
Краткий обзор
В Таблице 3.1 суммируются основные факторы, определяющие время и сферу действия переменных и функций. Однако, эта таблица не учитывает всех возможных вариантов. Дополнительная информация содержится в Главе «Объявления».
Следующий пример программы иллюстрирует блоки, вложение и доступ к переменным. В примере есть четыре уровня доступа: внешний и три уровня блоков. Предположим, что функция printf определена в каком-либо другом месте программы. Значения будут выводиться на экран так, как это показано в предшествующем каждому оператору комментарии.
В программе на языке С идентификаторы используются для ссылки на многие виды различных объектов. При написании программы на С идентификаторы используются для функций, переменных, формальных параметров, компонентов об’единений и других используемых в программе объектов. С позволяет использовать один идентификатор для нескольких элементов программы, если придерживаться правил, изложенных в этом разделе. (Определение идентификатора содержится в Главе «Элементы С».)
Компилятор устанавливает «классы» для того, чтобы различать идентификаторы, использованные для различных видов элементов. Чтобы не возникало конфликта, имя каждого класса должно быть уникальным, но в нескольких классах может быть использовано идентичное имя. Это значит, что можно использовать идентификатор для нескольких разных объектов, если эти объекты располагаются в разных классах. Компилятор может идентифицировать ссылку исходя из контекста использования идентификатора в программе. Следующий список описывает виды элементов, которым можно присваивать имена в программе на С и привила по присваиванию имен:
Три элемента с именем student в следующем примере не конфликтуют, т.к. признаки структур, компоненты структур и имена переменных находятся в трех разных классах. Контекст использования каждого элемента позволяет корректно интерпретировать каждое появление student в программе.
Например, когда student появляется после ключевого слова struct, компилятор распознает, что это признак структуры. Когда student появляется после оператора выбора компоненты (-> или .), это имя относится к компоненте структуры. В другом случае student относится к структурной переменной.
Функция main и выполнение программ
Все программы, написанные на языке C, содержат основную функцию, которая должна иметь имя main. Если код соответствует модели программирования Юникода, можно использовать версию функции main для многобайтовых символов с именем wmain. Функция main является начальной точкой для выполнения программы. Она обычно управляет выполнением программы, вызывая другие ее функции. Как правило, выполнение программы завершается в конце функции main, но по разным причинам это может случиться и в других местах программы. Иногда (возможно, при обнаружении некоторой ошибки) может потребоваться принудительно завершить программу. Для этого используйте функцию exit. Сведения о функции exit и пример ее использования см. в Справочнике по библиотеке времени выполнения.
Синтаксис
Примечания
Функции в исходном коде программы выполняют одну или несколько конкретных задач. Функция main может вызывать эти функции для выполнения соответствующих задач. Когда функция main вызывает другую функцию, она передает ей управление выполнением, и работа программы продолжается с первого оператора вызываемой функции. Вызываемая функция возвращает управление функции main, когда выполняется оператор return или достигается конец этой функции.
Для любой функции, включая функцию main, можно объявить наличие параметров. Термин «параметр» или «формальный параметр» относится к идентификатору, получающему значение, передаваемое функции. Сведения о передаче аргументов в качестве параметров вы найдете в статье Параметры. Когда одна функция вызывает другую, вызываемая функция получает значения своих параметров от вызывающей функции. Эти значения называются аргументами. Для функции main можно объявить формальные параметры, и тогда она будет принимать аргументы из командной строки в следующем формате:
Если в функцию main передаются параметры, они традиционно именуются argc и argv , хотя компилятор C не обязывает использовать именно эти имена. Типы для параметров argc и argv определяются языком C. Если в функцию main передается третий параметр, он по традиции называется envp . В приведенных ниже в данном разделе примерах описывается использование этих трех параметров для доступа к аргументам командной строки. Эти параметры объясняются в следующих разделах.
Описание версии main для расширенных символов см. в статье Использование wmain.
Структура программ на языке Си
Все программы, написанные на языке Си, имеют общую структуру. О которой мы и поговорим в этом уроке. В этом нам поможет наша первая программа, написанная на предыдущем шаге.
Будем заполнять простую карту. На данный момент мы знаем, что существуют программы, но как они устроены внутри нам неизвестно. Поэтому наша карта будет иметь следующий вид.

Рис.1 Карта «Структура программ на языке Си.» Начальный уровень.
На протяжении всего курса мы к этой карте будем возвращаться, уточнять её, дополнять новыми элементами и блоками.
Сейчас внимание. Не пугайтесь! Ниже написан исходный код трёх простеньких программ. Ваша задача внимательно на них посмотреть и попытаться найти в их коде какую-то закономерность (нечто общее, что есть в каждой программе).
Листинг 1. Программа 1. Печатает «Hello, World!»
Листинг 2. Программа 2
Листинг 3. Программа 3
Не торопитесь смотреть продолжение урока и правильный ответ на эту задачу. Для начала попробуйте ответить самостоятельно. После этого нажмите кнопку «Смотреть продолжение!»
Итак, ответ: Во всех программах выше присутствует следующая конструкция:
Листинг 4. Главная функция любой программы на языке Си — функция main.
Что же это за конструкция. Это объявление функции main. Такая функция обязательно есть в каждой программе, которая написана на языке Си.Большая программа или маленькая, компьютерная игра или программа «Hello, World!», написана вами или Биллом Гейтсом — если программа написана на языке Си — в ней есть функция main. Это так сказать главная функция нашей программы. Когда мы запускаем программу, то можно думать, что запускаем функцию main этой программы.
Остановимся на секундочку. Мы, кажется, уже кое-что выяснили о структуре программ на языке Си. Любая программа на языке Си должна содержать функцию main. Отобразим этот факт на нашей карте знаний «Структура программ на языке Си.»

Рис.2 Карта «Структура программ на языке Си.» Функция main.
Теперь карта не напрягает нас своей зияющей пустотой. Продолжим наши исследования.
Давайте я расскажу немного о функции main и о функциях вообще.
Перед именем функции написано int, это сокращение от слова integer, которое переводится с английского, как «целое». Подобная запись означает, что когда функция main завершит свою работу, она должна вернуть вызывающей программе (в нашем случае это операционная система) какое-нибудь целое число. Обычно, для функции main это число ноль, которое оповещает операционную систему: «Мол, всё хорошо. Происшествий не случилось.»
Случалось ли вам видеть сообщения об ошибках на экране своего компьютера? Обычно там пишут что-то вроде «Программа аварийно завершена . бла-бла-бла. Код -314.» Вот это примерно тоже самое. Разница в том, что когда случаются проблемы операционная система нас об этом оповещает, а когда всё хорошо она нас лишний раз не беспокоит.
После имени функции в скобках записано слово void. Вообще в скобках обычно записывают аргументы функции, но в нашем случае, когда в скобках пишут void, это означает, что аргументов у функции нет. Другими словами, чтобы функция main начала работу ей не нужны никакие дополнительные данные извне. Мы ещё поговорим обо всём этом подробно, а пока просто запомним, что слово void вместо аргументов функции обозначает, что для данной функции никаких аргументов не требуется.
Внутри фигурных скобок идёт описание функции main, т.е. непосредственно то, что эта функция должна делать.
Перед закрывающей фигурной скобкой мы видим команду return. Именно эта команда и отвечает за то, чтобы вернуть значение из функции. Т.е. смотрите, если программа дошла до этого места, то значит всё было хорошо и никаких ошибок не возникло, а значит можно вернуть значение нуль.
Вы можете спросить, а почему именно нуль? А чёрт его знает! Просто так обычно делают. Можно, в принципе, возвращать какое-нибудь другое целое число, например 100, или -236. Лишь бы оно было целым числом. Помните про int? Поэтому и целое.
Вот мы и разобрались с функцией main. Ещё один момент. То что записано в фигурных скобках обычно называют «тело функции» (или описание функции), а первую часть, та что перед фигурными скобками называется заголовок функции.
Вернёмся теперь к нашей первой программе «Hello, World» и посмотрим, что там к чему.
Листинг 5. Программа «Hello, World»
Кое-что нам теперь уже понятно в этой программе. Не ясными остаются только две строки, пойдём по порядку.
Листинг 6. Директива include
Данная строчка это сообщение компилятору. Такие сообщения, начинающиеся с символа #, называются директивами компилятора. Буквально: «подключи файл stdio.h». Во время компиляции вместо этой строчки вставится содержимое файла stdio.h. Теперь немного поговорим об этом файле. stdio.h (от англ. STanDart Input Output) это заголовочный файл, в нем описаны различные стандартные функции, связанные с вводом и выводом.
Возникает резонный вопрос «А зачем нам писать эту строчку? Зачем нам вообще понадобилось вставлять сюда этот файл?» Это нужно для того, что бы в своей программе, мы могли использовать стандартную функцию вывода на экран printf().
Дело вот в чем. Прежде чем использовать что-нибудь в своей программе, нам надо сначала это описать. Представьте ситуацию, вас попросили принести канделябр, а вы знать не знаете что это такое. Непонятно, что делать.
Так же и компилятор. Когда он встречает какую-нибудь функцию, он ищет её описание (т.е. что она должна делать и что обозначает) в начале программы (с самого начала и до момента её использования в программе). Так вот, функция printf() описана в файле stdio.h. Поэтому мы и подключаем его. А вот когда мы его подключим, компилятор сможет найти функцию printf(), иначе он выдаст ошибку.
Кстати, настало время дополнить нашу карту знаний. Перед функцией main добавим ещё один блок, блок подключения заголовочных файлов.

Рис.3 Карта «Структура программ на языке Си.» Блок подключения заголовочных файлов.
Продолжим разбираться с нашей программой.
Листинг 7. функция printf()
В этой строке мы вызываем стандартную функцию вывода на экран printf(). В данном простейшем случае мы передаем ей один параметр, строку, записанную в кавычках, которую надо вывести на экран, в нашем случае это Hello, World! \n. Но постойте, а что это за \n? На экране, во время запуска программы, никаких \n не было. Зачем тогда мы тут это написали? Данная последовательность это специальный символ, который является командой перейти на следующую строку. Это как в MS Word нажать клавишу Enter. Таких специальных символов несколько, все они записываются с помощью символа «\» — обратный слеш. Такие специальны символы называются управляющими символами. Потом я еще покажу вам их. В остальном на экране появится именно то, что вы написали в двойных кавычках.
Кстати, обратите внимание, каждая команда языка Си заканчивается символом «;» (точкой с запятой). Это похоже на точку в конце предложения, в русском языке. В обычном языке мы разделяем точкой предложения, а в языке программирования Си, точкой с запятой отделяем команды друг от друга. Поэтому ставить точку с запятой обязательно. Иначе компилятор будет ругаться и выдаст ошибку.
Чтобы вызвать какую-нибудь функцию, необходимо написать её имя и указать передаваемые ей параметры в круглых скобках. У функции может быть один или несколько параметров. А может не быть параметров вовсе, в таком случае в скобках писать ничего не нужно. Например, выше мы вызвали функцию printf() и передали ей один параметр строку, которую необходимо вывести на экран.
Кстати, полезный совет. Так как в каждой программе обязательно присутствует функция main, и буквально в каждой программе нам потребуется что-то выводить на экран, то рекомендую вам сразу создать файл со следующей заготовкой, чтобы каждый раз не писать одно и то же.
Листинг 8. Стандартная заготовка для программ на языке Си.
Ну вот вроде бы и всё. Этом первый урок можно считать законченным. Хотя нет, ещё один момент есть.
Самое главное в этом уроке это, конечно, общая структура программы. Но кроме того, мы научились выводить на экран произвольный текст. Кажется, что совсем ничего вроде и не узнали, но даже этого хватит для того, чтобы, например, сделать небольшой подарок своей маме на 8 марта.
Рис.4 Программа-открытка на 8 марта.
Исходный код программы-открытки есть в архиве с исходными кодами этого урока. Экспериментируйте! У вас всё получится.
Практика
Задачи с автоматической проверкой решения. Для удобства работы сразу переходите в полноэкранный режим 