Элементы языка С

advertisement
Элементы языка Си
Алфавит

1. Буквы и цифры - большие буквы латинского алфавита
ABCDEFGHIJKLMNOPQRSTUVWXYZ
- малые буквы латинского алфавита
abcdefghijklmnopqrstuvwxyz
- десятичные цифры

0123456789

2. Специальные символы

пробел ! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | } ~
Алфавит

Идентификаторами в языке Си являются последовательности букв и цифр,
начинающиеся с буквы, причем символ подчеркивания
рассматривается
компилятором как буква. Большие и малые буквы латинского алфавита
считаются различными. Длина идентификатора формально может быть
произвольной, однако только лишь первые 31 символ являются значимыми
для компилятора

В программах на языке Си идентификаторы служат именами переменных,
символических констант, функций, типов данных и меток. Общепринято для
именования констант использовать большие буквы латинского алфавита,
сохраняя малые буквы для обозначения переменных и функций

Замечание. Не рекомендуется в прикладных программах использовать идентификаторы,
начинающиеся с подчеркивания, ибо в конкретной среде это может привести к конфликту с
именами создаваемых компилятором служебных переменных или констант
Name, name1, Total_5, paper
Ключевые слова

Ключевые слова - это предопределенные идентификаторы, имеющие
специальные значения. Имена никаких объектов программы не
должны совпадать со следующими зарезервированными ключевыми
словами:

- типы данных
char float short typedef void double int signed union
enum long struct unsigned

- классы памяти
auto extern register static


- операторы
break default for return while case do goto sizeof
continue else if switch
- специальные
const far huge pascal cdecl fortran near volatile
Комментарии

Под комментариями понимаются последовательности символов,
игнорируемые компилятором. Комментарии имеют следующую
форму:
/* Characters */ - однострочный комментарий
/*
Characters
*/

- многострочный комментарий
где Characters есть произвольная комбинация любых печатаемых
символов ASCII
Константы

Константами в языке Си могут быть числа (целые и вещественные),
символы и строки символов, которые допустимо использовать в
программе в смысле их значений. Значение никакой константы не
может быть изменено в процессе работы программы. Специальные
директивы языка дают возможность присваивать константам любого
типа символические имена
1. Целые константы
12, 11, 1007
- Десятичные первой цифрой не должен
быть ноль
012, 076, 0111
- Восьмеричные. Начинаются с нуля
0x12, 0X12, 0x2f, 0X2F - Шестнадцатеричные.
Цифры 0-9, буквы a-f, A-F
Начинаются с 0x, 0X.
2. Длинные целые константы

Определяются буквой l или L после константы
12l, 956L
012l,076L - длинная восьмеричная
0x12l 0XA3L - длинная шестнадцатеричная
3. Константы с плавающей точкой

Константа с плавающей точкой всегда представляется числом с
плавающей точкой двойной точности
345.
3.14159265
2.1Е5
0.12е-3
4. Символьные константы

Символьные константы состоят из одного символа кода ASCII,
заключенного в апострофы ’A’ ’s’

