Вы находитесь на странице: 1из 85

ЯЗЫ К

ПР ОГРАММИР ОВА НИЯ


С/С+ +
1.Структура программы на Си/Си++

Программа на языке Си/Си++ обычно состоит из одной или нескольких функций


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

{
<Список описаний>
<Список операторов> (1)
}
В формуле (1), если отсутствует тип значений функции, то по
умолчанию используется int. Конструкция в [] может присутствовать
или отсутствовать.
Список описаний и список операторов – это последовательность
операторов языка Си. Каждый оператор Си завершается ; (хотя в
некоторых случаях синтаксис этого не требует). Встречаются
ситуации, когда в программе отсутствует – ; и нет предупреждения
транслятора.
Каждый оператор в свою очередь – это последовательность более
мелких единиц программы – «лексем».
Лексема – минимальная единица программы, наделенная смыслом.
В Си множество лексем разбито на группы:
1. Ключевые слова - зарезервированы (выделены жирным шрифтом).
2. Символы – разделители ( , ; < > ).
3. Идентификаторы – последовательность латинских букв и цифр,
начинающаяся с буквы (в этой последовательности можно использовать -).
Длина меньше или равна 16 или 32. Строчные и прописные буквы
различаются, Константы записываются большими, переменные маленькими
буквами.
4. Константы.
5. Комментарии.
6. Невидимые символы (перевод строки и т.д.).
Комментарий является разделителем лексем, он допускается в любом
месте, где разрешено использовать пробел . В Си длина одной строки
программы не определена. Практически она реализуется длиной
строки редактора. Строковую константу языка Си нельзя переносить
на другую строку. Невидимые символы – это, большей частью,
символы редактирования, такие как пробел, табуляция, возврат
каретки, конец файла ( вставляется редактором). Обязательно
следует разделять между собой пары лексем из 1ой и 3ей групп.
Любой оператор языка Си может начинаться с любой позиции любой
строки. Ни одна лексема, кроме комментариев (только для Си) не
может продолжаться на следующей строке. Там где уместен пробел,
можно записать комментарий или любую последовательность
невидимых символов.
Тело функции (1) состоит из двух списков: список описаний (операторы
описания) и список операторов описывающий действия ( операторы действий).
Рассмотрим синтаксис и семантику операторов действия (=> - это):
Список операторов => Оператор (2.1)
=> Оператор Список операторов (2.2)

Оператор => Составной оператор (3.1)


=> Выражение; (3.2)

=> if (выражение) Оператор (3.3)

=>if (выражение) Оператор


else Оператор (3.4)

=> while (выражение) Оператор (3.5)


=>do Оператор while (выражение) (3.6)

=> for ([выражение 1]; [выражение2]; [выражение3])


Оператор (3.7)

=>switch (выражение)
{
сase константное выражение 1: Оператор1

case константное выражение n: Оператор n
default: Оператор1
} (3.8)
=> break; (3.9)
=>continue; (3.10)
=> return; (3.11)
=> return выражение; (3.12)
=> goto Метка; (3.13)
=> Метка: Оператор (3.14)
=> ; (3.15)
Метка => Идентификатор
(3.16)
Оператор1 => пусто
=> Список операторов (3.17)
Составной оператор => { [Список описаний]
[Список операторов]
} (4).
Из формул (2.1), (2.2) следует, что Список операторов состоит из
одного или нескольких Операторов действия. Из формул (3.1) и (4) –
совокупность Операторов описания и Операторов действия
заключенная в фигурные скобки есть Составной оператор, который
принято считать одним Оператором действия. Составной оператор и
Операторы (3.3) – (3.8) имеют не тривиальную
структуру(конструкторы), а Операторы (3.2) и (3.9) – (3.15) можно
отнести к элементарным.
3.Семантика операторов - конструкторов

Оператор (3.3) – называют неполным условным, который имеет


единственную ветвь, которая выполняется тогда и только тогда, когда
значение выражения оператора не равно нулю.
Оператор (3.4) – называют полным условным, если значение
выражения оператора не равно нулю, то выполняется оператор первой
ветви, иначе – оператор второй ветви.
3.1. Операторы цикла

Оператор (3.5) – называют оператором цикла с предусловием.


