- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
166 13
cout << p;
выводит изображение символа.
Для перехода к следующей строке экрана выводится манипулятор endl, определенный в iostream.h.
Программа выдает:
Работа с беззнаковыми p = 100 = 01100100
q = 200 = 11001000
p + q = 44, p - q = 156 q >> 2 = 50 = 00110010 Работа со знаковыми
z = 127 = 01111111, z + 1 = -128 = 10000000
x= -59 = 11000101
x| 017 = -49 = 11001111
x& 017 = 5 = 00000101
x^ 017 = -54 = 11001010 ~x = 58 = 00111010
x<< 2 = 20 = 00010100
x>> 2 = -15 = 11110001
13.6. Дробные числа в двоичной системе
Как известно, при записи дробных чисел используется точка для отделения целой и дробной части. Веса цифр дробной части равны отрительным степенями двойки, например,
585 = 4 +1+ 48+1 = 22 + 20 + 12 + 18 = 1× 22 + 0× 21 +1× 20 +1× 2−1 + 0× 2−2 +1× 2−3 = 101.101.
Для нахождения цифр двоичного представления дробного числа нужно сначала записать в двоичной системе его целую часть рассмотренным выше способом – делением на 2.
Заметим, что при умножении числа на 2 точка, отделяющая целую и дробную части, переместится вправо и старший разряд дробной части превратится в младший разряд целой части. Используя это наблюдение, приходим к следующему алгоритму получения двоичного представления числа, меньшего 1. Нужно умножать число, меньшее 1 на 2. Очередная двоичная цифра дробной части равна цифре целой части после очередного умножения числа на 2. Найдем, например, двоичное представление для числа 5/8 = 0.625, табл.54.
Внутреннее представление чисел |
167 |
Таблица 55. Двоичные цифры числа 5/8
Число |
Число *2 |
Двоичная цифра |
0.625 |
1.25 |
1 |
0.25 |
0.5 |
0 |
0.5 |
1.0 |
1 |
0.0 |
|
|
В данном примере число представляется в виде двоичной дроби с конечным числом цифр, процесс преобразования прекращается, когда число обращается в 0.
Рассмотрим теперь число 0.3, табл.56
Таблица 57. Двоичные цифры числа 0.3
Число |
Число*2 |
Двоичная цифра |
0.3 |
0.6 |
0 |
0.6 |
1.2 |
1 |
0.2 |
0.4 |
0 |
0.4 |
0.8 |
0 |
0.8 |
1.6 |
1 |
0.6 |
1.2 |
1 |
… |
… |
… |
Видно, что получение цифр является бесконечным периодическим процессом. Таким образом,
0.3 = 0.010011001100110011001100...
13.7. Внутреннее представление плавающих типов
Числа с плавающей точкой хранятся в памяти в экспоненциальной форме в двоичной системе счисления. Формула такого представления имеет вид
x = ±1.M2 2± p2 .
Здесь 1. M2 – мантисса числа в двоичной системе, p2 – порядок числа
в двоичной системе.
Чтобы получить двоичные цифры мантиссы, нужно представить число в виде суммы степеней двойки. Например,
16813
5.3= 5 + 0.3 = 101.01001100110011001100110...2 =
=1.01010011001100110011001100...2 *2102
Итак, для числа 5.3 мантисса имеет вид:
M2 = 01010011001100110011001100...2,
порядок равен:
p2 = 102.
Видно, что мантисса числа 5.3 есть бесконечная периодическая дробь. Разряды мантиссы, не умещающиеся в пределы разрядной сетки, отбрасываются. Если старший отбрасываемый разряд равен единице, то происходит округление путем прибавления единицы к младшему разряду мантиссы.
В памяти хранятся знак числа, часть мантиссы M2 и порядок p2 .
Самая старшая единица мантиссы не хранится, но учитывается в вычислениях.
Рассмотрим для примера тип float, под который отводится 4 байта памяти с подряд идущими адресами. Из 32 бит, выделяемых для размещения float, старший 31-й разряд используется для хранения знака числа (0 – положительное число, 1 – отрицательное), в 8 разрядах (с 23го по 30-й) хранится порядок и в 23-х разрядах (с 0-го по 22-й) размещается мантисса. Порядок хранится в увеличенном на шестнадцатеричное число 7F виде, то есть используется двоичная нотация с избытком 127. Это позволяет обойтись без специального разряда для хранения знака порядка.
Пусть для размещения числа типа float выделены байты с адресами a, a+1, a+2, a+3.
Возможны различные способы размещения в этих байтах разрядов двоичного представления числа. В процессорах фирмы Intel принят способ
1234,
то есть младшие разряды двоичного представления числа размещаются в байтах с меньшими адресами. В табл.58. приведены примеры внутреннего представления чисел типа float.
|
|
|
Внутреннее представление чисел |
169 |
||
|
Таблица 59. Двоичный код для чисел с типа float |
|
||||
Число |
|
|
Двоичный код |
16 |
– ричный |
|
|
|
порядок |
Мантисса |
код |
|
|
1.0 |
0 |
011 1111 1 |
000 0000 0000 0000 0000 0000 |
3f 80 00 00 |
||
2.0 |
0 |
100 0000 0 |
000 0000 0000 0000 0000 0000 |
40 |
00 00 |
00 |
10.0 |
0 |
100 0001 0 |
010 0000 0000 0000 0000 0000 |
41 |
20 00 |
00 |
5.30 |
0 |
100 0000 1 |
010 1001 1001 1001 1001 1010 |
40 A9 99 9A |
13.8. Преобразование типов
Если операнды некоторого оператора имеют разный тип, то они перед выполнением оператора приводятся к некоторому общему типу. Автоматически выполняются преобразования, которые превращают операнд с меньшим диапазоном значений в операнды с большим диапазоном значений. Например, целое преобразуется в число с плавающей точкой в выражениях вида
f + i,
где f – число с плавающей точкой, i – целое.
Выражения, не имеющие смысла, не допускаются. Например, плавающее число нельзя использовать в качестве индекса массива.
Если возможна потеря информации, например, при присваивании целой переменной значения с плавающей точкой, компилятор может выдать предупреждение (warning), но такие выражения допустимы.
Тип char
Значения типа char – это просто малые целые, потому они свободно используются в арифметических выражениях. При вычислениях char предварительно преобразуется к целому типу. В качестве примера приведем функцию atoi, преобразующую строку цифр в ее числовой эквивалент.
// atoi: преобразование s в целое int atoi(char s[])
{
int i, n = 0;
for(i = 0; s[i] >= ’0’ && s[i] <= ’9’; i++) n = n*10 + s[i] – ’0’;
return n;
}
170 13
Выражение s[i] – ’0’ дает числовое значение цифры, размещенной в s[i], так как значения ’0’, ’1’,…, ’9’ образуют непрерывную возрастающую последовательность (’0’ = 48, ’1’ = 49,…, ’9’ = 57).
Предложенный вариант функции atoi несовершенен, например, не предусмотрена возможность записи числа в виде последовательности цифр, начинающейся знаком + или -. Заголовочный файл stdlib.h содержит описания ряда библиотечных функций для преобразования строк в числовые значения.
Функция
int atoi(const char *s)
переводит s в int, начальные пробелы игнорируются, число может иметь знак.
Функция
long atol(const char *s)
переводит s в long. Функция
double atof(const char *s)
переводит s в double, игнорируя начальные пробелы.
Следующая функция lower преобразует заглавную латинскую букву в строчную. Если же символ не является заглавной буквой, он не изменяется.
int lower(int c)
{
if(c >= ’A’ && c <= ’Z’) return c + ’a’ – ’A’;
else return c;
}
Для латинских букв эта функция будет работать правильно, так как между одноименными буквами верхнего и нижнего регистров одинаковая разность, кроме того, латинский алфавит плотный, то есть между ’A’ и ’Z’ и между ’a’ и ’z’ расположены только буквы. Для русских букв в кодовой таблице 866, которая используется в DOS-программах, это не так. Заглавные русские буквы ’А’, ’Б’, …, ’Я’ идут плотно, а у строчных русских букв есть разрыв между ’п’ и ’р’, в котором расположены символы псевдографики. В кодовой таблице 1251, используемой в Windows, русские заглавные и строчные буквы расположены непрерывно в алфавитном порядке.
Имеются библиотечные функции для преобразования символов и проверки их типа, объявленные в заголовочном файле ctype.h.
Внутреннее представление чисел |
171 |
Функция
int tolower(int c);
возвращает код малой (строчной) латинской буквы, соответствующей заглавной (прописной) латинская букве c. Если c не является заглавной латинской буквой, то возвращается c без преобразования.
Функция
int toupper(int c)
возвращает код заглавной латинской буквы, соответствующей строчной латинской букве c. Если c не является строчной латинской буквой, то возвращается c без преобразования.
Функция
int isalpha(int c)
возвращает 1, если c – латинская буква, иначе 0. Функция
int isdigit(int c)
возвращает 1, если c – цифра, иначе 0. Функция
int isalnum(int c)
возвращает 1, если c – латинская буква или цифра, иначе 0. Функция
int isspace(int c)
возвращает 1, если c – пробел, табуляция, новая строка, возврат каретки, новая страница, вертикальная табуляция, а иначе 0.
Функция
int isupper(int c)
возвращает 1, если c – заглавная латинская буква, иначе 0. Перечисленные функции не обрабатывают правильно русские
буквы.
Проверку
s[i] >= ’0’ && s[i] <= ’9’, использованную в функции atoi, можно заметить на
isdigit(s[i]).
Язык не определяет, является тип char знаковым или нет, поэтому это зависит от реализации. Например, в C++Builder тип char считается
172 13
знаковым. В Visual C++ тип char – беззнаковый. В Turbo C++ характеристика char определяется настройками компилятора. Для установки спецификации unsigned для char нужно выполнить команду меню Options, Compiler, Code generation и установить
соответствующий флажок, рис.57.
Рис.58. Настройки компилятора Turbo C++
В выражениях char преобразуется в int. Для знакового char преобразование производится посредством «распространения знака» и получится отрицательное число, если старший разряд был единичным. Для беззнакового char преобразование производится путем заполнения старших разрядов слева нулями, поэтому получаемое значение будет всегда положительным.
Значения логических выражений
Отношения типа i > j и логические выражения, содержащие операторы &&, ||, ! определяют выражение, которое имеет значение 1, если оно истинно и 0, если ложно. После присваивания
d = c>= ’0’ && c <= ’9’;
d будет иметь значение 1, если c – цифра и 0 в противном случае. Однако функции, подобные isdigit, могут выдавать в качестве истины любое ненулевое значение.
Внутреннее представление чисел |
173 |
Арифметические преобразования
Перед выполнением оператора вроде + или * с операндами разных типов «низший тип» повышается до «высшего». Высшим считается тип с большим размером памяти. Для целых типов одного размера высшим считается беззнаковый тип по отношению к типу со знаком. Результат выражения будет иметь высший тип.
Правила преобразования следующие:
∙Если один из операндов имеет тип long double, другой тоже преобразуется к long double.
∙В противном случае, если один из операндов имеет тип double, другой тоже преобразуется в double.
∙В противном случае, если один из операндов имеет тип float, другой тоже преобразуется в float.
∙В противном случае типы char, unsigned char, signed char
преобразуются к int. Это действие называется целочисленным повышением.
∙Затем, если один из операндов имеет тип unsigned long, другой тоже преобразуется к unsigned long.
∙В противном случае, если один из операндов имеет тип long int, другой unsigned int, то если long int может представить все значения типа unsigned int, то unsigned int преобразуется в long int, иначе оба операнда преобразуются к типу unsigned long int.
∙В противном случае, если один из операндов имеет тип long, другой тоже преобразуется в long.
∙В противном случае, если один из операндов имеет тип unsigned int, другой тоже преобразуется в unsigned int.
∙В противном случае оба операнда имеют тип int.
Пусть на конкретной машине int занимает 16 битов, а long – 32. В этом случает long содержит все возможные значения unsigned int, и выражение
–1L < 1U
будет истинным, так как 1U преобразуется в long и после преобразования будет иметь значение 1.
Но
–1L > 1LU,
так как –1L имеет внутреннее представление из одних единиц и, после повышения до типа unsigned long, воспринимается как большое положительное число, в то время, как 1LU имеет единичку в младшем разряде, а остальные разряды – нули.