Как в языке c называют именованную последовательность инструкций

Provide feedback

Saved searches

Use saved searches to filter your results more quickly

Sign up

Appearance settings

Язык Си. Функция, пишем свою функцию. Технические детали.

Язык программирования Си.
Функции.

Небольшие технические детали (в тексте ниже).

лекция № 2 — Функция, пишем свою функцию. Часть 1.

лекция № 2 — Функция, пишем свою функцию. Часть 2.

Функция это именованная последовательность инструкций.

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

Синтаксис объявления функции:

 

тип имя(список параметров через запятую);

 void foo(); 

Описание функции без тела(без реализации) называется объявлением.
Описание функции с телом(с реализацией) называется объявлением и определением. Обычно объявление функций делается в заголовочных файлах(.h), а определение в файлах реализации(.c).
Если в текущей единице трансляции  присутствует только объявление функции(не берем в счет ошибки программиста), это значит что реализация функции находится в другой единице трансляции. Вы должны были уже заметить что для вывода сообщений на экран, мы использовали функцию printf(), для этого нам нужно было ввести это имя в нашу единицу трансляции, мы это делали с помощью подключения заголовочного файла #include<stdio.h>, а вот реализации этой функции мы не наблюдали, все нормально, на этапе компоновки, компоновщик увидит использование функции printf(), найдет ее объявление в заголовочном файле, далее, он не найдет ее реализации в исходном коде, и начнет искать ее готовую реализацию в библиотеках которые присоеденены к проекту. К нашему проекту автоматически присоединяются(линкуются) стандартные библиотеки языка(если этого требует исходный код). Функция может возвращать значение любого из законченных типов (стандартных или пользовательских), либо не возвращать ничего(для этого ее тип должен быть void). Точно так же, функция может принимать аргументы, или не принимать их СОВСЕМ, рассмотрим пример ниже:

void foo_a()
{
}
void foo_b(void)
{
}

Функция foo_a() определена как функция без параметров, но это не так!
В языке Си это означает что аргументов может не быть, или они могут быть, но их количество может меняться (аналогия со стандартной библиотечной функцией printf(), в которой количество аргументов всегда разное). Каким способом узнать сколько аргументов было передано, это отдельная тема.
Что касается второй функции foo_b(), то в месте отведенном для описания параметров, мы четко указали void что означает НИКАКИХ АРГУМЕНТОВ. Посмотрите на пример ниже, и попробуйте его отдать компилятору :-)

void foo_a()
{
}
void foo_b(void)
{
}
int main()
{
  foo_a();
  foo_a(1);
  foo_a(1,2,3);
  foo_b();
  foo_b(1);     // compilation error
  return 0;
} 

Когда мы что-то передаем в функцию, то то что мы передаем называется аргументом, а что называется параметром я думаю вы уже поняли. 
Функции избавляют программиста от многократного написания одного и того же кода. Давайте посмотрим на printf(), представьте себе на сколько увеличилась бы наша программа, если бы вместо каждого использования именованной последовательности инструкций printf(), писали бы всю реализацию(если бы мы ее имели :-) ). Кроме того функцию можно использовать в различных частях программы, а в случае улучшения работы функции, нам нужно сделать это улучшение только один раз, в месте определения, а не искать все эти куски кода по всей программе.
К примеру, нам нужно вычислять площадь треугольника, используя формулу Герона, значит создаем следующую функцию:

#include <math.h>
double triangle_area_herons(double aA, double aB, double aC)
{
  double p = (aA + aB + aC) / 2.;
  return sqrt(p *(p - aA) * (p - sB) * (p - sC));
}

Для вычисления квадратного корня(функцией sqrt()), мы подключили стандартный заголовочный файл математической библиотеки math.
Наша функция по вычислению площади готова, теперь её можно смело использовать в коде программы:

#include <math.h>
#include <stdio.h>
double triangle_area_herons(double aA, double aB, double aC)
{
  double p = (aA + aB + aC) / 2.;
  return sqrt(p *(p - aA) * (p - sB) * (p - sC));
}
int main()
{
 double tr_area = 0.0;
 
 tr_area = triangle_area_herons(12., 10., 6.);
 printf("Area of triangle 1 = %d\n", tr_area);
 printf("Area of triangle 2 = %d\n", triangle_area_herons(1., 2., 3.));
 
 return 0;
}

