- •Н. А. Аленский основы программирования
- •§ 1. Структура простой программы. Ввод, вывод
- •1.1. Пример первой программы
- •1.2. Директива препроцессора #include
- •1.3. Структура программы
- •1.4. Комментарии
- •1.5. Ключевые слова и идентификаторы
- •1.6. Простой ввод, вывод
- •§ 2. Оператор if
- •2.1. Полная форма
- •2.2. Сокращённая форма
- •2.3. Особенности оператора
- •Задачи и упражнения
- •§ 3. Выражения
- •3.1. Константы
- •Непосредственно записать в выражении;
- •3.2. Операции и их приоритет
- •3.3. Операции отношения и логические операции
- •3.4. Особенности операции присваивания
- •3.5. Тернарная операция (?)
- •Задачи и упражнения
- •§ 4. Оператор выбора switch
- •Задачи и упражнения
- •§ 5. Операторы цикла
- •5.1. Оператор while c предусловием
- •Правила использования и особенности оператора while
- •5.2. Оператор цикла do … while c постусловием
- •5.3. Оператор for
- •5.4. Операторы continue и break
- •Задачи и упражнения
- •§ 6. Введение в одномерные массивы
- •6.1. Что такое массив. Объявление одномерного массива
- •6.2. Способы определения массивов
- •6.3. Вывод одномерного массива. Функции printf и сprintf
- •6.4. Некоторые типы простых задач при работе с массивами
- •Задачи и упражнения
- •§ 1. Функции без результатов. Передача параметров по значению
- •1.1. Примеры. Правила оформления и вызова функций
- •Void line2(int Len, y, char ch) // ошибка,
- •1.2. Формальные и фактические параметры
- •1.3. Передача параметров по значению
- •§ 2. Функции типа void с несколькими результатами
- •2.1. Пример
- •2.2. Что такое ссылочный тип
- •2.3. Возврат значений из функции с помощью ссылочного типа
- •Задачи и упражнения
- •§ 3. Функции с одним результатом. Оператор return
- •Задачи и упражнения
- •§ 4. Одномерные массивы в функциях. Сортировка массива
- •Задачи и упражнения.
- •§ 5. Область действия имён. Локальные и глобальные имена
- •§ 6. Дополнительные возможности функций
- •Встраиваемые функции (inlineфункции)
- •6.2. Параметры по умолчанию
- •6.3. Перегрузка функций
- •§ 1. Примеры
- •§ 2. Класс. Поля и методы класса
- •§ 3. Создание объектов. Конструктор
- •Задачи и упражнения.
- •Глава 4 простые типы данных § 1. Целый тип
- •1.1. Битовые операции
- •1.2. Использование битовых операций
- •1.3. Упаковка и распаковка информации
- •Задачи и упражнения.
- •§ 2. Логический тип
- •§ 3. Символьный тип
- •Глава 5 матрицы (двухмерные массивы) § 1. Объявление, способы определения
- •§ 2. Вывод матриц
- •§ 3. Типы алгоритмов на обработку матриц
- •3.1. Построчная обработка
- •3.2. Обработка матрицы по столбцам
- •3.3. Обработка всей матрицы
- •3.4. Обработка части матрицы
- •3.5. Преобразование матрицы
- •Упражнения.
- •3.6. Построение матриц
- •§ 4. Передача матрицы в качестве параметра функции
- •Задачи и упражнения.
- •Б. Обработка матрицы по столбцам.
- •Даны две матрицы a и b одинаковой размерности. Построить матрицу с, каждый элемент которой определяется по правилу:
- •Список рекомендуемой литературы
- •Сборники задач по программированию
- •Оглавление
- •Задачи и упражнения …….……………………………………...12
- •3.1. Константы ………………………………………………...…14
Глава 4 простые типы данных § 1. Целый тип
1.1. Битовые операции
В языке С++ есть следующие битовые операции:
& — битовое и;
| — битовое или;
^ — исключающее или;
~ — дополнение;
>> сдвиг вправо на указанное количество разрядов (бит);
<< сдвиг влево на указанное количество разрядов (бит).
Первые три операции являются бинарными. Они работают с двоичным представлением двух операндов (констант, переменных или выражений). Они выполняются над каждой парой битов по следующим правилам:
& | ^
1 1 1 1 0
1 0 0 1 1
0 1 0 1 1
0 0 0 0 0
Упражнение 1. Определить результат:
short int k1=30,k2=-1707,r; r=k1 & k2;
cout<<endl<< k1<< “&”<<k2<<”=”<<r;
1) Представляем положительное число 30 в оперативной памяти. Для этого переводим его в двоичную систему счисления делением на 2 следующим образом: 30/2=15 (0 в остатке), 15/2=7 (1 в остатке), 7/2=3 (1), 3/2=1(1), 1/2=0(1). Записывая все остатки в обратном порядке, получим 3010 =111102. Представляем это число в двух байтах, так как оно объявлено как short int. Для этого дописываем слева необходимое количество нулей и получаем 0000000000011110.
2) Представляем отрицательное число –1707 в оперативной памяти в дополнительном коде. Для этого выполняем следующее:
а) так как делением на 2 перевод в двоичную систему счисления выполняется долго, сначала переведём число 1707 во вспомогательную шестнадцатеричную систему счисления делением на 16. 1707/16=106 (11 в остатке), 106/16=6 (10), 6/16=0(6). Записывая все остатки в шестнадцатеричной системе счисления в обратном порядке, получим 170710 =6AB16, так как 1010=A16, 1110=B16;
б) каждую шестнадцатеричную цифру полученного результата записываем в виде четырёх двоичных цифр (двоичной тетрады): 011010101011;
в) представляем это число в двух байтах, так как оно объявлено как short int. Для этого дописываем слева необходимое количество нулей: 0000011010101011. Получили представление положительного числа в памяти компьютера;
г) для получения дополнительного кода выполняем инверсию положительного представления с учётом “левых” нулей, т. е. нуль меняем на единицу, а единицу на нуль. К результату инверсии прибавляем единицу. Получим 1111100101010101.
3) К полученным таким образом двоичным кодам двух чисел применяем битовую операцию и (&). При этом единицы получаем только там, где были обе единицы, во всех остальных разрядах получатся нули: 00000000000010100.
4) Что это за число в десятичной системе счисления? Для ответа на вопрос разбиваем его на тетрады и получаем число в шестнадцатеричной системе счисления: 1416. Для перевода в десятичную систему счисления записываем его как сумму степеней числа 16, умноженную на соответствующую шестнадцатеричную цифру: 1416=1*16+4=2010. При этом действия выполняются в десятичной системе счисления.
Упражнение 2. Найти r2=30 | -1707, если, a) short r2, b) unsigned short r2.
По умолчанию подразумевается тип int. К полученным в предыдущем упражнении двоичным кодам применяем битовую операцию или ( | ). При этом нули получаются только там, где были оба нуля, во всех остальных разрядах получатся единицы: 1111100101011111.
a) Так как результат объявлен как знаковое число (по умолчанию signed) и в самом левом бите получилась единица, то это дополнительный код отрицательного числа. Для его получения выполняем в обратном порядке то, что делали в пункте 2) предыдущего упражнения: вычитаем единицу и выполняем инверсию. Получим 0000011010100001. Разбив на тетрады, получаем 6A116=6*162+10*16+1=1697. Ответ: –1697.
б) Так как при таком объявлении (unsigned) отрицательного числа быть не может, то мы имеем положительное число, несмотря на единицу в самом левом бите. Разбиваем двоичное число на тетрады и переводим его из шестнадцатеричной системы счисления в десятичную: F95F16=15*163+9*162+5*16+15=63839.
Упражнение 3. Найти r3=30 ^ –1707, если: a) short r3, b) unsigned short r3.
Упражнение 4. Пусть short r3. Определить результат: r3=~30.
Операция дополнение (~) меняет единицу на нуль, а нуль на единицу. Поэтому к полученному в упр. 1 двоичному коду числа 30 0000000000011110 применяем инверсию: 1111111111100001. Так как по умолчанию переменная имеет модификатор signed и в самом левом бите получена единица, то это отрицательное число. Для его восстановления вычитаем единицу и выполняем инверсию: 0000000000011111=1F16=1*16+15=31. Ответ: –31.
Операция << (сдвиг влево) имеет общий вид a<<m, где a — число, участвующее в сдвиге, а m показывает, на какое количество разрядов сдвигаем число. При этом как для положительных, так и для отрицательных чисел “вращение”, или циклический сдвиг, не выполняется. Значения левых сдвинутых бит теряются, а справа появляются нули.
Например, в результате выполнения следующего фрагмента программы
char k= –5;
for(int I=1; I<=4; I++)
{ k<<=1; // или k=k<<1;
printf("%5d",k);
}
получим –10, –20, –40, –80. Почему? Число –5 имеет следующее представление в одном байте (тип char): 11111011. После сдвига на один разряд имеем 11110110. При этом левая крайняя единица потерялась, и справа появилось число 0, а не 1. Так как это отрицательное число, то после вычитания единицы и инверсии получаем 00001010, т. е. число 10. Поэтому первым будет выведено число –10. Аналогично получаем остальные числа.
Сдвиг влево на один разряд означает увеличение целого числа в два раза, сдвиг влево на два разряда увеличивает число в четыре раза и так далее, сдвиг влево на m разрядов равносилен увеличению числа в 2m раза. Это не зависит от того, какое число, положительное или отрицательное, участвовало в сдвиге.
Сдвиг вправо (a >> m) выполняется аналогично, без циклического сдвига. При сдвиге положительных чисел слева появляется m нулей, а при сдвиге отрицательных чисел слева добавляется m единиц.
Сдвиг вправо на один разряд означает целочисленное деление на 2, сдвиг вправо на два разряда означает целочисленное деление на 4 и так далее, сдвиг вправо на m разрядов равносилен целочисленному делению числа на 2m .
Например, 42>>2 даёт 1010. Действительно, 42=001010102, а в результате сдвига получаем 000010102=1010. В результате операции –42>>2 получим –11. Почему? –42=110101102, а после сдвига получим 111101012, то есть отрицательное число –11.
В качестве упражнения выполните следующий фрагмент программы и объясните результат:
char k= –30; cout<<endl;
for(int I=1; I<=4; I++)
{ k>>=1; // или k=k>>1;
printf ( "%5d" , k);
}