Перед выполнением оператора тела-цикла вычисляется выражение,
если его значение не равно нулю, то выполняется тело цикла и вновь
вычисляется выражение. Этот процесс длиться до тех пор, пока значение
выражения не станет равным нулю. Если равенство нулю не достигается в
процессе работы цикла, то имеем бесконечны цикл. Если значение выражения
равно нулю при первом вычислении, то тело цикла не выполняется.
Оператор (3.6) – называется оператором цикла с постусловием.
В начале выполняется оператор тела-цикла, только затем вычисление
выражения. Тело цикла выполняется повторно пока значение выражения не
равно нулю.
Оператор (3.7) – называется оператором цикла типа арифметической
прогрессии.
В этом операторе в круглых скобках три выражения, образующих заголовок
цикла, каждое выражение заканчивается «;», но что самое интересное, каждое
выражение может отсутствовать.
Если в наличии три выражения, то семантика цикла эквивалентна семантике
следующего фрагмента функции:

Выражение1;
while (Выражение2)
{оператор
Выражение3 ; (5)
}
Если отсутствует первое и третье выражение, то семантика оператора цикла
задана формулой (5), в которой опущены операторы выражение1 и выражение 3,
если отсутствует выражение2, то вместо него по умолчанию используется
константа, равная единице.

3.2.Оператор SWITCH

Замечание к синтаксису:
Вариант default может находиться в любом месте, а не только на последнем.
Семантика:
Вычисляется выражение после switch.
Его значение сравнивается со значениями константных выражений в
порядке их следования. Если ни одно значение в опции case не
совпадает со значением выражения, то если присутствует вариант
default, то выполняется его оператор, иначе – ни один оператор
switch не выполняется. Если значение некоторого константного
выражения совпало со значением выражения, то выполняется
оператор данного варианта.
Если в операторе switch выполнился кокой либо вариант, в том числе
и default, то следующими выполняются все ниже лежащие варианты.
Чтобы обеспечить выполнение только одного варианта нужно
использовать оператор break.
Тип выражения switch – int.
Пример:
int a, b, c ;

if (a= =b)
a+=b;

if (a>b)
{a--; b++;}
else {++a; --b;}

while (c==(a=b))
c=a/b;

do
c/=2;
while(c);

for (a=b; a!=b*b; a+=b)


cout << “значение” <<a;
switch(a)
{
case 5: cout << “a равно b и следовательно” <<b; break;
case 6: cout <<“a равно c и следовательно” <<c; break;
default:
cout << “a не равно а ни b ни с и следовательно ” <<a;
}

В любом языке программирования есть операторы, внутри


которых не допускаются другие операторы. Такие операторы
в языке Си называются элементарными (cout - функция
вывода).
4.Элементарные операторы

Оператор break – прерывает выполнение таких конструкторов как while, do while, for и
switch.

while (1)
{…
if (a==b) break;

}

s=0.0; i=4;
do
if (i) {s=s+1./i; i=i-1;}
else break;
while (s<=a);
s=0.0; i=4;
do
if (i)
s+=1.0/i--;
else
break;
while (s<=a);

do
if (i--)
s+=1.0/i;
else
break;
while(s<=a) ;
for (i=4,s=0; s<=a; s+=1.0/i--)
if(!i) break;

Оператор continue – оператор продолжения тела цикла.


Используется continue внутри тела цикла while, do while, for –
его назначение передать управление на условие цикла, игнорируя
выполнение оставшихся до конца цикла операторов. Фактически
это “goto” без метки.
1) s=0; i=100;
while (s>=a)
if (i>0) s+=1.0/i--;
else if (i==0)
{i=-1; continue;}
else s=1.0/i--;
2)for (;;)
{…
if (a==b) break;

if (a==b) break;

if (a==1) continue; ⌠ [первый пропуск]
… │
if (b==0) continue; │ ⌠ [второй пропуск]
… ⌡ ⌡
}
Оператор return – возврат из функции без передачи значения
имени функции. Он позволяет игнорировать значения функции.
Оператор return выражения – возврат из функции с передачей
значения имени функции. Если функция не содержит данный
оператор, то выход из неё – по достижения конца функции.
Оператор goto метка и помеченный оператор
метка:Оператор применяют редко только в случае
необходимости. Он нужен , если его применение упрощает
программирование не в ущерб ясности. Есть несколько ситуаций,
когда нужен оператор goto.
I) 1a) flag=0;
for (i=1; i<=100; i++)
for (j=1; j<=100; j++)
{ for (k=1; k<=100; k++)
if (a[i] [j] [k])

else {flag=1; break;

if (a[i] [j] [k]); else break;


}

if(flag) cout<<”\n достигнуто нулевое значение”;


1б) flag=0;
for (i=1; i<=100; i++)
for (j=1; j<=100; j++)
for (k=1; k<=100; k++)
if (a[i] [j] [k])