Если функция получается большой, к примеру на несколько страниц, то желательно разбивать такие большие функции, на несколько небольших. Это улучшит читаемость кода, и уменьшит вероятные ошибки, которые возникают из-за того что перед глазами программиста не весь текст функции, а приходится листать вверх-вниз для того чтобы понять, как же она работает. НО! Если это возможно. Иногда невозможно разбить функцию, скажем в 400 строк кода на 5 функций по 80 строк. Наш идеал это — функция, реализация которой умещается в одну страницу кода. Не забываем всегда думать :-)
В языке Си и С++ для объектов(переменных) и функций есть такое понятие как внутренняя связь(internal linkage) и внешняя связь(external linkage), что означает доступность в других единицах трансляции. Внешняя связь, я думаю вы уже догадались, делает возможность получить доступ к объекту или функции в другой единице трансляции, грубо говоря делает возможным объявить объект или функцию глобальной для всех файлов исходного кода. Смотрите код ниже:

void foo_a()        // external linkage
{
}
extern void foo_b() // external linkage
{
}
static void foo_c() // internal linkage
{
}
int main()          // external linkage
{
  foo_a();
  foo_b();
  foo_c(); 
  return 0;
}

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

extern void hello();
int main()
{
  hello();
  return 0;
} 

Запись extern void hello(); вводит имя внешней функции в нашу область видимости(единицу трансляции)
файл hello.c

#include <stdio.h>
void hello()
{
  printf("I am from another translation unit!\n");
}

После сборки программы, на экране появится нужное нам сообщение :-)
Но стоит вам изменить void hello() на static void hello(), то вы получите ошибку при сборке.
Есть очень хорошая программа для того чтобы определить, какие обьекты являются со внешней связью а какие с внутренней, называется она NM из GNU Binary Utils, если вы используете один из дистрибутивов Linux(крайне рекомендую, особенно при изучении программирования) то проблем не должно быть с ее использованием, если же Windows … то …
вас никто не заставлял использовать Windows :-) , в принципе можно установить Linux Terminal под Windows, называется он Cygwin при установке которого, можно установить практически все полезные программы из Linux.

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

#!/bin/bash
clear
gcc -c main.c
nm -C main.o
#nm -C --extern-only main.o
#nm --defined-only main.o
#nm --undefined-only main.o

Если его выполнить в корне со следующим файлом,
main.c

void foo_a()        // external linkage
{
}
extern void foo_b() // external linkage
{
}
static void foo_c() // internal linkage
{
}
int main()          // external linkage
{
  foo_a();
  foo_b();
  foo_c(); 
  return 0;
}

То на экране вы увидите:
0000000000000000 T  foo_a
0000000000000007 T  foo_b
000000000000000e  t  foo_c
0000000000000015  T main

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

Думаю ничего не забыл из важного, но в любом случае всегда можно дописать!
Спасибо за внимание!

Структура Си-программы[]

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

  • заголовочные, или h-файлы
  • файлы реализации, или Cи-файлы

Имена заголовочных файлов имеют расширение «.h». Имена файлов реализации имеют расширения «.c».

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

Файлы реализации содержат тексты функций и определения глобальных переменных.

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

#include <stdio.h>

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

#include "mylib.h"

Препроцессор — это программа предварительной обработки текста непосредственно перед трансляцией. Команды препроцессора называются директивами. Директивы препроцессора содержат символ # в начале строки. Препроцессор используется в основном для подключения h-файлов. В Си также очень часто используется директива #define для задания символических имен констант. Пример:

#define PI 3.14159265

Функции[]

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

Вызов функции происходит в результате использования ее имени в выражении. За именем функции следуют круглые скобки, внутри которых перечисляются фактические значения ее аргументов. Даже если аргументов нет, круглые скобки с пустым списком аргументов обязательно должны присутствовать!
После вызова функции значение, возвращенное в результате ее выполнения, используется в выражении (имя функции как бы заменяется возвращенным значением). Примеры:

x = sin(1.0);
f();

Типы переменных[]

Базовые типы[]

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

Целочисленные типы[]

Целочисленные типы различаются по длине в байтах и по наличию знака. Их четыре: char, short, int и long. Кроме того, к описанию можно добавлять модификаторы unsigned или signed для беззнаковых (неотрицательных) или знаковых целых чисел.

Тип int[]

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

Тип char[]

