Как вывести unsigned char

Типы данных. Переполнение.

В предыдущем уроке мы изучили основные типы целочисленных данных на языке С ++, узнали, как создавать переменные соответствующего типа и, какие числа можно хранить в этих переменных.

Однако , иногда возникают ситуации, когда полученное в результате математической операции число, больше, чем может содержать переменная определенного типа. Например, для типа unsigned char максимально допустимое число – 255. Если мы к этому числу прибавим 1, то, казалось бы, должно получиться 256, но на самом деле получается 0. Почему так происходит? Сложим столбиком в двоичной форме числа 11111111 (255) и 1:

Как считать столбиком в двоичной форме? Точно также, как и в десятичной, только нужно помнить, что 1 + 1 =10, а 1 + 1 + 1 = 11. Начинаем сложение с самых правых чисел: 1 + 1 = 10, 0 пишем, а 1 запоминаем (эта единица отмечена красным). Ко второй справа единице добавляем 1, которую мы запомнили: получается 10, 0 пишем, 1 запоминаем и т.д … К последней единице (та, что слева) добавляем 1, которую мы запомнили на предыдущем шаге. Получаем 10. Это число записываем снизу. В результате получилось число 100000000, равное 256, если рассматривать его в десятичной форме. Но в типе unsigned char используется только 1 байт, состоящий из 8-ми двоичных разрядов (бит). В результате в этот байт помещаются 8 полученных нулей (они обведены красным прямоугольником), а девятый разряд 1 не помещается в нашу переменную. Число 00000000 в десятичной форме равно 0. В результате мы получили, что 255 + 1 = 0.

Рассмотрим другой пример сложим числа типа unsigned char 250 и 10 (в двоичной форме 11111010 и 1010 соответственно):

Читайте также:  Медведки морские как чистить

В результате получилось число 100000100, которое соответствует десятичному числу 260. Однако, старшая (девятая) единица снова не поместилась в один байт. Поэтому в переменной осталось число 00000100, равное 4 в десятичной форме. Итак, 250 + 10 = 4.

На самом деле такой результат не является ошибкой. Ни среда разработки, ни программа, ни операционная система никак не отреагируют на неверный результат, поскольку переполнение является обычной ситуацией в процессе работы центрального процессора или контроллера. За эту ошибку ответственен только программист, который неверно подобрал тип переменной. Поэтому необходимо внимательно подходить к выбору типа.

Скачайте следующую программу, написанную на языке C ++, поместите скачанный файл TYPES 02. CPP в папку C :\ TCPP \ BIN \.

Запустите DOSBox (Как настроить эту программу можно посмотреть ЗДЕСЬ).

Нажмите клавишу F 3. Выберите файл TYPES . CPP и нажмите клавишу Enter .

На экране должна появиться открытая программа TYPES 02. CPP :

Эта программа демонстрирует возможности использования переменных нескольких типов. Разберем эту программу построчно:

# include iostream . h > — подключаем модуль iostream . h . В этом модуле содержится функция cout , которая используется в этой программе ниже. Она необходима для вывода информации на экран.

# include conio . h > — подключаем модуль conio . h , содержащий функции clrscr () и getch ();

void main () <— описываем заголовок функции main . Это главная функция. Она должна быть в каждой программе на языке С ++. v oid – это тип функции main . Void – означает, что наша функция ничего не возвращает. Пустые скобки () означают, что у этой функции нет входных параметров. Любая функция начинается c открывающейся фигурной скобки <, а заканчивается закрывающейся фигурной скобкой > .

clrscr ( ); — функция, которая очищает экран.

unsigned char a 1, b 1, c 1; — объявляем три переменные – a 1, b 1 и c 1 типа unsigned char .

cout unsigned char :\ n «; — выводим на экран надпись « unsigned char :». Обратите внимание на специальную комбинацию символов « \ n ». Когда программа встречает эту комбинацию при выводе текста на экран, она переводит курсор на новую строчку.

a 1=100; — переменной a 1 присваиваем значение 100.

b 1=15; — переменной b 1 присваиваем значение 15.

c 1= a 1+ b 1; — переменной c 1 присваиваем сумму значение переменных a 1 и b 1.

cout int ( a 1) int ( b 1) int ( c 1) n «; — выводим на экран сначала значение переменной a 1, затем текст « + », затем значение переменной b 1, потом текст « = », затем значение переменной с1, и в конце выводим текст « \ n », что означает переход курсора на следующую строчку. Обратите внимание, что в этой функции мы не просто пишем имя переменной, а предварительно преобразуем ее тип из unsigned char в int с помощью функции int (). Это нужно для того, чтобы числа типа unsigned char или char корректно отображались на экране. Если не преобразовать тип переменной в тип int , то функция cout посчитает, что мы хотим вывести не числа, а символы, которые соответствуют этим числам в таблице символов ACSII (об этом мы поговорим в другой раз).

a 1=255; — переменной a 1 присваиваем значение 255.

b 1=1; — переменной b 1 присваиваем значение 1.

c 1= a 1+ b 1; — переменной c 1 присваиваем сумму значение переменных a 1 и b 1.