else {flag=1; goto
lable1;}...
label1: if (flag)
cout << “Достигнуто нулевое значение”;
II. Переходы в конец функции:

if (…) goto m1;

if (…) goto m2;

if (…) goto m3;

m1: cout <<“\n выход по ошибке № 1”;
return;
m2: cout <<“\n выход по ошибке № 2”;
return;
m3: cout <<“\n выход по ошибке № 3”;
return;

III.Допускаются переходы в следующие структуры:

…goto M3;

…goto M2;

…gotoM1;

M1: …


M2: …


M3:…
Другие варианты нежелательны, но допускаются. Уместное использование
goto:
1) ясность программы не уменьшается;
2) программа сокращается.
Правильное использование goto- это показатель уровня квалификации
программиста.
Пустой оператор - используется там, где не требуется никаких действий.
for (i=1, s=0.0; i<=100; s+=i*i++);
Других операторов действий в Си нет. Все остальные действия типа:
ввода и вывода, открытия и закрытия файлов, математических операций,
работы со строками - реализованы через соответствующие библиотеки (в
виде библиотек функций или классов).
5.Операция присваивания

<адрес> <операция присваивания> <выражение>


Новый операнд операции(<адрес>) – адрес переменной.
Любая переменная имеет атрибуты: имя, тип значения, тип памяти,
область видимости.
Независимо от того, каким образом выделена память под
переменную, схема связи имени, адреса и значения следующая:
Значение
Х

Адрес имя

b: c: d:
С: Х

<адрес х>
Если левый операнд для операции присваивания выражен именем
переменной, то транслятор понимает это как адрес переменной.
Здесь неявно присутствует операция разыменования (определения
адреса по имени).
Семантика:
1. Вычисляется значение выражения.
2. Вычисляется адрес левого оператора.
3. Выполняется присваивание в зависимости от вида операции.
Операция присваивания => = | += | –+ | *= | /= | %= | >>= | <<= |
&= | ^= | |=
( | - или)
Выражение :
Адрес *= выражение тождественно Адрес = значение
(адрес)*выражение

Примеры:
x=5.3
y*=(x+5); тождественно y=у*(х+5)
у*=х+5; тождественно у=у*х+5

Где & ^ : - поразрядные битовые операции, >> ,<< - операции


сдвигов битов,
+ - * / % - арифметические операции.
6.Арифметические типы

В Си определены четыре базовых типа:


char, int, float, double

char = [-128, 127] – 1б.


int = [-215, 215 -1] – 2б.
float = [10-38, 1038] – 8б.
Хотя эти типы базовые, сказать из каких элементов они состоят
трудно, так как это зависит от реализации. Во многих
компиляторах char и float реализованы по стандартам.
Тип int может быть реализован и в 4 байта, тогда диапазон его
значений следующий: [-231, 231-1].
Существуют квалификаторы типа:
short (короткий), long (длинный),signed (знаковый), unsigned
(беззнаковый)
– применённые к базовым типам, они изменяют их диапазон.
Длина Длина значения ≤ Длина

значения значения

short int int long int


1-2б 2-4б 4-8б
Квалификатор long можно применить и к double → long double.

сhar = [-128, 127] signed short int unsigned short int (от 0 до 216-1)
signed char = [-128, 127] signed int unsigned int (от 0 до 216-1)
unsigned char = [0, 255]. signed long int unsigned long int (от 0 до 232-1)
7.Унарные операции

1.Унарная операция “ –“ - изменение значения на противоположное (имеет


более высокий приоритет, чем бинарные операции).
x3 = –х*х +3* –х;
2.Унарная операция “++” - инкремент
++х; тождественно х=х+1;
х++ ; тождественно х=х+1;
Если же операция используется в выражении, то операция ++х означает
использование х=х+1 в качестве операнда выражения , а х++ - есть значение
х, но до увеличения на 1.
3. Унарная операция “- -“ - декремент – аналог инкремента только
уменьшение на 1.