ASCII (American Standard Code for Information Interchange —
американский стандартный код для обмена информацией

ASCII представляет собой 7-битную кодировку для представления
десятичных цифр, латинского и национального алфавитов, знаков
препинания и управляющих символов.

В компьютерах обычно используют 8-битные расширения ASCII
На подавляющем большинстве современных компьютеров минимально адресуемая единица памяти — 8-битный
байт, поэтому там используются 8-битные, а не 7-битные символы. Обычно символ ASCII расширяют до 8 бит,
просто добавляя нулевой бит в качестве старшего.
Специальные (управляющие) символьные константы










Перевод строки (новая строка)
LF
Горизонтальная табуляция
HT
Вертикальная табуляция
VT
Возврат на шаг
BS
Возврат каретки
CR
Перевод формата (новая страница) FF
Обратная косая
\
Апостроф
’
Кавычки
”
Нулевой символ
NUL
\n
\t
\v
\b
\r
\f
\\
\’
\”
\0

Кроме
того
любой
символ
может
быть
представлен
последовательностью 3 восьмеричных цифр \ddd или \xddd символ ASCII в шестнадцатеричном представлении.

Незначащие нули слева в обоих случаях могут быть опущены
#define
FORMFEED
’\014’
'A' 'c' '?' '7' '\'' '\\' '\n' 'r'
'\033'
'\10' '\x1F'
5. Строковые константы

Последовательность символов ASCII, заключенная в двойные
кавычки. Строки считаются значениями типа “массив символов”,
относящихся к статической памяти и инициированными заданными
символами. Транслятор помешает в конец каждой строки нулевой
байт \0
”This is a character string”

”A”
”1234”
Каждая строковая константа, даже если она равна другой, помещается
в отдельном месте памяти

Для формирования длинной последовательности символов,
занимающей более одной строки на экране терминала, необходимо
набрать символ \, нажать клавишу Enter и продолжить ввод
символов с новой строки:
"Long string can be broken\
into two pieces."

Важно заметить, что символьная константа, например 'x' , не
идентична строке "x" , содержащей один символ

Дело в том, что символьная константа занимает один байт памяти и
равносильна своему числовому коду во внутреннем машинном
представлении
Строка же из одного символа занимает два байта памяти, первый из
которых содержит код этого символа, а второй - символ \0

6. Перечисляемые константы

Имена, указанные в описании перечисляемых констант, трактуются
как целые. Данные перечислимого типа относятся к некоторому
ограниченному множеству данных

Определение: enum color { red, green, yellow};
Описание:
enum color chair;
enum color suite[40];

Использование:
char = red;
suite[5] = yellow;
Операции и выражения





Под операциями следует понимать действия, выполняемые
программой над определенными в ней объектами
Для обозначения операций используются некоторые стандартные
комбинации специальных символов из алфавита языка
Объекты программы, участвующие в операции, называются
операндами
Всякая комбинация одного или большего числа операндов и
символов операций, дающая единственное значение, образует
выражение
Любое выражение, заканчивающееся точкой с запятой, является
оператором

Множество всех операций языка Си удобно разделить на следующие
группы:
1.
2.
3.
4.
5.
6.
7.
8.
9.
арифметические операции
операции отношения
логические связки
побитовые операции
операции присваивания
адресные операции
операции над массивами
операции над структурами и объединениями
другие операции
1. арифметические операции
+
-
*
/
%
++
--

Двухместную операцию вычитания следует отличать от имеющей
наивысший приоритет одноместной (унарной) операции изменения
знака, символом которой служит знак минус (-) слева от операнда

Важную роль в программах на языке Си играют одноместные
операции увеличения (++) и уменьшения (--) значения переменной
на единицу. Можно писать ++n и n++ . В первом случае увеличение
производится до использования переменной, во втором после

Эти операции можно применять лишь к переменным
X=(i+j)++
так нельзя
Пример:
n=5; x=n++;
//(x=5)
n=5; x=++n;
//(x=6)
if (c== ‘\n’) { s[i]=c; ++i;} или более компактно
if (c== ‘\n’)
s[i++];

Приоритет операций ++ и -- выше приоритета любой двухместной
операции и операции присваивания, а порядок их обработки
компилятором - справа налево.

Совокупность одного или большего числа операндов и символов
операций
(включая
операции
присваивания)
образуют
арифметическое выражение

Обычный порядок выполнения операций может быть изменен путем
заключения некоторой части арифметического выражения в круглые
скобки

Приведем несколько примеров арифметических операций
a = 4.3 + 2.7;
b = (c + d) % 4;
e = ++f/(g + h);

В последнем примере использована префиксная форма оператора ++
и поэтому операция деления будет выполнена после фактического
увеличения значения переменной f на единицу

В языке Си операция присваивания является полноправной частью
любого арифметического выражения

Встречаются достаточно сложные в семантическом отношении
выражения вида
p = 2*(q + s)/(t = u * ++v)
2. операции отношения

==
!=
<
>
<=
>=
Отношения имеют приоритет ниже арифметических.
i < lim-1; Вычисляется как i < (lim-1);

Пример: год будет високосным, если он делится на 4, но не делится
на 100, однако годы делящиеся на 400 тоже високосные
if (year % 4 == 0 && year % 100 != 0 || year %
400 == 0) год високосный;
else год невисокосный ;

Результатом всякой операции отношения является числовое
значение типа int, равное единице, если сравнение истинно, и
нулю в противном случае

Таким образом, операции отношения во внутреннем машинном
представлении приводят к арифметическому результату



Замечание. Строго говоря, логическое значение "истина" должно отвечать
любому числовому значению, отличному от нуля. В дальнейшем мы
увидим, что именно такое соглашение принято в языке Си.
Это дает возможность объединить понятия арифметического, условного и
логического выражений в едином понятии "выражение", что очень важно с
точки зрения гибкости и "симметричности" языка
Выражения, сконструированные при помощи операций отношения,
принято называть условными выражениями
3. логические связки


!
||
&&
Приоритет ниже, чем у операций отношения
Выражения с && и || вычисляются слева направо и вычисления
заканчиваются, когда определяется истинность или ложность
результата
for (i=0; i<lim-1; &&(c=getch())!= ’\n’ && c != EOF; ++i)
s[i]=c;


Скобки (c=getch()) нужны, поскольку приоритет присваивания
ниже
Унарная операция ! преобразует ненулевой операнд в ноль, и
наоборот
if (!inword) то же, что и if(inword==0)

4. побитовые операции ~

Операции для работы с разрядами. Их нельзя применять к float и
double

& - поразрядное И.
c = m & 0177; - Устанавливает в 0 все разряды, кроме младших
семи

| - поразрядное ИЛИ
x =x | MASK;
- Устанавливает в 1 те разряды x, которым
соответствует 1 в MASK

^ - исключающее ИЛИ. Результат содержит 1 в тех разрядах в
которых разные значения, 0 в остальных.
<<
>>
&
|
^

<<
>> - сдвиг влево, сдвиг вправо.
x=x<<2; // сдвигает x влево на два разряда.
x=x>>2; // сдвигает x вправо на два разряда.
На некоторых машинах приводит к размножению знакового разряда

~ - унарная операция дополнение до 1. 1 где 0 и 0 где 1.
x =x & ~077; // - Устанавливает в 0 6 разрядов x.

5. операции присваивания
= += -= *= /= %= <<= >>= &= ^= |=

i=i+2; // можно записать в виде

Пример: Следующая функция считает число единичных разрядов в
целом аргументе
i+=2;
int Bitecount(n)
{
int b;
for (b=0; n!=0; n >>= 1)
if (n&01) b++; return(b);
}

6. адресные операции & *

&v

Пример:
intptr = &n;
*pe
- значением выражения является переменная, адресуемая
указателем pe
*ptr = c;
*fpe
- значением выражения является функция, адресуемая
указателем fpe
fpe = funcname;
(*fpe)(arg1,arg2);
значением выражения является адрес переменной v

7. операции над массивами
[ ]
pe[ie] - значением выражения является переменная, отстоящая на
ie переменных от адреса, заданного ie

Пример:
arname[i]=3; присвоить 3 i-му элементу массива.
Первый элемент arname[0].

8. операции над структурами и объединениями .
->
sv.smem Значением выражения является элемент smem структуры
или объединения sv
product.p = 50;
spe->smem
Присвоить 50 элементу p структуры product
Значением выражения является элемент smem
структуры (или объединения), на которую указывает
spe. Это значение эквивалентно (*spe).smem
prodptr->p = 2;
Присвоить 2 элементу p структурной переменной
на которую указывает prodptr
9. другие операции
e1?e2:e3
? : , syzeof (type specifier) ( )
- условное выражение
if (a>b) x=a; else x=b;
z=(a>b)?a:b;
Условное выражение действительно выражение.
Если e2 и e3 разных типов, то результат задается правилами
преобразования типов
sizeof(e)
- число байт, требуемых для размещения данных типа е.
Если е описывает массив, то в этом случае е обозначает весь массив,
а не только адрес первого элемента, как в остальных операциях
sizeof(тип) - число байт, требуемых для размещения объектов типа
n=sizeof(arname)/sizeof(int);
- число элементов в массиве целых чисел, определяемое как число
байт в массиве, поделенное на число байт, занимаемых одним
элементом массива. Функция выполняется на этапе трансляции
(type specifier)e - значение е, преобразованное в тип данных
x= (float)n/3;
( )
fe(e1,e2, ,eN)
- вызов функции fe с аргументами
e1,e2,...,eN. Значением выражения является значение,
возвращаемое функцией. Обратите внимание, что порядок
вычисления выражений e1,e2,...,eN не гарантируется
x = sqrt(y);
x = sin(y);
Преобразование типов

Если в выражении появляются операнды различных типов, то они
преобразуются к некоторому общему типу

Преобразования могут состоять в следующем:



увеличение или уменьшение размерности машинного слова, то
есть "усечение" или "растягивание" целой переменной;
преобразование целой переменной в переменную с плавающей
точкой и наоборот;
преобразование знаковой формы представления целого в
беззнаковую и наоборот

Уменьшение размерности машинного слова всегда происходит путем
отсечения старших разрядов числа. Заметим, что это может привести
к ошибкам потери значащих цифр и разрядов

Увеличение размерности приводит к появлению дополнительных
старших разрядов числа. При этом способ их заполнения зависит от
формы представления целого:


для беззнаковых целых заполнение производится нулями;
для целых со знаком они заполняются значением знакового
(старшего) разряда

Поэтому "удлинение" целого со знаком, представленного в
дополнительном коде, осуществляется корректно (Для некоторых
компьютеров это не так)

При преобразовании плавающего к целому естественно происходит
потеря дробной части, однако возможны случаи возникновения
ошибок переполнения и потери значимости, когда полученное целое
имеет слишком большое значение.

Преобразование знаковой формы к беззнаковой не сопровождается
изменением значения целого числа и вообще не приводит к
выполнению каких-либо действий в программе. В таких случаях
транслятор "запоминает", что форма представления целого
изменилась
1) Значения типа char, int в арифметических операциях можно
перемешивать