cout int ( a 1) int ( b 1) int ( c 1) n «; — выводим на экран информацию. Аналогично описанному выше.

unsigned int a 2, b 2, c 2; — объявляем три переменные – a 2, b 2 и c 2 типа unsigned int .

cout nunsigned int :\ n «; — переводим курсор на следующую строчку («\ n » в начале текста), выводим на экран надпись « unsigned int :» и переводим курсор на следующую строчку («\ n »).

a 2=50000; — переменной a 2 присваиваем значение 50000.

b 2=153; — переменной b 2 присваиваем значение 153.

c 2= a 2+ b 2; — переменной c 2 присваиваем сумму значение переменных a 2 и b 2.

cout a 2 b 2 c 2 n «; — вывод результата на экран, как описано выше. Поскольку теперь переменные имеют тип unsigned int , для них уже не нужно использовать функцию преобразования типа int ();

a 2=65530; — переменной a 2 присваиваем значение 65530.

b 2=15; — переменной b 2 присваиваем значение 15.

c 2= a 2+ b 2; — переменной c 2 присваиваем сумму значение переменных a 2 и b 2

cout a 2 b 2 c 2 n «; — Выводим на экран результат.

int a 3, b 3, c 3; — объявляем три переменные – a 3, b 3 и c 3 типа int .

cout nint :\ n «; — переводим курсор на следующую строчку («\ n » в начале текста), выводим на экран надпись « int :» и переводим курсор на следующую строчку («\ n »). Далее все аналогично предыдущим примерам.

getch (); — это функция ждет нажатия клавиши. Если не использовать эту функцию, то программа после вывода результата просто закроется, но благодаря функции getch () программа не закроется, пока не будет нажата любая клавиша.

> – конец функции main .

Чтобы запустить программу, нажимаем комбинацию клавиш Alt + R , выбираем в появившемся меню пункт Run и нажимаем клавишу Enter . Ни в коем случае не нажимайте для запуска программы комбинацию клавиш Ctrl + F 9 – это закроет DOSBox !

На экране появится результат работы программы:

При нажатии на любую клавишу программа закроется.

Для каждого типа мы видим два результата: первый результат имеет правильное значение, а второй нет, поскольку произошло переполнение.

Задание: 1) Какой будет результат сложения переменных a 1 и b 1 типа unsigned char , если a 1=200, а b 1=100? Внесите эти данные в программу, запустите ее и посмотрите результат. 2) Присвойте переменным свои значения и посмотрите результат. 3) вместо сложения, попробуйте другие операции: вычитание (-), умножени е( *), деление (/).

Источник

Форматированный ввод и вывод

Форматированный вывод

Сегодня мы рассмотрим две важные функции форматированного ввода и вывода. Устройство и работу этих функций полностью можно понять только после изучения работы с указателями и функций с переменным числом параметров. Но пользоваться этими функциями необходимо уже сейчас, так что некоторые моменты придётся пропустить.

Функция форматированного вывода printf получает в качестве аргументов строку формат и аргументы, которые необходимо вывести в соответствии с форматом, и возвращает число выведенных символов. В случае ошибки возвращает отрицательное значение и устанавливает значение ferror. Если произошло несколько ошибок, errno равно EILSEQ.
int printf (const char * format, . );

Функция проходит по строке и заменяет первое вхождение % на первый аргумент, второе вхождение % на второй аргумент и т.д. Далее мы будем просто рассматривать список флагов и примеры использования.

Общий синтаксис спецификатора формата
%[флаги][ширина][.точность][длина]спецификатор
Спецификатор – это самый важный компонент. Он определяет тип переменной и способ её вывода.

Таб. 1 Спецификатор типа.

Спецификатор Что хотим вывести Пример
d или i Целое со знаком в в десятичном виде 392
u Целое без знака в десятичном виде 7235
o Беззнаковое в восьмеричном виде 657
x Беззнаковое целое в шестнадцатеричном виде 7fa
X Беззнаковое целое в шестнадцатеричном виде, верхний регистр 7FA
f или F Число с плавающей точкой 3.4563745
e Экспоненциальная форма для числа с плавающей точкой 3.1234e+3
E Экспоненциальная форма для числа с плавающей точкой, верхний регистр 3.1234E+3
g Кратчайшее из представлений форматов f и e 3.12
G Кратчайшее из представлений форматов F и E 3.12
a Шестнадцатеричное представление числа с плавающей точкой -0xc.90fep-2
A Шестнадцатеричное представление числа с плавающей точкой, верхний регистр -0xc.90FEP-2
c Буква a
s Строка (нуль-терминированный массив букв) Hello World
p Адрес указателя b8000000
n Ничего не печатает. Аргументом должен быть указатель на signed int. По этому адресу будет сохранено количество букв, которое было выведено до встречи %n
% Два идущих друг за другом процента выводят знак процента %

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

Таб. 2 Флаги.