Чаще всего декремент и инкремент используются для изменения параметров


цикла и индекса массива. Все унарные арифметические операции равноправны,
Пример:
Пусть х=3;
++(х+1); - ошибка (операндом выражение не может быть)
--х++; => -3
но х=4
если х= –х++; то х= – 2.
8.Бинарные операции

Бинарные операции - +, -, *, /, % , где %- деление по модулю,


остальные применяются в обычном смысле.
В бинарных операциях используются два операнда, поэтому здесь
важны их типы.
Операция % - остаток от деления только для целых чисел (int).
Операция * - для int операндов результат – int , для double
операндов – double.
Операция / - для int операндов результат – int (2/3=0), для double
операндов – double.
9.Преобразование типов в арифметических выражениях

а) короткие арифметические типы расширяются: char, short – >


int.
б) существует алгоритм:
если один из операндов double, то результат double,
если один из операндов unsigned long, то результат unsigned long,
если один операнд long int и второй операнд unsigned int, то оба
операнда unsigned long int, иначе
если один из операндов unsigned int, то результат unsigned int,
иначе - int.
Правила умолчания построены так, что бы не терялось значение при
преобразованиях. Во всех остальных случаях следует использовать явное
преобразование :
(тип) унарное выражение , где унарное выражение – конструкция из
последовательности унарных операций над некоторым именем.

функция преобразования имеет аргументы char, int, …, long double
Конструкцию (тип) унарное выражение можно использовать на месте
любого арифметического операнда.
В стандарте нет описания, что происходит, если значение первого типа
после преобразования ко второму не принадлежит последнему. Лучше
использовать явное преобразование.
Пример:
int a, b, c, d;
double x, y, z;
x+=3.5;
z=1/(z*=y*x);
z=z*y*x;
z=1/z;
c=b=a=d;
d*=a/=b+=c;
10.Массивы

Массивы – однородная (однотипная) совокупность конечного числа


элементов, в которой каждый [i]-й элемент строго следует за [i–1]-ым элементом.
(Перенумерованная последовательность однотипных элементов, в которой
элементы строго следуют друг за другом, в порядке возрастания номеров).
Синтаксис:
Тип имя [количество элементов по 1 размерности]… [количество элементов по
k-ой размерности].
[=список элементов инициализации]
В стандарте количество элементов массива не определено.
Ограничение: по каждой размерности количество элементов задается
константным выражением (константы соединенные арифметическими
операциями).
Пример:
double x[10][100];
int y[15][5][4];
char z[10];

Семантика:
Любой массив Си –вектор своих компонентов. Индекс по каждой
размерности начинается с 0.
Z0 Z19

Вектор z.
X0

X1

X9

Двухмерный массив X.
Y0

Y1

Y14

Трехмерный массив Z.
Список инициализации представляет собой последовательность однородных
инициализирующих списков, каждый список заключается в “{}”, и только для
одномерных векторов его список инициализации представлен списком значений.
Элементы списка инициализации отделяются друг от друга запятой.
Примеры:
сhar z [20] = {‘M’, ‘A’, ‘Ш’, ‘A’, ‘_’, ‘К’ ,‘У’, ‘П’, ‘И’, ‘Л’, ‘А’, ‘Ш’, ‘Л’, ‘Я’,
‘П’, ‘К’, ‘У’, ‘_’, ‘!’};
int y [15] [5][4]=
{{{1,1,1,1},{2,2,2,2},{3,3,3,3},{4,4,4,4},{5,5,5,5}},…,{{…},{…},{…},{…},
{75,75,75,75}}};
Не все элементы массива можно инициализировать, но для пропущенного
элемента инициализации его запятая в списке сохраняется, если она (они) не в
конце списка.
int y [10]= {1,2,,,,6,7}-инициализированы первый , второй , шестой и
седьмой элементы. При объявлении массива в [] можно ничего не указывать,
если присутствует список инициализации.
Пример:

Задание - написать подпрограмму реверсирующую значения векторов.

int revers0 (double x [10], double y [10])


