БИЛЕТ 22.
1) Старшинство и порядок выполнения операций
При вычислении выражения, операции выполняются в порядке убывания их приоритетов. Все, кроме присваивания, выполняются слева направо. Операция присваивания справа налево. Порядок выполнения равноприоритетных операций не определен. Компилятор организует вычисление подвыражения в том порядке, в котором он считает наиболее эффективным. Это может вызвать побочные эффекты.
Примеры.
1) a=f()+g()
Если функции f и g используют глобальные переменные и меняют их, то результат a будет зависеть от того, в каком порядке они будут вызваны.
2) f(v[i], i++);
порядок вычисления аргументов неопределен.
3) a/(b*d)
Выражение включает в себя коммутативные и ассоциативные операции, могут быть реорганизованы компилятором произвольным образом, даже при наличии скобок.
Рекомендации:
1) уровень старшинства побитовых операций & ^ || ниже, чем уровень операции == и !=. В условиях, осуществляющих побитовую проверку, выражения должны заключаться в скобки.
2) т.к. нефиксирован порядок выполнения равноприоритетных операций, то в ситуации, когда две или более функции используют и изменяют глобальные переменные, задавайте порядок их вызова, явно используя дополнительные переменные.
a=f();
b=g();
c=a+b;
Все логические операции младше арифметических, поэтому скобки могут опускаться. a*b+c<3
Логические связки && || вычисляются слева направо с учетом приоритета скобок. При это их рассмотрение прекращается сразу же, как только становится ясно будет ли результат истинным или ложным.
Старшинство операций сравнения == и != выше, чем у операции присваивания, которая имеет один из самых низких приоритетов.
Название |
Символ операции |
Порядок выполнения |
Обращение к функции Выделение элемента массива Выделение поля структурной переменной Выделение поля структурной переменной по указателю на ее начало |
( ) [ ] . -> |
Слева направо То же То же То же
|
Логическое отрицание Поразрядное логическое НЕ Изменение знака (унарный минус) Инкремент Декремент Определение адреса переменной Обращение к памяти по значению указателя Преобразование к типу Определение размера в байтах |
! ~ - ++ -- & * (type) sizeof |
Справа налево То же То же То же То же То же То же То же То же |
Умножение Деление Определение остатка целого деления |
* / % |
Слева направо То же То же |
Сложение Вычитание |
+ - |
Слева направо То же |
Сдвиг влево Сдвиг вправо |
<< >> |
Слева направо То же |
Меньше Меньше или равно Больше Больше или равно |
< <= > >= |
Слева направо То же То же То же |
Равно Не равно |
= = != |
Слева направо То же |
Поразрядное логическое И |
& |
Слева направо |
Поразрядное исключающее ИЛИ (XOR) |
^ |
Слева направо |
Поразрядное логическое ИЛИ |
| |
Слева направо |
Логическое И |
&& |
Слева направо |
Логическое ИЛИ |
|| |
Слева направо |
Операция условия |
?: |
Справа налево |
Присваивание |
= += -+ *= /= %= <<= >>= |= ^= &= |
Справа налево |
Операция «запятая» |
, |
Слева направо |
2) Директивы препроцессора.
При каждом запуске компилятора сначала запускается препроцессор, который выполняет директивы начинающиеся с символа #. При выполнении этих команд создается временный файл исходного кода, с которым уже работает компилятор.
Директивы препроцессора:
#include
#define
#undef
#if
#else
#endif
#ifdef (#if defined)
#ifndef (#if !defined)
#error
#line
#pragma
Директива #include
Строка
#include "имя. файла "
заменяет эту строку полным содержимым файла имя. файла. Если не указан путь то файл сначала ищется в директории исходного файла, затем в директории заданной в опциях компилятора(обычно директория Include).
Строка
#include <имя. файла>
ищет файл только в директории заданной в опциях компилятора.
Директива #define
#define идентификатор строка символов
заменяет все последующие вхождения идентификатора строкой символов.
пример:
#define A_NUMBER 100
int n=A_NUMBER ;
n присвоится значение 100
#define можно применять также для определения макросов,например
#define SWAP(a,b) temp=(a);(a)=(b);(b)=temp
подробнее о #define (и в частности о макросах) будет отдельная статья
Директива #undef
строка
#undef идентификатор
отменяет прероцессорное определение идентификатора
Директивы #if #else #endif
директива
#if выражение
.....
#endif
проверяет истинно ли выражение и если истинно, то выполняет все последующие строки до директивы #endif
конструкция типа
#if выражение
....
#else
...
#endif
проверяет выражение, если оно истинно то выполняются строки между #if и #else а если ложно то между #else и #endif
Директивы #ifdef #ifndef
директива #ifdef идентификатор
.....
#endif
проверяет определен ли идентификатор в препроцессоре в данный момент(директивой #define) и если определен, то выполняет все последующие строки до директивы #endif
директива #ifndef идентификатор
.....
#endif
наоборот, выполняет все последующие строки до директивы #endif если идентификатор не определен в препроцессоре в данный момент
Директива #error
Директива #error сообщение об ошибке
останавливает работу компилятора и выдает сообщение об ошибке .
Директива #line
Директива #line константа "имя. файла”
заставляет компилятор считать, что константа задает номер следующей строки исходного файла, и текущий входной файл именуется идентификатором. Если идентификатор отсутствует, то запомненное имя файла не изменяется.
Директива #pragma
#pragma - это директива препроцессора, которая реализует возможности компилятора. Эти особенности могут быть связанны с типом компилятора.Разные типы компиляторов могут поддерживать разные директивы. Общий вид директивы:
#pragma команда компилятора
*************************************22 - 3
Написать программу, которая вычисляет интервал между двумя датами.
#include<stdio.h>
#include<conio.h>
int day1=18,mon1=2,year1=1977;
int day2=19,mon2=3,year2=1977;
int d_rez,m_rez,y_rez,more,i;
void main()
{
clrscr();
y_rez = year2 - year1;
if (y_rez == 0)
m_rez = mon2 - mon1;
else
m_rez = 12 - mon1 + mon2;
if (m_rez == 0)
d_rez = day1 + day2 - 1;
else
{
if (mon1 == 1 || mon1 == 3 || mon1 == 5 ||mon1 == 7 || mon1 == 8 || mon1 == 10 || mon1 == 12)
d_rez = 31 - day1 + day2;
else
d_rez = 30 - day1 + day2;
}
if (d_rez >= 30)
{
if (mon1 == 1 || mon1 == 3 || mon1 == 5 ||mon1 == 7 || mon1 == 8 || mon1 == 10 || mon1 == 12)
{
d_rez -= 31;
more = d_rez/m_rez;
}
else
{
d_rez -= 30;
more = d_rez%m_rez; //HERE
}
if (more == 0)
more = 1;
m_rez += more;
}
while (m_rez >= 12)
{
m_rez -= 12;
y_rez += 1;
}
m_rez -= 1;
if (y_rez > 0)
y_rez -= 1;
for (i=year1;i<year2;i++)
if((i%4 == 0) && (i%100 != 0))
d_rez++;
if((mon1<=2)&(mon2>=2))
d_rez -= 2*y_rez;
if (d_rez < 0)
for(i=0;d_rez<0;i++)
{
d_rez += 30;
y_rez++;
}
printf("%d days, %d month(es) and %d year(s) latter...",d_rez,m_rez,y_rez);
getch();
}
*************************************22 - 4
Написать программу, которая по введенному с клавиатуры символу печатает его код. Программа заканчивает работу, если введенный символ- точка.
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
char*a;
do{
printf("Enter symbol");
gets(a);
printf("%d ",*a);
printf("\n");
}while(*a!='.');
getch();
}