Флаг Описание
Выключка влево на заданное шириной значение
+ Явно указывать знак у числа, даже для положительных чисел
(пробел) Если знак не будет выведен, то вставляет пробел перед выводимым числом
# Когда используется вместе с o, x или X, вставляет перед числом 0, 0x или 0X
Когда используется со спецификаторами a, A, e, E, f, F, g или G, вставляет десятичную точку, даже если после неё нет десятичных знаков.
0 Вставляет нули, когда объявлен спецификатор ширины
Таб. 3 Ширина.
Ширина Описание
(число) Минимальное количество знаков, которое необходимо вывести. Если в числе меньше знаков, то вставляет пробелы (или нули)
* Ширина не указана в строке формата, она передаётся отдельно в виде аргумента, который должен предшествовать выводимому числу
Таб. 4 Точность.
.Точность Описание
.число Для спецификаторов целых (d, i, o, u, x, X) точность определяет минимальное количество знаков, которое необходимо вывести. Если значение короче, то выводятся нули перед числом. Значение не обрезается, даже если оно длиннее. Точночть 0 означает, что для значения 0 ничего не выводится.
Для спецификаторов чисел с плавающей точкой (a, A, e, E, f, F) это число знаков, которые необходимо вывести после десятичной точки (по умолчанию 6).
Для g и G — это число значащих разрядов, которые необходимо вывести.
Для s — выводится указанное число символов. По умолчанию выводятся все символы до первого нулевого.
Если число не стоит, то по умолчанию точность равна 0
.* Точность не указана в строке формата, она передаётся отдельно в виде аргумента, который должен предшествовать выводимому числу

Суб-спецификатор длины изменяет длину типа. В случае, если длина не совпадает с типом, по возможности происходит преобразование до нужного типа.

Таб. 5 Длина.

спецификаторы
Длина d, i u o x X f F e E g G a A c s p n
(none) int unsigned int double int char* void* int*
hh signed char unsigned char signed char*
h short int unsigned short int short int*
l long int unsigned long int wint_t wchar_t* long int*
ll long long int unsigned long long int long long int*
j intmax_t uintmax_t intmax_t*
z size_t size_t size_t*
t ptrdiff_t ptrdiff_t ptrdiff_t*
L long double

Форматированный ввод

Рассмотрим форматированный ввод функцией scanf.
int scanf(const char*, . )
Функция принимает строку формата ввода (она похожа на строку формата printf) и адреса, по которым необходимо записать считанные данные. Возвращает количество успешно проинициализированных аргументов.
Формат спецификатора ввода
%[*][ширина][длинна]спецификатор

Таб. 6 Спецификатор типа.

Спецификатор Описание Выбранные символы
i, u Целые Произвольное число цифр (0-9), возможно, начинающихся с + или -. Если число начинается с 0, то считывается в восьмеричном формате, если с 0x, то в шестнадцатеричном.
d Десятичное целое Произвольное число цифр (0-9), возможно, начинающихся с + или -.
o восьмеричное целое Произвольное число цифр (0-7), возможно, начинающихся с + или -.
x Шестнадцатеричное целое Произвольное число цифр (0-F), возможно, начинающихся с + или — и префикса 0x или 0X.
f, e, g Число с плавающей точкой Число, состоящее из набора цифр 0-9, возможно с десятичным разделителем (точкой). Возможно также представление в экспоненциальной форме. C99 позволяет также вводить число в шестнадцатеричном формате.
a
c Символ Если ширина не передана, то считывает один символ. Если ширина передана, то считывает нужное количество символов и размещает их в массиве БЕЗ терминального символа на конце.
s Строка Считывает все не пробельные символы. Если указана ширина, то не более n символов. Ставит на место n+1 символа терминальный.
p Адрес указателя Последовательность символов, трактуемая как адрес указателя. Формат зависит от реализации, но совпадает с тем, как выводит printf с ключом p
[символы] Множество символов Считывает только те символы, которые записаны в квадратных скобках, С99
[^символы] Множество символов Считывает только те символы, которые не указаны в квадратных скобках, С99
n Ничего не считывает Сохраняет число уже считанных символов по указанному адресу

Как и в printf, ширина, заданная символом * ожидает аргумента, который будт задавать ширину. Флаг длина совпадает с таким флагом функции printf.

Кроме функций scanf и printf есть ещё ряд функций, которые позволяют получать вводимые данные

int getch() [aka _getch(), getchar()] — возвращает введённый символ, при этом не выводит его на консоль.

char * fgets ( char * str, int num, FILE * stream ) — функция позволяет считывать строку с пробельными символами. Несмотря на то, что она работает с файлом, можно с её помощью считывать и из стандартного потока ввода. Её преимущество относительно gets в том, что она позволяет указать максимальный размер считываемой строки и заканчивает строку терминальным символом.

Это не полный набор различных функций символьного ввода и вывода. Таких функций море, но очень многие из них небезопасны, поэтому перед использованием внимательно читайте документацию.

Непечатные символы

В си определён ряд символов, которые не выводятся на печать, но позволяют производить форматирование вывода. Эти символы можно задавать в виде численных значений, либо в виде эскейп-последовательностей: символа, экранированного обратным слешем.

Источник

Оцените статью