Электронный учебно-методический комплекс по учебной дисциплине «Системное программирование» для специальностей 1-40 01 01 «Программное обеспечение информационных технологий», 6-05-0612-01 «Программная инженерия»
.pdf¦ [] выделение |
элемента массива |
¦ |
|
¦ |
или объединения |
¦ |
|
¦ -> выделение |
элемента структуры(объеди- ¦ |
||
¦ |
ния), адресуемой(ого) указателем |
¦ |
|
----------------------------------------------------------------
2 ¦ ! |
логическое отрицание |
¦Справа налево |
¦ ~ |
побитовое отрицание (дополнение) |
¦ |
¦ - |
изменение знака |
¦ |
¦ ++ |
увеличение на единицу |
¦ |
¦ -- |
уменьшение на единицу |
¦ |
¦ & |
определение адреса (указателя) |
¦ |
¦ * |
обращение по адресу (указателю) |
¦ |
¦ (тип) преобразование (приведение) типа |
¦ |
|
¦ sizeof определение размера в байтах |
¦ |
|
--------------------------------------------------------------
3 ¦ * |
умножение |
¦Слева направо |
|
¦ |
/ |
деление |
¦ |
¦ |
% |
деление по модулю |
¦ |
--------------------------------------------------------------
4 ¦ |
+ |
сложение |
¦ |
- " |
¦ |
- |
вычитание |
¦ |
|
--------------------------------------------------------------
5 ¦ |
<< |
сдвиг |
влево |
¦ |
- " |
¦ |
>> |
сдвиг |
вправо |
¦ |
|
-------------------------------------------------------------
6 ¦ > |
больше |
¦ |
- " |
|
¦ >= |
больше или равно |
¦ |
|
|
¦ |
< |
меньше |
¦ |
|
¦ |
<= |
меньше или равно |
¦ |
|
--------------------------------------------------------------
7 ¦ |
== |
равно |
¦ |
- " |
¦ |
!= |
не равно |
¦ |
|
--------------------------------------------------------------
8 ¦ & побитовая конъюнкция (И) ¦ - "
--------------------------------------------------------------
9 ¦ ^ побитовое исключающее ИЛИ ¦ - "
--------------------------------------------------------------
10 ¦ | побитовая дизъюнкция (ИЛИ) ¦ - "
--------------------------------------------------------------
11 ¦ && логическая конъюнкция (И) ¦ - "
--------------------------------------------------------------
12 ¦ || логическая дизъюнкция (ИЛИ) ¦ - "
--------------------------------------------------------------
13 ¦ ?: условное вычисление ¦Справа налево
--------------------------------------------------------------
14 ¦ = |
присваивание |
¦ |
- " |
|
¦ *= |
умножение |
и присваивание |
¦ |
|
¦ /= |
деление и |
присваивание |
¦ |
|
¦ %= |
деление по модулю и присваивание |
¦ |
|
|
¦ += |
сложение и присваивание |
¦Справа налево |
||
¦ -= вычитание |
и присваивание |
¦ |
|
|
¦ <<= сдвиг влево и присваивание |
¦ |
|
||
¦ >>= сдвиг вправо и присваивание |
¦ |
|
||
¦ &= |
побитовая |
конъюнкция и присваивание |
¦ |
|
¦ ^= |
побитовое |
исключающее ИЛИ и |
¦ |
|
¦ |
присваивание |
¦ |
|
|
¦ |= |
побитовая |
дизъюнкция и присваивание |
¦ |
|
--------------------------------------------------------------
15 ¦ , последовательное вычисление ¦Слева направо
--------------------------------------------------------------
Примеры:
x*y/c |
<=> |
(x*y)/c |
/* ==> */ |
||
a=b=c |
<=> |
a=(b=c) |
/* |
<== |
*/ |
alfa[i]() <=> |
(alfa[i])() |
/* |
==> |
*/ |
|
51
В сложных выражениях иногда играет роль порядок обработки операндов. Только для четырех операций (&& || ?: ,) в языке C левый операнд гарантированно обрабатывается первым. С целью обеспечения переносимости (мобильности) программы рекомендуется не использовать повторно в выражении переменную, значение которой присваивается любым образом в этом выражении. Пример:
y=(x=1)-(++x);
Перепишем оператор формирования результата в виде
y=ol-or;
Если компилятор планирует вычисление операндов в скобках слева направо, то схема формирования значения y:
ol=1; or=2; y=-1;
(переменная x последовательно принимает значения 1 и 2). При вычислении операндов в обратной последовательности
or=x+1; ol=1; y=x;
(переменная x вначале увеличивается на 1, затем принимает значение 1). Результат присваивания переменных x и y оказался существенно различен [1].
1.4 УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ
1.4.1Условные операторы
Вязыке С имеется две разновидности условных операторов: простой и полный операторы условного выполнения. Синтаксис простого оператора условного выполнения:
if (выражение) оператор
Элемент "оператор" подлежит выполнению, если "выражение" от лично от нуля. Примеры записи:
if (x>0) x=0;
if (i!=1) j++, l=1; <===> if (i!=1) { j++, l=1; }
if (getch()!=27) { k=0;
}
if (i) exit(1); <===> if (i!=0) exit(1);
if (i>0) if (i<n) k++; <===> if ((i>0)&&(i<n)) k++; if (1) i=0; <===> i=0;
52
Синтаксис полного оператора условного выполнения:
if (выражение) оператор_1 else оператор_2
Если "выражение" отлично от нуля, то подлежит выполнению "оператор_1", иначе - "оператор_2". Примеры записи:
if (x>0) j=k+1; else m=i+10;
if (x) { y=i++; k=sfn(i);
} else { printf("\n ???");
exit(0);
}
Элементы "оператор_1" и(или) "оператор_2" могут быть любым оператором, в том числе и условным оператором. Фраза "else ..." относится к непосредственно предшествующей ей фразе "if ...", поэтому для устранения коллизий условных операторов разных уровней вложенности необходимо заключать их в фигурные скобки [1]:
if (!x) |
if (!y) printf("\n |
x=YES, y=YES"); |
else printf("\n x=NO"); /* |
x=0 <===> (x!=0)&&(y==0) ??? */ |
|
if (!x) |
{ |
|
if (!y) printf("\n x=YES, |
y=YES"); |
|
}else printf("\n x=NO");
1.4.2Операторы цикла
Перечень разновидностей операторов цикла:
оператор цикла с предусловием;
оператор цикла с постусловием;
оператор цикла с предусловием и коррекцией. Синтаксис оператора цикла с предусловием:
while (выражение) оператор
(элемент "оператор" может быть пустым оператором, оператором-выражением или операторным блоком). Смысл оператора: на каждой итерации цикла предварительно проверяется условие продолжения цикла - ненулевое значение "выражения", затем выполняется "оператор". Элемент "оператор" может включать любое количество управляющих операторов, связанных с конструкцией while:
53
continue - переход к следующей итерации цикла; break - выход из цикла.
Примеры записи:
while (i>0) i<<=1, j++;
while (printf("\n n-?"), scahf(" %d",&n));
...
while (1) { /* Организация бесконечного цикла */ /* ... */
if (kbhit()&&(getch()==27)) break; /* Выход по ESC */ /* ... */
}
while (!kbhit()); /* Активное ожидание нажатия клавиши */
Синтаксис оператора цикла с постусловием:
do оператор while (выражение);
(элемент "оператор" может быть пустым оператором, оператором выражением или операторным блоком). Смысл оператора: на каждой итерации цикла предварительно выполняется "оператор", затем проверяется условие продолжения цикла - ненулевое значение "выражения". Назначение используемых в элементе "оператор" управляющих операторов continue и break совпадает с ранее рассмотренным, но оператор continue вызывает переход к этапу оценки "выражения".
do printf("\n ???");
while (!scanf(" %d",&n));
...
float *x; int i=0;
...
m=coreleft()/sizeof(*x); do {
printf("\n n-?");
if (!scanf(" %d",&n)) { sound(300);
printf(" Вводите цифры !"); continue;
}
if (n>m) continue;
if (!scanf(" %f",x+i)) break; } while (++i<n);
Синтаксис оператора цикла с предусловием и коррекцией:
for (инициализация; условие_выполнения; коррекция) оператор
Здесь "инициализация", "условие_выполнения" и "коррекция" выражения, которые могут отсутствовать (пустые выражения), но символы ';' опускать нельзя. Оператор-выражение "инициализация" выполняется один раз перед
54
началом итераций цикла. Итерации цикла продолжаются, пока истинно "условие_выполнения" - выражение пустое либо непустое выражение отлично от нуля. На каждой итерации последовательно выполняются "оператор" и оператор-выражение "коррекция". Назначение используемых в элементе "оператор" управляющих операторов continue и break совпадает с ранее рассмотренным.
float x[10], y; int i,n;
...
for (i=n=sizeof(x)/sizeof(*x); i>0; x[--i]=0);
...
for (i=0; i<n; x[i++]=0);
for (i=0; i<n; i++) x[i]=0;
...
for (i=0, i=0; i<n; i++)
if (x[i]<0) y+=x[i];
...
Различные формы операторов цикла могут выражаться друг через друга, например:
а) оператор
for (инициализация; условие_выполнения; коррекция) оператор
эквивалентен последовательности операторов
инициализация;
while (условие_выполнения) { оператор; коррекция;
}
(здесь "оператор" не может включать операторы break или continue); б) оператор
for (; условие_выполнения;) оператор
эквивалентен оператору
while (условие_выполнения) оператор;
в) оператор
for (оператор; условие_выполнения;) оператор
эквивалентен оператору
do оператор while (условие_выполнения);
г) оператор
for (;;) оператор
55
эквивалентен оператору
while (1) оператор;
(вместо 1 здесь может быть любое число, отличное от нуля).
При использовании вложенных циклов следует учитывать, что управляющие операторы break и continue действуют внутри собственного цикла. Для выхода из вложенного цикла приходится использовать оператор
безусловного перехода goto [1]:
float x[10][20]; int i,j;
/* Проверка наличия отрицательных значений */
for (i=0; i<10; i++) for (j=0; j<20; j++)
if (x[i][j]<0) goto next_step;
next_step: printf("\nЭлемент (%d,%d) отрицателен...");
1.4.3 Оператор выбора альтернатив (переключатель)
Синтаксис:
switch (выражение) { ------------------------------------ |
|
case константа_1: оператор_1 |
Тело |
case константа_2: оператор_2 |
оператора |
... |
switch |
default: оператор_N |
|
} ------------------------------------------------------ |
|
Ключевое слово default и целочисленные значения констант рассматриваются как специальные метки операторов, область действия которых - тело оператора switch. Порядок следования таких меток не регламентирован. Целочисленное выражение сравнивается после вычис ления со значениями констант-меток. При совпадении с одной из них выполняется передача управления соответствующему оператору в теле оператора switch. В случае несовпадения значения выражения с одной из констант - переход на метку default либо, при ее отсутствии, к оператору, следующему за оператором switch. Упомянутые здесь специальные метки в теле оператора switch недолжны повторяться или использоваться для ссылок в операторе goto. Для выхода из тела оператора switch используют управляющий оператор break (дополнительно можно воспользоваться операторами goto или return, а при вложенности в оператор цикла и оператором continue). Рассмотрим пример построения
56
простейшего калькулятора для вычисления значений функций sin(), cos(), log(), sqrt(), tan().
#include <stdio.h> #include <math.h> #include <conio.h<
char f[]="\n %s(%lf)=%lf";
void main() { double x;
while (sound(1000), printf("\n x-? "), nosound(), scanf("%lf",&x)) {
for (;;) {
printf("\n x=%lf, Sin, Cos, Log, sQrt, Tan - ? ",x); switch(getch()) {
case 27 : goto cont; /* 27 - код клавиши ESC */ case 's':
case 'S': printf(f,"sin",x,sin(x)); break;
case 'c':
case 'C': printf(f,"cos",x,cos(x)); break;
case 'l':
case 'L': printf(f,"log",x,log(x)); break;
case 'q':
case 'Q': printf(f,"sqrt",x,sqrt(x)); break;
case 't':
case 'T': printf(f,"tan",x,tan(x)); break;
default: sound(100);
printf("\n Select Sin, Cos, Log, sQrt, Tan or ESC"); nosound();
}
}
cont:;
}
}
Очевидно, что здесь оператор switch можно заменить вложенными условными операторами:
int i;
...
i=getch();
if ((i=='s')||(i=='S')) printf(f,"sin",x,sin(x)); else if ((i=='c')||(i=='C')) printf(f,"cos",x,cos(x));
...
57
else if ((i=='t')||(i=='T')) printf(f,"tan",x,tan(x)); else {
sound(100); printf ...
nosound();
}
В последнем варианте используется последовательная проверка условий, его вычислительная сложность 6/2 (половина количества альтернатив). Оператор switch реализуется переходом по адресу, выбираемому из инвертированной таблицы меток по значению выражения, поэтому его вычислительная сложность близка к единице [1].
1.4.4 Операторы передачи управления
Формально к операторам передачи управления относятся: а) оператор безусловного перехода
goto метка;
б) оператор перехода к следующему шагу (итерации) цикла
continue;
(игнорирование оставшихся операторов тела цикла); в) выход из цикла либо оператора switch
break;
(передача управления следующему оператору); г) оператор возврата их функции
return;
return выражение;
(прекращение выполнения текущей функции и возврат управления вызвавшей программе с передачей, при необходимости, значения выражения).
Операторы вида a...в рассматривались ранее. Оператор return обязательно необходим в функциях, возвращающих значения. В функциях, не возвращающих результат, он неявно присутствует после последнего оператора. Значение "выражения" при необходимости будет преобразовано к типу возвращаемого функцией значения.
void error(void *x, int n) {
if (!x) printf("\nМассив не создан"); if (!n) printf("\nМассив пустой");
}
float estim(float *x, int n) { int i;
58
float y;
if ((!x)||(!n) { error(x,n); return 0;
}
for (y=i=0; i<n; i++) y+=x[i];
return y/n;
}
Строго говоря, в языке C имеются дополнительные возможности передачи управления:
нелокальный переход, организуемый парой функций longjump и setjump;
операторы структурного управления исключениями _try/_except и _try/finally [1].
1.5 СТРУКТУРИЗАЦИЯ ПРОГРАММ И ДАННЫХ
1.5.1Области действия объектов программ
Вязыке С можно выделить два уровня детализации модуля программы: файл исходного текста и функцию. Файл исходного текста может включать определения данных и функций. Операционные объекты, кроме атрибута типа, имеют атрибуты области действия и класса памяти. По области действия
разделяют объекты:
глобальные - доступны во всех функциях файла исходного текста;локальные - доступны только в теле функции или операторного блока.
Вязыке С нет ключевого слова, указывающего область действия объекта. Область действия определяется местоположением оператора описания объекта в файле исходного текста программы (любой объект полностью описывается в одном операторе).
Структура исходного текста программ на языке С
----------------------------------------- |
|
|
|
------------------ |
¦ |
Описание глобальных объектов |
|
¦ |
|
----------------------------------------- |
|
|||
----------------------------------------- |
|
|||
¦ |
Заголовок функции { |
|
¦ |
|
¦ |
|
|
¦ |
Директивы |
¦ |
---------------------------------- |
|
¦ |
|
¦ |
¦ Описание локальных объектов |
¦ |
¦ |
препроцессора |
¦ |
---------------------------------- |
|
¦ |
|
¦ |
---------------------------------- |
|
¦ |
и макрокоманды |
¦ |
¦ Операторы |
¦ |
¦ |
|
¦ |
---------------------------------- |
|
¦ |
|
¦ |
|
|
¦ |
|
¦ |
} |
|
¦ |
|
----------------------------------------- |
|
|
|
------------------ |
59
Файл исходного текста может включать любое количество определений функций и(или) глобальных данных. Параметры функции являются локальными объектами и должны отличаться по именам от используемых в теле функции глобальных объектов. Локальные объекты, описанные в теле функции, имеют приоритет перед объектами, описанными вне функции:
int n; |
/* Глобальное n */ |
void main (int n, char **l) { int i;
/* ... */ f1(i); /* ... */ f2(n);
}
f1(int i) { /* ... */ i=n;
/* ... */
}
f2(int n) { int i;
/* ... */ i=n;
/* ... */
}
Локальные объекты в программах на языке С можно декларировать в начале любого операторного блока, а операторный блок тела функции - частный случай такого правила (в языке С++ оператор декларации может размещаться в любом месте операторного блока). В любом месте файла исходного текста можно ссылаться на глобальные объекты, определенные ниже в остатке текущего файла или в других файлах. Для этого необходимо описать тип объекта и добавить к описанию ключевое слово extern. Описания функций подразумевают атрибут extern по умолчанию. Разрешается опускать длину внешних одномерных массивов, но операция sizeof к таким массивам становится бессмысленной. Следует учитывать, что любой оператор описания действует только на остаток файла исходного текста [1].
1.5.2 Классы памяти объектов программ
Классы памяти объектов в языке C:
статическая память - распределяется на этапе трансляции и заполняется по умолчанию нулями;
60
