ЛЕКЦИИ И МАТЕРИАЛ ДЛЯ ЭЭБ и ИСИТвЭ / Методичка по С
.pdfКаждое условное выражение проверяется: истинно оно или ложно, т. е. каждое условное выражение, при своем выполнении, принимает значение “истинно” (“true”) или “ ложно” (“false”). В языке С нет логического типа данных. Поэтому результатом логического выражения является целочисленное значение. В языке С “ истинно” – это ненулевая величина, “ ложно” – это нуль. В большинстве случаев в качестве ненулевой величины используется единица. Рассмотрим пример
#include < stdio.h > /* Пример 8 */ main()
{
int tr, fal;
tr=(99<100); /* выражение истинно */ fal=(100>101); /* выражение ложно */ printf(“true - %d false - %d\n”,tr,fal);
}
Логические операции в языке С соответствуют классическим логическим операциям AND(&&), OR(||) и NOT(!), а их результат приводится в табл. 2.4 .
|
|
|
|
|
Таблица 2.4 |
|
Логические операции и их результат |
|
|||
|
|
|
|
|
|
X |
Y |
X AND Y |
X OR Y |
NOT X |
X XOR Y |
|
|
|
|
|
|
0 |
0 |
0 |
0 |
1 |
0 |
|
|
|
|
|
|
1 |
0 |
0 |
1 |
0 |
1 |
|
|
|
|
|
|
X |
Y |
X AND Y |
X OR Y |
NOT X |
X XOR Y |
|
|
|
|
|
|
0 |
1 |
0 |
1 |
1 |
1 |
|
|
|
|
|
|
1 |
1 |
1 |
1 |
0 |
0 |
|
|
|
|
|
|
Операция XOR называется операцией “исключающее или”. В языке С нет знака логической операции XOR, хотя она может быть реализована с помощью операций AND, OR, NOT. Далее будут рассмотрены побитовые операции, среди которых операция “исключающее или” уже есть.
Операции отношения и логические операции имеют более низкий приоритет, чем арифметические операции. Старшинство логических операций и операций отношения следующие:
21
!
> < >= <= == !=
&&
||
Влогических выражениях также можно использовать круглые скобки, которые имеют наивысший приоритет. Кроме того, использование круглых скобок позволяет сделать логические выражения более понятными и удобными при чтении текста программ. Условные и логические выражения, чаще всего, используются в управляющих операторах языка С, речь о которых пойдет далее.
Операция присваивания. Операция присваивания обозначается знаком = , и используется для реализации оператора присваивания. В отличие от других языков в языке С оператор присваивания может использоваться “внутри” различных управляющих операторов, речь о которых пойдет далее.
Вфрагменте If ((c=a-b)<0) printf (“число а меньше чем b“) сначала вычисляется величина a-b, которая присваивается переменной c, затем сравнивается ее значение с нулем. Кроме того, в языке С имется возможность многократного присваивания, например: a=b=c=x+y. Здесь сначала вычисляется значение x+y, затем оно присваивается переменной c, потом b, и лишь затем a. В левой части оператора присваивания должно стоять выражение, которому можно присвоить значение. Такое выражение в языке С, например просто переменная, называется величиной lvalue. Выражение 3 = 3 ошибочно, так как константе нельзя присвоить никакое значение: константа не является величиной lvalue.
Вязыке С имеются дополнительные операции присваивания +=, -=, /=, *=, %=.
Вместо выражения a=a+7 можно использовать выражение a+=7. Здесь += аддитивная операция присваивания, в результате выполнения которой величина, стоящая справа, прибавляется к значению переменной, стоящей слева. Аналогично выполняются остальные дополнительные операции присваивания.
Дополнительные операции присваивания имеют тот же приоритет, что и операция =, т. е. ниже, чем приоритет арифметических операций. Необходимо отметить, что операция a+=7 выполняется быстрее, чем операция а=а+7.
22
Поразрядные операции (побитовые операции ). Поразрядные операции проводятся с любыми целочисленными переменными и константами. Нельзя использовать эти операции с переменными типа float, double, long double. Результатом побитовой операции будет целочисленное значение.
Поразрядными (побитовыми) операциями являются
&AND,
|OR,
^XOR,
~NOT,
<< сдвиг влево,
>>сдвиг вправо.
Операции AND, OR, NOT и XOR нам уже известны, они аналогичны соответствующим логическим операциям. Только в этом случае сравниваются значения соответствующей пары битов, а не значения выражений.
Поразрядные операции позволяют обеспечить доступ к отдельным битам информации и поэтому часто используются в программах кодирования и декодирования информации, различных драйверах.
При выполнении поразрядной операции над двумя переменными, например типа char, операция производится над каждой парой соответствующих разрядов(битов). Отличие поразрядных операций от логических и операций отношения состоит в том, что логические операции и операции отношения всегда в результате дают 0 или 1. Для поразрядных операций это не так. Приведем ряд примеров:
1) ‘A’ |
11000001 |
2) ‘A’ |
11000001 |
127 |
01111111 |
128 |
10000000 |
‘A’&127 |
01000001 |
‘A’| 128 |
11000001 |
Поразрядные операции удобны для хранения информации в сжатом виде, например о состоянии некоторого объекта. Значение каждого бита ( 0 или 1) можно интерпретировать как “отсутствие/присутствие” или “включен/выключен”. В каждом байте можно хранить 8 таких флагов. Если переменная ch является хранилищем таких флагов, то определить значение четвертого бита можно следующим образом:
If ( ch & 8 ) printf(“4 бит содержит 1”);
23
Эта проверка основывается на двоичном представлении числа 8=00001000.
Операции сдвига << и >> применимы только к целочисленным переменным. В результате применения этих операций сдвигаются все биты левого операнда на число позиций, определяемого выражением справа от знака операции влево или вправо. Форма этих операций следующая:
value << число позиций value >> число позиций.
Пример: двоичное представление числа x=9: 00001001, тогда x=9<<3 01001000
x=9>>3 00000001 x=9>>5 00000000
Применение операций сдвига может приводить к потере младших или старших байтов. Применение операций << и >> по очереди к одной и той же переменной может изменить значение этой переменной из-за потери разрядов.
Поразрядные операции порождают еще несколько сложных операций присваивания: |=, &=, ^=, <<=, >>=.
Операции ( ) и [ ]. В языке С круглые и квадратные скобки также рассматриваются как операции. Причем эти операции имеют высший приоритет.
Операция условие? Операция условие – единственная операция языка С, имеющая три операнда. Эта операция имеет вид
( выр1 )?(выр2):(выр3)
Вычисляется выражение (выр1). Если это выражение имеет ненулевое значение, то вычисляется выражение (выр2), и оно будет результатом выполнением операции. Если значение выражения (выр1) равно нулю, то вычисляется значение выражения (выр3) и его значение будет результатом операции. В любом случае вычисляется только одно из выражений: (выр2) и (выр3). Например, операцию условие удобно применять для нахождения наибольшего из двух чисел a и b
max=(a>b)?a:b;
или для нахождения абсолютной величины числа a abs=(a>0)?a:-a;
Если второй и третий операнды являются величинами типа lvalue, т. е. могут стоять в левой части операции присваивания, то и результат операции условие является величиной типа lvalue. С помощью этой
24
операции можно просто решить такую задачу: найти наибольшее из двух чисел заменить его на единицу:
(a>b)?a:b=1;
Операция запятая. Операция запятая имеет самый низкий приоритет из всех операций языка С. Она выполняется слева направо, и ее значением является значение правого операнда. В выражении (выр1), (выр2) сначала вычисляется значение (выр1), а затем – значение (выр2). Это значение и будет результатом операции.
Операция sizeof.. Операция sizeof имеет две формы: sizeof(тип) или sizeof(выражение). Результатом этой операции является целочисленная величина типа или выражения в байтах. При использовании второй формы значение самого выражения не вычисляется, а лишь определяется его тип. Примеры использования: sizeof( double ) или sizeof( a ). В качестве типа в операции sizeof не может использоваться тип void.
В дальнейшем покажем, что ряд операций в языке С имеют двойное назначение, например операция &. Кроме того операции . и -> рассмотрим позднее.
2.7. Выражения
Выражения в языке С – это некоторая допустимая комбинация переменных, констант и операций. Каждое выражение принимает какое-либо значение. В выражениях языка С допустимо смешение переменных разного типа. Правила языка С, которые используются для автоматического приведения типов при вычислении арифметического выражения, следующие:
1.Все переменные типа char и short int преобразуются в int, все переменные типа float преобразуются в double.
2.Для любой пары операндов, если один из операндов long double, то и другой преобразуется в long double; если один из операндов double, то и другой преобразуется в double; если один из операндов long, то и другой преобразуется в long; если один из операндов unsigned, то и другой преобразуется в unsigned.
3.В операторе присваивания конечный результат приводится к типу переменной в левой части оператора присваивания, при этом тип может как повышаться так и понижаться.
Тип результата вычисления выражения можно изменить, используя конструкцию “приведение”, имеющую следующий вид:
( тип ) выражение
25
Здесь “тип” – один из стандартных типов данных. Например, если необходимо сделать результат деления переменной a типа int на 2 типом float, надо записать ( float ) a/2. Значение выражения (float) (a/2) будет другим, чем в первом случае. Это связано с тем, что в первом случае приведение типа применялось к переменной а, а во втором случае – к результату вычисления выражения в круглых скобках а/2.
Пробелы и круглые скобки в выражениях расставляются так как необходимо программисту. При компиляции лишние пробелы просто игнорируются.
26
3.ОПЕРАТОРЫ
3.1.Условный оператор
Основная форма условного оператора выглядит следующим образом: if ( условие ) оператор;
else оператор;
Если значение условия “ истинно”, то выполняется оператор (им может быть составной оператор), следующий за условием. Если же условие принимает значение “ ложно” то выполняется оператор, следующий за словом else. В записи оператора if вторая часть (т. е. оператор else) может отсутствовать. Тогда, если условие принимает значение “ ложно”, выполняется следующий оператор программы. В качестве условия может стоять произвольное выражение. В операторе if лишь проверяется, является ли значение этого выражения ненулевым (истинным) или нулевым (ложным). Рассмотрим пример программы определения знака вводимого с клавиатуры вещественного числа с использованием оператора if
# include < stdio.h > /* Пример 9 */ main()
{
int sgn; float x;
printf (“ Введите число “); scanf (“%f”,&x);
if ( x>0 )
{sgn=1; printf(“Число %f положительное sgn = %d\n”,x,sgn); } if ( x==0 )
{sgn=0; printf(“Число %f равно нулю sgn = %d\n”,x,sgn);}
if ( x<0 ) { sgn=-1; printf(“Число %f отрицательное sgn =%d\n”,x,sgn);
}
}
27
Часто встречается необходимость использовать конструкцию if-else-if: if ( условие1 ) оператор1;
else if ( условие2) оператор2; else if( условие3) оператор3;
…
else оператор;
В такой форме условия оператора if проверяются сверху вниз. Как только некоторое условие принимает значение “ истинно”, выполняется оператор, следующий за этим условием, а вся остальная часть конструкции будет проигнорирована. Поэтому, предыдущую программу можно было бы написать следующим образом:
# include < stdio.h > /* Пример 10 */ main()
{
int sgn; float x;
printf(“ Введите число “); scanf(“%f”,&x);
if ( x>0 ) { sgn=1; printf(“Число %f положительное sgn = %d\n”,x,sgn); }
else if (x<0) {sgn=-1; printf(“Число %f отрицательное sgn = %d\n”,x,sgn); }
else { sgn=0; printf(“Число %f равно нулю sgn = %d\n”,x,sgn);
}
}
Для того чтобы проверить, равно число х нулю или не равно, можно написать
if ( x==0 ) printf(“ Число равно нулю ”); else printf(“ Число не равно нулю ”);
Такой же результат можно получить, написав if ( !x ) printf(“ Число равно нулю ”); else printf(“ Число не равно нулю ”);
Вложенным оператором if называется конструкция вида if( x )
if( y ) оператор1; else оператор2;
28
Втакой форме непонятно, к какому из операторов if относится else.
Вязыке С оператор else ассоциируется с ближайшим if в соответствующем блоке. Поэтому в указанной конструкции else относится к if( y ). Для того чтобы отнести else к if( x), необходимо соответствующим образом расставить операторные скобки:
if( x ){
if( y ) оператор1;
}
else оператор2;
Теперь if( y ) относится к другому блоку.
3.2. Оператор множественного выбора
Язык С имеет встроенный оператор множественного выбора, называемый switch. Основная форма оператора имеет вид
/* Пример 11 */ switch ( выражение ) { case constant1:
последовательность операторов break;
switch ( выражение ) { case constant2:
последовательность операторов break;
…
switch ( выражение ) { case constantN:
последовательность операторов break;
default
последовательность операторов
}
Сначала вычисляется выражение в скобках за ключевым словом switch. Затем просматривается список меток ( case constant1 и т. д. ) до тех пор, пока не найдется метка, соответствующая значению вычисленного выражения. Далее происходит выполнение последовательности операторов, следующих за двоеточием. Если же значение выражения не соот-
29
ветствует ни одной из меток оператора switch, то выполняется последовательность операторов, следующих за ключевым словом default.
Допускается конструкция оператора switch, когда слово default и соответствующая последовательность операторов может отсутствовать.
Еще один не встречавшийся ранее оператор – break. Когда после последовательности операторов встречается ключевое слово break, то выполнение оператора break приводит к выходу из оператора switch и переходу к следующему оператору программы. Наличие оператора break в операторе switch необязательно. Оператор break заканчивает последовательность операторов, относящихся к каждой метке. Если же оператор break отсутствует, то выполнение switch продолжается до первого встретившегося break либо до конца самого оператора switch. Рассмотрим две программы с использованием оператора break и без него:
# include < stdio.h > /* Пример 12 */ main()
{
char ch;
printf(“ Введите заглавную букву русского алфавита ”); ch=getchar();
if ( ch >= ‘А’ && ch <=’Я’) switch (ch)
{
case ‘А’: printf(“Андреев\n”); break;
case ‘Б’: printf(“Булгаков\n”); break;
case ‘В’: printf(“Волошин\n”); break;
case ‘Г’: printf(“Гоголь\n”); break;
default:
printf(“Достоевский, Зощенко и другие \n”); break;
30