Тип char представляет целые числа в диапазоне от -128 до 127. Элементы типа char занимают один байт памяти. Слово «char» является сокращением от character, что в переводе означает «символ». Действительно, традиционно символы представляются их целочисленными кодами, а код символа занимает один байт. Тем не менее, подчеркнем, что элементы типа char — это именно целые числа, с ними можно выполнять все арифметические операции. Стандарт Си не устанавливает, трактуются ли элементы типа char как знаковые или беззнаковые числа, но большинство Си-компиляторов считают char знаковым типом.

Вещественные типы[]

Вещественных типов два: длинное вещественное число double (переводится как «двойная точность») и короткое вещественное число float (переводится как «плавающее»). Вещественное число типа double занимает 8 байтов, типа float — 4 байта.
Тип double является основным для компьютера. Тип float — это, скорее, атавизм, оставшийся от ранних версий языка Си. Компьютер умеет производить арифметические действия только с элементами типа double, элементы типа float приходится сначала преобразовывать к double. Точность, которую обеспечивает тип float, низка и не достаточна для большинства практических задач. Все стандартные функции математической библиотеки работают только с типом double.

1. Перечислимый тип[]

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

Объявление переменной перечислимого типа задаёт имя переменной и определяет список именованных констант, называемый списком перечисления: enum [<тег>] {<список перечисления>} <описатель> [, <описатель> …]; enum <тег> <описатель> [, <описатель> …];

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

Список перечисления содержит одну или более конструкций вида: <идентификатор> [= <константное выражение>]

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

Запись  = <константное выражение> изменяет умалчиваемую последовательность значений. Элемент, идентификатор которого предшествует записи  = <константное выражение>, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип intи может быть как положительным, так и отрицательным. Следующий элемент списка получает значение, равное <константное выражение> + 1, если только его значение не задаётся явно другим константным выражением.

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

enum Weekdays {SA, SU, MO, TU, WE, TH, FR};
enum Weekdays {SA, SU = 0, MO, TU, WE, TH, FR}; // SA и SU имеют одинаковое значение
void main()
{ enum Weekdays d1 = SA, d2 = SU, d3 = WE, d4;
d4 = 2; // Ошибка!
d4 = d1 + d2; // Ошибка!
d4 = (enum Weekdays)(d1 + d2); // Можно, но результат
d4 = (enum Weekdays)(d1 — d2); // может не попасть
d4 = (enum Weekdays)(TH * FR); // в область определения
d4 = (enum Weekdays)(WE / TU); // перечисления
}

2. Структуры[]

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

Объявление структуры задает имя структурного типа и/или последовательность объявлений переменных, называемых элементами структуры. Эти элементы могут иметь различные типы. struct [<тег>] {<список объявлений элементов>} <описатель> [, <описатель> …]; struct <тег> <описатель> [, <описатель> …];

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

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

struct
{ char str[50];
int a, b; // Объявляем структуру, не задавая тег
} s; // и сразу же объявляем переменную
struct S
{ char str[50];
int a, b;
}; // Объявляем структуру с тегом S
struct S s; // Объявляем переменную

Элемент структуры не может быть структурой того же типа, в которой он содержится. Однако он может быть указателем на тип структуры, в которую он входит. Размер указателя стандартный, поэтому компилятор знает, сколько памяти потребуется под указатель. Для работы с указателем надо знать размер типа, на который он указывает, но к моменту работы с указателем структура будет полностью объявлена, и, следовательно, размер её будет известен.

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

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

struct S s = {«Str», 0, 1}; // Используем тег S, объявленный в предыдущем примере

Выбор элемента структуры осуществляется с помощью одной из следующих конструкций: <переменная> . <идентификатор элемента структуры> <указатель> -> <идентификатор элемента структуры>

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

struct S s, *p = &s; // Объявляем переменную s и указатель p, в который заносим адрес переменной s
s.a = 10;
p->b = 20;

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

2.1. Пример[]

Вводим массив структур и осуществляем поиск по любой совокупности параметров.

  1. include <stdio.h>
  2. include <math.h>
  3. include <string.h>
  4. include <conio.h>
