
- •Н. А. Аленский основы программирования
- •§ 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
1.3. Упаковка и распаковка информации
В реальных задачах возникает необходимость работать с числами из определённого диапазона. Например, из условия задачи известно, что числа находятся на промежутке от нуля до трёх. Тогда для их представления в памяти достаточно двух бит, так как 310=112. Для экономии памяти возникает необходимость в одну ячейку поместить несколько чисел. Например, в двухбайтную переменную r, объявленную как unsigned short r и занимающую 16 бит, можно записать 16/2=8 чисел из диапазона 0..3. Такие задачи называют упаковкой, или сжатием, информации.
Существует несколько алгоритмов решения подобной задачи. Предлагается заполнять ячейку r справа налево. Первое число помещаем в последние два бита, сдвигаем его влево на два разряда. На освободившиеся после сдвига два бита засылаем второе число, сдвигаем влево на два разряда, записываем третье число, сдвигаем и так далее.
randomize();
unsigned short num, r=0;
for (int j=1; j<=8; j++)
{ r<<=2; // или r=r<<2;
num=random(4);
cout<<num<<" ";
r |= num; // или r+= num;
}
printf(" \ n % x % d",r, r);
Так как после сдвига влево ячейки r два последних бита будут нулевыми, а в переменной num ненулевые только два последних бита, то r = r | num и r = r+num ( r |= num и r += num ) выполняются одинаково.
В функции вывода printf формат %x используется для вывода целого числа в шестнадцатеричной системе счисления.
В таких задачах важно уметь проанализировать результат. Пусть случайным образом сформированы следующие восемь чисел в таком порядке: 3, 0, 2, 1, 3, 0, 1, 1, которые в цикле выводятся с помощью cout<<num<<" ". Тогда будет выведено c9c5 — шестнадцатеричное представление числа по формату %x. Почему? Так как, по условию, каждое число занимает два бита, то в двоичном виде имеем 1100100111000101. Разбив на тетрады и учитывая, что это положительное число (unsigned), получим c9c5. Затем будет выведено 51653 — это же число в десятичной системе счисления по формату %d.
Как из такого числа r, в котором хранятся восемь чисел из диапазона 0..3, “взять” каждое из них и, например, вывести? Это называют распаковкой.
Алгоритм 1. Выполнить распаковку можно так, как выводили целое число в двоичной системе счисления (упр. 5 из п. 1.2), т. е. будем выделять числа справа налево. При этом операция & выполняется с числом 3 (11 в двоичной системе счисления), а сдвигать надо вправо на 2, 4, 6, … разрядов.
Алгоритм 2. Числа будем получать слева направо в том же порядке, как они формировались. Для выделения первой левой цифры (в нашем примере 3) используем операции (r & 0xC000)>>14, так как С00016 = 11000000000000002.
Для выделения второй цифры (0) из числа 11000000000000002 получаем 00110000000000002= 300016 , используя сдвиг на два разряда и выполняем операции (r & 0x3000)>>12.
На каждом последующем шаге переменную Maska, с которой выполняется операция &, сдвигаем вправо на два разряда, а результат этой операции сдвигаем вправо на 10, 8, … разрядов (переменная shift ).
cout<<endl;
unsigned Maska=0xC000, shift=14;
for (int j=1; j<=8; j++, shift –=2, Maska>>=2)
{ num= (r & Maska)>>shift;
cout<<num<<" ";
}
В результате будут получены и выведены те же числа, которые были сформированы случайным образом, т. е. 3, 0, 2, 1, 3, 0, 1, 1.
Упаковку эффективно использовать, если в памяти необходимо хранить массив целых чисел из указанного диапазона большой размерности. Например, если надо сохранить 400 чисел из диапазона 0..3, то вместо массива unsigned short a[400] достаточно объявить массив unsigned short a[50]. Этим самым память экономим в 8 раз. Эффективность этой методики возрастает, если надо обрабатывать числа из малого диапазона (например, 0..1). Время выполнения таких программ увеличивается.