{
int i;
for (i=0; i<=9; i++)
y [i]=x [9-i];
}
Можно иначе
int revers1 (double x [ ], double y [ ]) //только для одномерных массивов
{
int i=0;
int Kx,Ky;
Kx=sizeof (x)/sizeof (double)-1 ;
Ky=sizeof (y)/ sizeof (double)-1 ;// операция sizeof определяет размер
памяти в байтах
if (Kx<=Ky)
do y [i++]=x[Kx];
while (Kx--);
else
do y[Ky-i]=x[i];
while (++i<=Ky);
}
Стринговой строкой является стринговая константа «МАША КУПИЛА
ШЛЯПКУ !» . В этой константе 20 литер+ 1 литера – «\0»(признак конца строки),
которая ее завершает.
М А Ш А \0

В памяти .
Принципиально структура памяти для массива z=[20] и стринговой константы
одна и та же – последовательность смежных байтов. И то и другое - оба массивы.
В Си нет операции над строками как над единым целым, даже операции
присваивания.
Нельзя записать
х= “ошибка#1”;
Её можно только инициализировать
char x [20] = “ это правильно”;
char y[]=”это тоже правильно”;

Все операции со строками реализованы через функции библиотеки <string.h>.


11.Константы литерные и арифметические

Символьные (или литерные) константы: ’литера’ – и гарантировано, что литеры с кодом 0-127
принадлежат стандартной таблице ASCII.
В различных компиляторах коду от 128 до 255, если данные типа unsigned char, или, что то же
самое, код от -127 до -1, если данное типа signed char могут соответствовать различные символы,
это зависит как от транслятора (компилятора), так и от драйверов клавиатуры.
Пусть некоторая литера имеет внутренний код 10000000 и он присвоен переменной lit. В
зависимости от того какому типу принадлежит lit имеем следующее число, если char lit ≡ signed
char lit, то lit=(100000002)со знаком следовательно 10000000 – 1 - получили обратный код

01111111 для числа 10000000 2 =12710 следовательно lit=-127, если unsigned char lit, то

lit=(10000002)без знака и следовательно прямой код числа 100000002 =12810.


Очевидно, что -127≠128. Поэтому следует обращать внимание на то, является ли переменная со
знаком или нет.
Напомним еще раз, что данные типа char , если они участвуют в
арифметических операциях, приводятся к ближайшему целому типу, в том числе и
константы, т.е. уместны операции типа:
5+’+’ ≡ 5+43=48, где 43 код литеры +.
Если char х и х=’>’, и х+=10; следовательно х=х+10 и т.к. код х - 62 получаем
72, а это код - H , и следовательно х=’H’. Произошло преобразование неявно ‘>’ в
int, затем 72 в char, более корректно x=(char)(x+10).
Существуют литеры видимые и невидимые. В таблице ASCII все коды из
диапазона 0-32 – невидимые, из диапазона 33- 126 – видимые, а код 127 –
невидимый. Все видимые литеры имеют изображения, которые следует
заключать астрографы. В СИ часть невидимых символов изображается
специальной литерой, а часть в форме кода. Поэтому форма кода допустимы и для
Способ задания литер более одним знаком заключенных в
апострофы, позволяет ввести новое понятие ESC –
последовательность (3 формы):
а) '\литера'
б) '\ddd' - от одной до трех восьмеричных цифр.
в) '\xhh' - от одной до двух шестнадцатеричных цифр.

ESC-последовательность в форме '\литера' допустима для