struct S // Объявляем структуру, состоящую
{ char str[21]; int a; }; // из строки и целого числа
struct S s[10]; // Объявляем массив структур
void main(int argc, char *argv[]) { int n, a, i, check = 0; // Переменная а содержит число, которое будет сравниваться с полем структуры а. // Переменная check указывает, нужно ли использовать этот параметр для поиска.
char str[21] = «»; // Переменная str содержит строку, которая будет сравниваться с полем структуры str. // Если переменная str содержит пустую строку, этот параметр не используется для поиска.
FILE *in, *out; char ans; if (argc < 3) { printf(«Too few arguments.\n»); return; } if ((in = fopen(argv[1], «r»)) == NULL) { printf(«It is impossible to open file ‘%s’.\n», argv[1]); return; } if ((out = fopen(argv[2], «w»)) == NULL) { printf(«It is impossible to open file ‘%s’.\n», argv[2]); fclose(in); return; } for (n = 0; !feof(in); n++) fscanf(in, «%s%d», s[n].str, &s[n].a); fclose(in); printf(«Use Str for search? «); ans = getche(); if (ans == ‘y’ ans == ‘Y’) { printf(«\nInput string for search: «); scanf(«%s»,str); } printf(«Use A for search? «); ans = getche(); if (ans == ‘y’ ans == ‘Y’) { check = 1; printf(«\nInput A: «); scanf(«%d», &a); } for (i = 0; i < n; i++)
if ((!*str strcmp(str, s[i].str) == 0) && (!check a == s[i].a)) fprintf(out, «%-30s %3d\n», s[i].str, s[i].a); fclose(out); } // Данное условие проверяет содержимое структуры на равенство параметрам поиска, // учитывая необходимость сравнения с этим параметром

3. Объединения[]

Объединение позволяет в разные моменты времени хранить в одном объекте значения разных типов. В процессе объявления объединения с ним ассоциируется набор типов значений, которые могут храниться в данном объединении. В каждый момент времени объединение может хранить значение только одного типа из набора. Контроль над тем, какого типа значение хранится в данный момент в объединении, возлагается на программиста. union [<тег>] {<список объявлений элементов>} <описатель> [, <описатель> …]; union <тег> <описатель> [, <описатель> …];

Тег предназначен для различения нескольких объединений, объявленных в одной программе.

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

  1. include <stdio.h> void main() { union { float f; long int i; } u; printf(«Input float number: «); scanf(«%f», &u.f); printf(«Internal: %08x\n\n», u.i); }

Оператор typedef[]

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

typedef char *string;

Операторы языка Си[]

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

Оператор присваивания[]

x = (y = sin(z)) + 1.0;

Арифметические операции[]

z = x + y;
z = x - y;
z = x * y;
z = x / y;
z = x % y; // Остаток от деления x на y

Операции увеличения/уменьшения[]

Операции увеличения ++ и уменьшения — на единицу имеют префиксную и суффиксную формы.

++ x;    // Префиксная форма
x --;    // Суффиксная форма

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

Операции «увеличить на», «домножить на» и т.п.[]

Оператор вида ?= существует для любой операции ?, допустимой в Си. Примеры:

z += y;  // z = z + y
z *= y;  // z = z * y
z %= x;  // z = z % x
a ||= b; // a = a || b

Логические операции[]

a = b || c; // логическое "или"
a = b && c; // логическое "и"
a = !b;     // логическое "не"

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

Чрезвычайно важной особенностью операций логического сложения и умножения является так называемое «сокращенное вычисление» результата. А именно, при вычислении результата операции логического сложения или умножения всегда сначала вычисляется значение первого аргумента. Если оно истинно в случае логического сложения или ложно в случае логического умножения, то второй аргумент операции не вычисляется вовсе! Результат операции полагается истинным в случае логического сложения или ложным в случае логического умножения.

Операции сравнения[]

Операции сравнения в Си обозначаются следующим образом:

== равно,  != не равно,
> больше,  >= больше или равно,
< меньше,  <= меньше или равно.

Побитовые логические операции[]

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

& побитовое логическое умножение ("и")
| побитовое логическое сложение ("или")
~ побитовое логическое отрицание ("не")
^ побитовое сложение по модулю 2 (исключающее "или")

Операции сдвига[]

Операции сдвига применяются к целочисленным переменным: двоичный код числа сдвигается вправо или влево на указанное количество позиций. Сдвиг вправо обозначается двумя символами «больше» >>, сдвиг влево — двумя символами «меньше» <<. Пример:

int x, y;
//...
x = (y >> 3);   // Сдвиг на 3 позиции вправо
y = (y << 2);   // Сдвиг на 2 позиции влево