Каждый символ в любом выражении автоматически преобразуется в
целое. При преобразовании char в int в зависимости от
архитектуры машины может происходить размножение знака (в PDP11)

Пример:
Функция atoi( ) превращает строку цифр в ее числовой
эквивалент
int atoi(s)
char s[];
{ int i,n; n=0;
for (i=0; s[i] >= ‘0’ && s[i] <= ‘9’; ++i)
n=10*n + s[i] - ‘0’;
return(n);
}
2) При бинарных операциях, если операнды разных типов, перед тем
как выполнить операцию младший тип приводится к старшему.
Результат - старшего типа






char , short => в int
float
=> double
если один из операндов двойной точности, то другой к двойной
если один long, то другой в long
unsigned => unsigned
В Cи все действия с плавающей точкой идут с двойной точностью.


3) При присваивании значение из правой части преобразуется к
типу левой части.
Пример: Преобразование из целых в символы идет путем
отбрасывания лишних знаков
int i;
char c;
c=i;


4) Преобразования аргументов функции.
Т.к. аргументы функции представляют собой выражения, то при
передаче аргументов также происходит преобразование типов.
(char, short => int, float => double). Поэтому
аргументы функции должны быть описаны как int и double, даже
если к ней обращаются с char и float

5) Преобразование можно сделать принудительно
sqrt((double)n;

Пусть, например, переменная res имеет тип int. Тогда значение
арифметического выражения res = 2.7 + 1.5 согласно общим
правилам преобразования типов, равно 4. Однако применив явным
образом операцию приведения типа к обоим операндам в правой
части
res = (int)2.7 + (int)1.5;

получим результат, равный 3. Этот пример говорит о необходимости
с
особой
осторожностью
относиться
ко
всевозможным
преобразованиям типов операндов

Примеры преобразования базовых типов данных:
int i;
i = 0xFFFF;

Целая переменная со знаком получает значение FFFF,
сoответствует -1 для знаковой формы в дополнительном коде
что
long l;
l = i;

Преобразование int в long сопровождается "удлинением"
переменной, что с учетом знакового характера i дает FFFFFFFF, то
есть длинное целое со значением -1
l = (unsigned)i;

Сначала выполняется преобразование i к целому без знака, что не
сопровождается никакими действиями, затем при присваивании
беззнакового происходит его "удлинение" с заполнением старших
разрядов нулями, то есть результат будет равен 0000FFFF
Приоритеты и порядок выполнения
( ) [ ]
! ~ ++ -- (type) * &
sizeof
* / %
+ << >>
< <= > >=
== !=
&
^
|
&&
? :
= += -=
,

слева направо
справо налево
слева направо
справо налево
справо налево
справо налево
слева направо
Операции, перечисленные в одной строке, имеют одинаковый
приоритет. Строки расположены в порядке убывания приоритетов

В Си не задан порядок вычислений операндов для операций. Поэтому
обращения к функциям, вложенные операции и уменьшения могут
обладать побочным результатом. Например:
x = f(x) = g();

f может вычисляться ранее g и наоборот. Если f и g изменяют
какую-либо внешнюю переменную, от которой зависит другая
функция, то может оказаться, что х зависит от порядка вычислений
a[i]=i++;

// индексирование идет старым значением или новым
Транслятор может работать по разному
printf(”%d %d \n”, ++n, power(2,n));

на различных машинах разные результаты, будет ли обращаться к
power до или после. Правильно:
++n;
printf(”%d %d \n”, n, power(2,n));
Простейшие операторы языка Си

Рассмотренные выше арифметические, условные и логические
выражения в совокупности образуют объекты программы, которые
принято называть просто выражениями

Этой терминологией подчеркивается равноправие операций
различных групп с точки зрения их роли в формировании выражений

Более того, всякому выражению в Си соответствует некоторое
числовое значение (за исключением, конечно, тех случаев, когда
результат операции считается неопределенным), которое может быть
использовано в дальнейшем



Однако сами по себе выражения любого вида еще не являются
законченными инструкциями языка Си. Для обозначения
завершенных действий используется понятие оператора
Простейшим оператором языка является всякое выражение,
заканчивающееся точкой с запятой (;). В частности, отдельно
стоящая точка с запятой интерпретируется компилятором как нульоператор
Например, инструкции вида
a = c*(d + e)/4;
f = alpha++;

являющиеся операторами-выражениями, играют роль законченных
предписаний для исполняющей системы

Группа из одного или большего числа операторов, заключенных в
фигурные скобки, образует составной оператор. Заметим, что по
правилам языка точка с запятой после закрывающей фигурной скобки
не ставится. Например, группа из трех операторов
{ x = 7; y = x + 10; z = (x + y)/13; }

рассматривается компилятором как один составной оператор. В
программе на языке Си составные операторы могут быть
использованы всюду наравне с простыми операторами

Наиболее значительную группу операторов образуют инструкции
(операторы) управления процессом выполнения программы. К ним
относятся:

условный оператор (if else)
переключатель (switch)
несколько разновидностей оператора цикла
 while
 do while
 for
операторы передачи управления
 break
 continue
 goto
 return



условный оператор (if

else)
Условный оператор является простейшим и эффективным средством,
позволяющим программировать разветвленные алгоритмы. Его
формальный синтаксис задается следующей формулой:
if (expression)
statement1
<else
statement2>


причем else-часть не является обязательной и может быть опущена
Здесь if и else - ключевые слова языка Си; expression произвольное выражение, приводимое к логическому значению;
statement1 и statement2 - простые или составные операторы

Семантика

Прежде всего вычисляется значение выражения, стоящего в скобках,
и полученный результат сравнивается с нулем, что соответствует его
интерпретации в терминах "истина"/"ложь". Если результатом
является логическое значение "истина" (выражение отлично от нуля),
то выполняются действия, отвечающие statement1. В противном
случае осуществляется переход к statement2 в else-части
условного оператора, а при ее отсутствии - к оператору,
непосредственно следующему за оператором if

В приведенном ниже примере
if (i > 0) y = x/i; else { x = i/2; y = x + 4; }

оператор y = x/i; будет выполнен, если значение i больше нуля. В
противном случае выполняется группа операторов x = i/2; y =
x + 4;

В конструкциях вида
if (n > 0)
if (a > b) z = a;
else z = b;

где один оператор if вложен в другой, else-часть связывается с
ближайшим предыдущим оператором if. Чтобы изменить это
соглашение, необходимо использовать фигурные скобки:
if (n > 0)
{ if (a > b) z = a; }
else z = b;

Поскольку запись без скобок ненаглядна рекомендуется ставить
скобки для избежания ошибок
переключатель switch

Переключатель является специальным случаем условного оператора и
позволяет осуществлять многовариантный выбор, заменяя группу
вложенных операторов if-else. В общем случае от имеет
следующий формат:
switch (expression)
{ case const-expression: statements
. . .
default: statements
. . .
case const-expression: statements
}

где любая case- или default-часть может отсутствовать, а также
могут быть опущены statements в любой из этих частей

Семантика

Предварительно вычисленное значение выражения в круглых скобках
сравнивается с const-expression во всех вариантах case и
управление передается той группе операторов statements, которая
соответствует найденному значению.
В том случае, когда значение ни одного из константных выражений
не совпало со значением выражения expression, выполняются
операторы, связанные с меткой default, а при ее отсутствии оператор, непосредственно следующий за оператором switch.


Никакие два константные выражения в одном
переключателе не могут иметь одинаковых значений
операторе
-

В следующем примере значение переменной operation, имеющей
тип char, определяет ту арифметическую операцию, которая должна
быть выполнена над переменными x и y:
switch
{ case
case
case
case
}

(operation)
'+':
z = x + y; break;
'-': z = x - y;
break;
'*': z = x*y;
break;
'/': z = x/y;
Ключевое слово case вместе с const-expression служат просто
меткой соответствующих операторов, и если будут выполняться
операторы для некоторого варианта case, то далее будут
выполняться операторы всех последующих вариантов до тех пор,
пока не встретится оператор break

Поэтому если нескольким различным значениям выражения
expression должны соответствовать одни и те же действия, можно
воспользоваться следующей конструкцией:
switch
{ case
case
case
case
case
case
case
case
case
case
}
(key)
'0':
'1':
'2':
'3':
'4':
'5':
'6':
'7':
'8':
'9': printf ("Это цифра");
операторы цикла (три типа)
while
do while
for
1. Оператор цикла while

Оператор while позволяет циклически выполнять определенную
последовательность операторов до тех пор, пока истинно некоторое
условие, проверяемое перед началом очередной итерации цикла (цикл
с предусловием). Формально его синтаксис может быть описан
следующей формулой:
while (expression) statement

где while - ключевое слово языка Си; expression - произвольное
выражение, приводимое к логическому значению (условие
продолжения итераций); statement - простой или составной
оператор (тело цикла)

Семантика

Если значение выражения expression истинно (отлично от нуля),
то тело цикла выполняется до тех пор, пока это выражение не станет
ложным (равным нулю), причем проверка производится всякий раз
перед началом очередной итерации цикла.
Если же значение выражения ложно в момент инициализации цикла,
то тело цикла не выполняется ни разу и управление передается
оператору, следующему за оператором while


В качестве примера использования оператора цикла с предусловием,
рассмотрим фрагмент программы, определяющей длину строки
символов string:
count = 0;
while (string[count] != '\0') count++;

После окончания работы этого фрагмента, значение переменной
count равно количеству символов в строке string, не считая
завершающего нуль-символа
2. Оператор цикла do-while

Принципиальное назначение этого оператора такое же, как и
рассмотренного оператора while. Семантическое различие двух этих
операторов цикла состоит лишь в том, что в рассматриваемом случае
условие продолжения проверяется после завершения очередной
итерации (цикл с постусловием). В общем виде оператор do-while
записывается следующим образом:

do statement while (expression);

где do и while - ключевые слова языка Си; statement - простой или
составной оператор (тело цикла); expression - произвольное
выражение, приводимое к логическому значению (условие
продолжения итераций)

Семантика

После однократного выполнения тела цикла вычисляется значение
выражения expression. Если найденное значение истинно (отлично
от нуля), то выполняется очередная итерация цикла. Этот процесс
повторяется до тех пор, пока значение выражения не станет ложным
(равным нулю), после чего управление передается оператору,
непосредственно следующему за оператором do-while. Таким
образом, тело цикла всегда будет выполнено хотя бы один раз

В качестве примера использования цикла с постусловием, приведем
фрагмент программы, выполняющей копирование строки символов
string1 в строку string2:
count = 0;
do string2[count] = string1[count];
while (string1[count++]);
3. Оператор цикла for

Оператор for является наиболее мощным средством реализации
циклических алгоритмов и управления циклическими процессами. Он
объединяет в себе инициализацию переменных, проверку условия
продолжения итераций и модификацию переменных перед
выполнением очередной итерации, что по своей сути эквивалентно
следующей группе операторов:
expression1
while (expression2) { statement expression3; }


Общая форма записи оператора цикла for такова:
for (expression1; expression2; expression3)
statement


где for - ключевое слово языка Си; expression1, expression2
и expression3 - произвольные выражения, причем второе из них
приводится к логическому значению; statement - простой или
составной оператор (тело цикла)
Любое из трех выражений, входящих в заголовок цикла, может быть
опущено при сохранении следующей за ним точки с запятой
Семантика

Перед началом выполнения цикла вычисляется значение
инициализирующего выражения expression1 и значение
выражения expression2, играющего роль условия продолжения
итераций. Если expression2 истинно (отлично от нуля), то
выполняется оператор statement тела цикла, вычисляется
корректирующее выражение expression3 и вновь проверяется
истинность выражения expression2

Этот процесс повторяется до тех пор, пока условие продолжения
итераций не станет ложным (равным нулю), после чего управление
передается оператору, следующему за оператором for. В случае
отсутствия выражения expression2 ему условно присваивается
постоянное значение "истина", что равносильно бесконечному
циклическому процессу

В следующем программном фрагменте, вычисляющем сумму
элементов числового массива, оператор цикла for используется для
организации последовательного доступа ко всем элементам этого
массива:
s = 0;
for (i = 0; i < n; i++) s = s + a[i];

Каждое из выражений в заголовке цикла может состоять из
нескольких подвыражений, связанных между собой операцией
запятая (,). Эта операция обеспечивает последовательное вычисление
своих операндов слева направо, причем ее результатом является
значение самого правого операнда

Применительно к оператору цикла for, операция запятая чаще всего
используется в тех случаях, когда необходимо иметь несколько
инициализирующих и корректирующих выражений

Эту ситуацию можно проиллюстрировать следующим программным
фрагментом, выполняющим инвертирование последовательности из n
элементов:
for (i = 0, j = n-1; i < j; i++, j--)
{ buf = a[i]; a[i] = a[j]; a[j] = buf; }

Пример: Следующая подпрограмма упорядочивает массив чисел
void shell(int v[],n)
{ int gap,i,temp;
for (gap=n/2; gap>0; gap /=2)
for (i=gap; i<n; i++)
for (j=j-gap; j>=0 && v[j]>v[j+gap]; j -=gap)
{temp = v[j]; v[j]=v[j+gap]; v[j+gap]=temp; }

Пример: Поворот строки
void reverse(char s[])
{ int c,i,j;
for (i=0, i=strlen(s)-1; i<j; i++,j--)
{ c=s[i]; s[i]=s[j]; s[j]=c; }
}
операторы передачи управления
goto break continue return

1. Оператор завершения break

В ряде случаев возникает необходимость завершить выполнение
какого-либо оператора цикла или оператора-переключателя раньше,
чем это произойдет в соответствии с принятой семантикой этих
операторов. Для этой цели служит оператор break, прекращающий
выполнение ближайшего вложенного оператора while, dowhile, for или switch и передающий управление оператору,
следующему за заканчиваемым

Пусть, например, необходимо найти сумму элементов числового
массива до первого отрицательного элемента. Эту задачу можно
решить с помощью следующего программного фрагмента:
s = 0;
for (i = 0; i < n; i++)
if (a[i] >= 0) s = s + a[i]; else break;

Заметим, что появление оператора break вне одного из операторов
while, do-while, for или switch приводит к ошибке на этапе
компиляции программы
2. Оператор продолжения continue

При возникновении необходимости прекратить выполнение текущей
итерации ближайшего внешнего оператора while, do-while или
for и перейти к началу следующей итерации, может быть
использован оператор continue. В случае операторов while и dowhile очередная итерация начинается с вычисления и проверки
истинности выражения expression, а в операторе for - с
вычисления значения корректирующего выражения expression3

Пусть теперь необходимо найти сумму всех положительных
элементов числового массива. Используя оператор continue, это
можно сделать следующим образом:
s = 0;
for (i = 0; i < n; i++)
{ if (a[i] < 0) continue; s = s + a[i]; }
3. Оператор перехода goto

Как и в подавляющем большинстве языков программирования, в
языке Си имеется возможность безусловной передачи управления
любому оператору в пределах текущей функции, хотя гибкость
управляющих конструкций этого языка позволяет почти всегда
обходиться без такой возможности. Формальный синтаксис оператора
перехода описывается следующей формулой:
goto label;

где goto - ключевое слово языка Си, а label - метка оператора в
пределах текущей функции

Согласно синтаксическим правилам языка Си, каждому оператору
программы может быть присвоено уникальное имя, называемое
меткой этого оператора. Сама метка является правильным
идентификатором языка, за которым следует символ двоеточие (:).
Метки операторов могут быть использованы только лишь как объекты
ссылок в операторе goto. Во всех остальных случаях они
игнорируются компилятором

В качестве примера использования оператора goto для выхода из
вложенных управляющих операторов, рассмотрим задачу нахождения
первого элемента двумерного массива, равного заданному числу x:
x = 17;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
if (a[i][j] == x) goto L01;
/*
Действия, выполняемые в случае, если элемент x не найден
...
L01: ...
*/
4. Оператор возврата return

Оператор return прекращает выполнение текущей функции и
возвращает управление той функции, из которой была вызвана
текущая. В общем случае он имеет следующий формат:
return expression;

где return - ключевое слово языка Си, а expression произвольное необязательное выражение
Семантика

После прекращение выполнения текущей функции и передачи
управления
вызвавшей
функции,
выполнение
последней
продолжается с оператора, непосредственно следующего за точкой
вызова. Кроме этого, при наличии выражения expression его
значение
передается
(возможно
после
предварительного
преобразования типа) вызвавшей функции. Если же выражение в
операторе return отсутствует, то возвращаемое текущей функцией
значение считается неопределенным

Замечание. В случае использования оператора return в главной
функции (т.е. функции, имеющей имя main()), его действие
приводит к прекращению выполнения программы и передаче
управления операционной системе

Рассмотренные выше арифметические, условные и логические
выражения в совокупности образуют объекты программы, которые
принято называть просто выражениями

Этой терминологией подчеркивается равноправие операций
различных групп с точки зрения их роли в формировании выражений

Более того, всякому выражению в Си соответствует некоторое
числовое значение (за исключением, конечно, тех случаев, когда
результат операции считается неопределенным), которое может быть
использовано в дальнейшем.
Download