видимых литер.
a,t,v,b,r,f,\,',",n,? и они означают следующее:
\a - звонок
\t - горизонтальная табуляция
\v - вертикальная табуляция(первая строка первая позиция)
\b -возврат на шаг
\r - возврат каретки
\n - новая строка
\f - перевод страницы
\\ -\
\? -?
\’ –‘
\” – “
Если литера не принадлежит видимому набору для ESC-последовательности то
это ошибка.
Числовые коды знать не обязательно, но при выводе на печать семь первых
случаев выполняются управляющие действия!
ESC- последовательности в форме '\d' или '\dd' или '\ddd' это восьмеричное коды с
десятичным значением из диапазона 0-127.
'\7' тождественно литере с кодом 7 ≡ звуковой сигнал,
‘\71’ – литера с кодом 7*8+1=57 ≡ ’9‘,
‘\177’ – литера с кодом 82+7*8 + 7=127≡ ‘забой’.
Esc - последовательность в форме '\xhh' или '\xh' тождественно любому
шестнадцатеричному коду из диапазона от 0 до 255.
'\xd' - код 13 ≡возврату каретки,
'\xa' - код 10 ≡ переводу строки.
Форма изображения константы не совпадает с формой
изображения числового значения. Так например, 'a'==91, a 'A'==65,
где а и А - латинские буквы.
Русские же литеры 'a' и 'A' будут имеет числовое значение в
зависимости от типа персонального компьютера и второй части
таблицы ASCII c кодами от 128 до 255, являющимися расширением
стандарта ASCII и может содержать национальные алфавиты,
символы псевдографики и т.п.
Существует несколько расширения стандартов, по одному из них 'A'
= 128 или-128 , а 'a' =160 или -96, в зависимости от типа unsigned
char или signed char, а по другому 'A' =176 или -80 и 'a' = 208 или -
48, а также от наличия специальным программы ввода с клавиатуры
и ввода на экран (драйвера).
Прежде чем использовать напрямую числовые (изображения в виде
литер) значения, следует проверить состав расширенной таблицы
ASCII.
Но более осторожно будет, если вы будите изображать числовые
значения литерами, доверяя системе изображения на числовую ось.
Пример:
Приведем программу, которая печатает числовой код литеры и саму
литеру на экране:
main()
{int i;
for (i=0;i<256;i++)
cout<<” десятичный код”<< i<<” знаковая литера”<<(char)i<<”
беззнаковое число”<<(unsigned)i;

}
Следующий пример - преобразование литер латинского алфавита с нижнего регистра на
верхний:
main()
{char lit;
for (lit='a';lit<='z';lit++)
cout<<”строчная литера”<<lit<<”прописная”<<lit+’A’-‘a’;
}
В этом примере имеет место следующее преобразование типов:
lit='a'- проходит без преобразования,
lit<='z' => int,
lit++ тождественно lit=lit+1}=> int => char,
то же самое происходит при вычислении lit+'A'-'a'.
В этом примере числовые значения литер используются для определения расстояния между
ними.
12.Числовые и целые константы
Целочисленную константу Си можно изобразить в трех системах счисления(СС)
– десятичной, восьмеричной и шестнадцатеричной.
В каждой системе счисления константы имеют следующую структуру
изображения –
[признак системы счисления]последовательность цифр систем
счисления[суффикс длинны и знака]
а) признак десятичной СС - константа начинается с десятичной цифры, но не
нуля;
б) признак восьмеричной СС - константа начинается с 0;
в) признак шестнадцатеричной СС - константа начинается с 0x или 0X.
Суффикс длинны L или l, суффикс знаки u или U .
Если константа не имеет суффикса, то она принадлежит int, если ее значение
принадлежит int, иначе long int. Все константы без знака. Отрицательных
констант не существует, -57 - это не константа, а выражение.
Пример:
В десятичной СС 5 - это int , а 55555 - long int .
В восьмеричной СС 05 - int, 055555==5*84+5*83+5*82+5*8 +5= |101|101|101|
101|101| - int.
В шестнадцатеричной СС 0x55555 - long int .
Если константа имеет суффикс l , то у нее тип (ее значение) принадлежит long
int, а если u - unsigned int , или unsigned long int, если суффикс – ul.
Пример:
57ul принадлежит unsigned long.
5710=7*8+1=0718=3*16+9=0х3916
Восьмеричные и шестнадцатеричные представления используются редко для
задач числового плана, но в системном программировании это не редкость.
13. Поразрядные логические операции
Пусть каким-то образом закодировано некоторое множество элементов,
Например:
{a1, a2, …, an} n<=32, пусть n=32.

Если a­­1, а2, …, аn – это стол, стул, табуретка и т.д., то изобразить эти элементы
невозможно. В Си нет операций над множествами (нет множественного типа),
Если X – множество из n элементов, а B включено в Х, то характеристический
вектор множества B – h(B) называется цепочка из 0 или 1, при этом 1 в этой
цепочке стоит на i-том месте тогда и только тогда, когда xi принадлежит B, где

{xi /i = от 1 до n}, =X.