Арифметика указателей[]

С указателями можно выполнять следующие операции:

  • сложение/вычитание указателя и целого числа, результат — указатель (указатель как бы сдвигается на n элементов вправо/влево)
  • увеличение/уменьшение переменной типа указатель, что эквивалентно прибавлению или вычитанию единицы (указатель как бы сдвигается на 1 элемент вправо/влево)
  • вычитание двух указателей, результат — целое число (количество элементов данного типа, которое умещается между двумя адресами)

Приведение типа[]

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

double x;
int n;
//...
x = (double) n;

Основы языка Си

Структура программы на Си

Последнее обновление: 01.01.2023

Программа на языке Си состоит из набора директив препроцессора, определений функций и глобальных объектов. Директивы препроцессора управляют
преобразованием текста до его компиляции. Глобальные объекты определяют используемые данные или состояние программы. А функции определяют поведение или действия программы.
Простейшая программа на Си, которая была определена в прошлых темах:

#include <stdio.h>
int main(void)
{
	printf("Hello METANIT.COM! \n");
	return 0;
}

Инструкции

Простейшим строительным элементом программы на Си являются инструкции (statements). Каждая инструкция выполняет определенное действие.
В конце инструкций в языке Си ставится точка с запятой (;). Данный знак указывает компилятору на завершение инструкции. Например:

printf("Hello METANIT.COM!");

Вызов функции printf, которая выводит на консоль строку «Hello METANIT.COM!» является инструкцией и завершается точкой с запятой.

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

{
	printf("Hello METANIT.COM!");
	printf("Bye world!");
}	

В этом блоке кода две инструкции. Обе инструкции представляют вызов функции printf() и выводят определенную строку на консоль.

Директивы препроцессора

Для вывода данных на консоль в примере выше используется функция printf(), но чтобы использовать эту функцию, чтобы она вообще стала нам доступна
в программе на Си, необходимо в начале файла с исходным кодом подключать заголовочный файл stdio.h с помощью директивы include.

Директива include является директивой препроцессора. Кроме данной include есть еще ряд директив препроцессора, например, define.

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

Непосредственно директива «include» определяет, какие файлы надо включить в данном месте в текст программы. По умолчанию мы можем подключать стандартные
файлы из каталога так называемых «заголовочных файлов», которые обычно поставляются вместе со стандартными библиотеками компилятора. И файл «stdio.h» как раз является
одним из таких заголовочных файлов.

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

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

При компиляции исходного кода вначале срабатывает препроцессор, который сканирует исходный код на наличие строк, которые начинаются с символа #.
Эти строки расцениваются препроцессором как директивы. И на месте этих директив происходит преобразование текста. Например, на месте
директивы #include <stdio.h> вставляется код из файла stdio.h.

Функция main

Стартовой точкой в любую программу на языке Си является функция main(). Именно с этой функции начинается выполнение приложения.
Ее имя main фиксировано и для всех программ на Си всегда одинаково.

Функция также является блоком кода, поэтому ее тело обрамляется фигурными скобками, между которыми идет набор инструкций.

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

#include <stdio.h>
void main()
{
	printf("Hello METANIT.COM!");
}

или

#include <stdio.h>
int main()
{
	printf("Hello METANIT.COM!");
	return 0;
}

Использование этих определений не было бы ошибкой, и программа также вывела бы строку «Hello METANIT.COM» на консоль. И для большинства компиляторов это было бы нормально.

Комментарии

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

В Си можно использовать два типа комментариев: блочный и строчный. Блочный заключается между символами /* текст комментария */. Он может размещаться
на нескольких строках. Например:

#include <stdio.h>

/* Функция main выводит 
	на консоль строку Hello World */
int main(void)
{
	printf("Hello METANIT.COM! \n");
	return 0;
}

Строчный комментарий помещается на одной строке после двойного слеша:

#include <stdio.h>		// подключаем заголовочный файл stdio.h

int main(void)					// определяем функцию main
{								// начало функции
	printf("Hello METANIT.COM!");		// выводим строку на консоль
	return 0;					// выходим из функции
}								// конец функции

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Пиперазин инструкция по применению для кошек дозировка таблетки
  • Ежевика салфетки инструкция по применению
  • Элтис 400 домофон инструкция
  • Цинк форте таблетки инструкция по применению
  • Дос гель грасс инструкция по применению