Например:
X = {стул, стол, табуретка, кресло} В = {стол, табуретка}
h(B) = 0110.
Если
А, В включено в Х, то АUВ - объединение и следовательно h(AUВ) это h(A) |
h(B) , где | поразрядная логическая операция или .
А, В включено в Х, то А∩В - пересечение и следовательно h(A∩В) это
h(A)&h(B) , где & побитовая операция и.
Есть еще одна бинарная операция – исключающее или: ^.
Таблица истинности:
0 ۸ 1=1
0 ۸ 0=0
1 ۸ 0=1
1 ۸ 1=1
Например:
5 ۸ 4 =1 =>

0005
- (похоже на вычитание)
0004

0001
Но
32 ۸ 31=63 =>

10 0000
1 1111 - (похоже на сложение)
11 1111

Имеется так же унарная операция ~ поразрядное логическое отрицание

~0 => 1
~1 =>0
Определить какие элементы не входят во множество А – ответ ~h(A).
Приоритет побитовых операций:
1) ~
2) &
3) ^
4) |

14. Моделирование множества


Введем unsigned long int h – вектор характеристик для
множества из 32 элементов.
Напишем функцию формирования вектора, если номера
элементов множества поступают с внешнего файла.
unsigned long int getset (void)
{unsigned long int h=0; int k;
while (<не конец файла>==<читать число в k>)
{switch (k)
{case 1: h = h|0x 0001; break; // 1 на 1 месте справа
case 2: h = h|0x 0002; break; // 1 на 2 месте справа
case 3: h = h|0x 4; break; // 1 на 3 месте справа
case 4: h = h|0x 8; break; // 1 на 4 месте справа
case 5: h = h|0x 10; break;
case 6: h = h|0x 20; break;
case 7: h = h|0x 40; break;
case 8: h = h|0x 80; break;

case 30: h = h|0x 2000 0000; break;
case 31: h = h|0x 4000 0000; break;// 1 на 31 месте справа
case 32: h = h|0x 8000 0000; break;// 1 на 32 месте справа

}
}
return (h);
}
Например, если номера - 1 5 3 14 15, то имеем:

Нумерация:

32 … 15 14 … 5 3 1

… 1 1 … 1 1 1

31 … … 4 3 2 1 0

нумерация
15.Функции, моделирующие операцию над множествами

Объединения множеств:
unsigned long int union–set (unsigned long int A, unsigned long
int B)
{return (A|B);
}
Пересечения множеств:
unsigned long int common–set (unsigned long int A, unsigned
long int B)
{return (A&B);
}
16. Маски
Логические операции часто нужны для выделения групп битов.
А восьмеричные и шестнадцатеричные константы используются
для создания масок:

Пример 1:
В битовом представлении некоторого числа выделить группу
битов с четвертого по седьмой включительно, считая слева на
право.
4-7 бит

0000 0101 1111 01100 - n- int

0 0 F 0
Построим маску int mas; – константу, с помощью которой
выделяется группа битов.
тогда int result = n&0xF0;
Операция & для маски - сбрасывает в нули все разряды
соответствующие нулевым разрядам маски и оставляет без
изменения разряды соответствующие единичным разрядам маски.
Пример 2:
В битовом представление некоторого числа устанавливается 1 в
знаковом разряде (пусть int - 2 байта) остальные остаются без
изменений.
int result = 0x8000| (n&0x7FFF)

(выделить знак)

(выделить цифры без знака)

0101 0001 0001 0001 - число

1000 0000 0000 0000 - маска


Можно проще: result = n| 0x8000.
Операция | для маски добавляет в разряды исходного числа соответствующе
разрядам маски1, остальные разряды оставляет без изменения.
Операция ^ для маски , если разряды приходятся на нулевые разряды , они не
изменяются, если на единичные – изменяются на противоположные.
Р-операнда ^ Р-маски Результат
=>

0 0 0
1 0 1
0 1 1
1 1 0
17.Операции сдвигов разрядов

1.Операция сдвиг вправо( >>).


Синтаксис операции:
<целочисленное выражение> >> <целочисленное выражение>
Например, сдвинуть в битовом представлении h все разряды вправо на 1бит - h>>1 , на
4бита – h>>4.
Пусть h=5 тогда при сдвиге на 1 бит вправо:

0000 0000 0000 0101 получим


0000516 =
0000 0000 0000 0010

последняя 1 – теряется, при h= –5 возможны 2 варианта:


а) 0111 1111 1111 1101 – логический (последняя 1 потеряна), а слева дописывается 0;
б) 1111 1111 1111 1101 – арифметический(последняя 1 потеряна)., а слева дописывается
1.Способ зависит от реализации.
Но если h принадлежит unsigned int, то сдвиг логический , это то же самое, что деление на 2b,
где b – второй операнд.
Пример:
unsigned int x = <constanta>
x = x >>5; с изменением х
или
x >>5; без изменения х.

1.Операция сдвиг влево(<<).


Синтаксис операции:
<целочисленное выражение> << <целочисленное выражение>
Разряды справа заменяются нулями.
x <<10 равносильно x*210
Если unsigned int x=3 и x=x<<10 , то :
0000 0000 0000 0011 => 0000 1100 0000 0000 – после сдвига.

Поразрядные операции над числами могут использоваться в числовых задачах,


при попытке определить накапливаемую вычислительную ошибку.
18.Константы с плавающей точкой

Синтаксис
[целая часть] [дробная часть] [степень] [суффикс] , где
а)может отсутствовать дробная часть, но тогда присутствует степень;
б) может отсутствовать целая часть и степень;
в) может отсутствовать степень, но тогда должна быть точка.

Примеры:
5. 5.0
.03 0.003 – правильная форма записи.
19.Логические выражения

В СИ как таковых логических выражений, то есть выражений, имеющих значения логического


типа нет, так как нет самого логического типа(в отличии от СИ++ ). Поэтому логическим
выражением будем считать выражение, содержащее логические операции (! – отрицания (не), || -
или, && - и), операции отношения (<=, >=, <, >), сравнения (==, !=); операнды и скобки.
Приоритеты операций:
1) !
2) <=, >=, <, >
3) ==, !=
4) &&
5) ||
Значение логического выражения либо 0(если выражение ложно), либо 1 (если выражение
истинно).
Пример:
int x, y, z, a, b, c;
a=b=c=x=y=z=1;
c=!a|| (b&&c) = = (x>y)||(x<y)

0 1 0 0
1 0

Следовательно c=0.Отрицание !х==1<=>x==0 во всех остальных случаях !


х==0.Логическое отрицание часто используется в условиях цикла.
Пример:
Пусть int getint ( ) – функция, которая из входного файла читает некоторое целое
число большее 0 и возвращает его, если обнаружен конец файла, возвращает
EOF. В Си нет функции EOF, а есть числовая константа целого типа,
обозначаемая EOF (конец файла) и определенная в библиотеке <stdio.h> Тогда
int k;
while ((k=geting ( )! = EOF)
Читать k, если k не EOF, то выполнить цикл, иначе – закончить. Нужно вставить
в функцию формирования множества, рассмотренную ранее.
20.Семантика операций && (И) и || (ИЛИ)
В выражении e1&&e2, если e1=0, то е2 – не вычисляется. В выражении е1||
е2, если е1==1, то е2 – не вычисляется.
Пример:
Рассмотрим выражение 3<x<5
а) пусть x=4, тогда 3<x =1 и получаем 1<5=1
б) пусть x=2, тогда 3<x=0 и получаем 0<5=1
в)пусть x=6, тогда 3<x=1 и получаем 1<5=1, т.е. при любом x 3<x<5 равно 1.
Более корректная запись выражения - (3<x)&&(x<5).
Пример:
Пусть int a[10] – массив в СИ. Нужно прекратить вычисления, при
первом аi<0.
for (i=0; i<=9&&a[i]>0; i++)
{…
}
Проверка a[10] не выполняется при i=10, т.е. выход за границы
массива не происходит. Выход из цикла или при отрицательном аi ,
или при достижении конца массива.
21.Условное выражение
Условный оператор if в СИ можно заменить на более простую конструкцию
a= выражение 0? Выражение1: выражение 2 - условное выражение.
Сначала выполняется выражение 0: если его значение не равно нулю, то
вычисляется выражение1, и результат всего выражения получает его значение.
Если значение выражения0 =0, то вычисляется выражение2, и его значение – это
значение всего выражения.

Пример:
a=(a= =b)?a:b – а присваивается значение а, если а равно b или b в противном
случае;
a=(a>b)?((a>c)?a:c):(b>c)?b:c – а присваивается наибольшее изтрех a, b, c .

Вам также может понравиться