учебное пособие. Часть1. Информатика
.pdfРис. 8. Дерево типов
Вэтом строгом требовании языка С++ проявляется тенденция развития
языков программирования в сторону повышения надежности создаваемых программ. При описании переменные можно инициализировать. На рис. 8 приведено “дерево” типов данных С++. В этом разделе рассмотрим целые и вещественные типы данных.
ВC++ нет жёсткого стандарта на диапазоны значений арифметических типов (в стандарте языка оговариваются лишь минимально допустимые зна- чения). В принципе, эти диапазоны определяются конкретной реализацией.
Диапазон возможных значений целых типов зависит от их внутреннего представления, которое может занимать один, два или четыре байта. В табл.
161
3 приводятся названия целых типов, их длина в байтах и диапазон возмож- ных значений (для ВС++3.1). Целые типы относят порядковым типам. Для порядковых типов характерно то, что такие типы имеют конечное число воз- можных значений, их можно каким-либо образом упорядочить и каждому поставить в соответствие целое число.
|
|
|
|
Таблица 2 |
|
|
|
Целые типы |
|
|
|
|
|
|
Длина, |
Название |
|
Назначение |
Диапазон значений |
байт |
типа |
|
типа |
|
|
|
|
Небольшие целые |
|
1 |
unsigned char |
|
числа и коды сим- |
от 0 до 255 |
|
|
|
волов |
|
|
|
|
Очень малые це- |
от −128 до 127 |
1 |
char |
|
лых числа и ASCII- |
|
|
|
|
коды |
|
2 |
unsigned int |
|
Большие целые и |
от 0 до 65535 |
|
счетчики циклов |
|||
|
|
|
|
|
|
|
|
|
|
2 |
int |
|
Небольшие целые |
от −32768 до 32767 |
|
|
|
|
|
2 |
short int |
|
Небольшие целые |
от −32768 до 32767 |
|
|
|
|
|
4 |
unsigned long |
|
Астрономические |
От 0 до 4294967295 |
|
расстояния |
|||
|
|
|
|
|
|
|
|
|
|
4 |
long |
|
Большие числа |
от −2147483648 до |
|
2147483647 |
|||
|
|
|
|
|
Описание переменных целого типа может выглядеть так: |
||||
int a, b=0; |
|
|
||
long c; |
|
|
||
unsigned int d; |
|
|
Переменная b инициализирована при описании. Основные операции над целыми числами:
"+" – сложение; "*" – умножение; " / – деление; "−" – вычитание; "%" – получение остатка от целочисленного деления. Ранг выполнения операций такой же, как в математике.
В языке С++ специальной операции целочисленного деления нет, по- этому тип операции определяется типами операндов. Если оба операнда це- лые, то операция деления выполняется как операция целочисленного деле- ния. Если хотя бы один из операндов вещественный, то операция деления выполняется не как целочисленная. Например:
162
5/2 |
=2 |
|
5%2 |
= 1 |
6/2 |
= 3 |
6%3 |
= 0 |
|
5./2 = |
2.5. |
17%7 = 3 |
Для представления вещественных чисел используется вещественный тип, в котором для отделения целой части числа от дробной используется де- сятичная точка. Значение числа вещественного типа представляется в ЭВМ лишь с некоторой конечной точностью, которая зависит от внутреннего фор- мата вещественного числа. В табл. 4 приведены названия вещественных ти- пов, их длина в байтах, а также диапазон возможных значений(для ВС++3.1).
В программировании применяют две формы представления вещественных чисел: с фиксированной и с плавающей точками. Примеры записи вещест- венных чисел с фиксированной точкой приведены в первом столбце, а с пла-
вающей – во втором: |
|
1.36e0 |
|
|
||
1.36 |
|
|
|
|
|
|
0.0013 |
|
|
1.3e-3 |
|
|
|
123.123 |
|
|
1.23123e2 |
|
|
|
Переменные вещественного типа можно описать так: |
||||||
float a, b; |
|
|
|
|
||
double c, d; |
|
|
|
|
||
long double l, m, n; |
Таблица 3 |
|||||
|
|
|
|
|
||
|
|
|
Вещественные типы |
|
|
|
|
|
|
|
|
|
|
Длина, |
|
Название |
|
Диапазон десятичного |
Количество знача- |
|
байт |
|
|
порядка |
щих цифр |
|
|
|
|
|
|
|||
4 |
|
float |
|
от −38 до +38 |
от 7 до 8 |
|
|
|
|
|
|
|
|
8 |
|
double |
|
от −308 до +308 |
от 15 до 16 |
|
|
|
|
|
|
|
|
10 |
|
long double |
|
от −4932 до +4932 |
от 19 до 20 |
|
|
|
|
|
|
|
|
В приложении 1 приведены наиболее часто используемые функции для обработки данных вещественного типа. Этими функциями можно пользоваться только после подключения файла math.h с помощью ди-
рективы препроцессора include. Для вычисления модуля целого числа используется функция abs(x).
3.1.3. Оператор присваивания
Оператор присваивания является самым важным оператором в любом языке программирования. Этот оператор служит для изменения областей па- мяти. Оператор присваивания заменяет значение переменной, идентификатор
163
которой стоит в левой части оператора, значением выражения, стоящего в правой части, и имеет следующую форму:
<идентификатор переменной> = <выражение>
Необходимо учесть, что переменная и выражение должны быть согла- сованы по типам. Например, если переменные описаны следующим образом:
int x, y ; float a, b;
то можно записать операторы присваивания x = 2;
x = x+5;// заменить x на x+5 y = x;
a = b = 3.1;
b = 5.33*x+y/2;
Что происходит со старым значением переменной, когда ей присваива- ется новое значение? Оно просто стирается. Поскольку переменная может хранить только одно число, то выполнение оператора присваивания приво- дит к потере предыдущего значения переменной. Переменная всегда содер- жит результат последнего оператора присваивания.
Как отмечалось, тип переменной позволяет не только устанавливать длину ее внутреннего представления, но и контролировать те действия, кото- рые осуществляются над ней в программе. Ниже приведены схемы преобра- зования типов, гарантирующие сохранение точности и неизменность числен- ного значения [4]:
signed char Þ short Þ int Þ long float Þ double Þ long double
unsigned char Þ unsigned short Þ unsigned int Þ unsigned long
Для описанных выше переменных оператор x = a будет неверным, так как невозможно точно преобразовать вещественный тип к целому, а опе- ратор a = x будет верным. При этом сообщение об ошибке выдаваться не будет, так как язык С++ относится менее жестко, чем скажем Паскаль, к со- ответствию типов.
В языке С считается, что все арифметические операции выполняются с двойной точностью [7]. Поэтому всякий раз, когда в выражении появляются значение с плавающей точкой, его “удлиняют” до удвоенной точности, до- бавляя к дробной части нули. При преобразовании значения с двойной точ- ностью к одинарной, например, при присваивании, прежде чем отбросить лишние для обычной точности разряды, происходит округление.
Кроме автоматических преобразований типов, существуют явные пре- образования типов. Синтаксис использования явного преобразования типов имеет две различные формы:
(имя_типа) операнд
или
164
имя_типа (операнд).
Во второй форме не может использоваться составное наименование типа (например, unsigned short). Как и при автоматическом преобра- зовании типов, ответственность за сохранение значения и точности результа- та лежит на разработчике программы.
Пример pr2 демонстрирует, какие последствия можно иметь от преоб- разования типов:
//Пример pr2 #include <cstdio> using namespace std; int main ()
{
long a=123456789; float b;
int rezult1, rezult2; rezult1=1.6+1.7;
rezult2 = (int)1.6+(int)1.7; printf("\nrezult1=%d",rezult1);//Печатает rezult1=3 printf("\nrezult2=%d",rezult2);//Печатает rezult2=2
b = (float)a; |
//Печатает a=123456789 |
printf ("\n a=%ld",a); |
|
printf ("\n b=%e",b); |
//Печатает b=1.2345689e+08 |
a = (long)b; |
//Печатает a=123456792 |
printf ("\n a=%ld",a); |
|
b = 2.222222e+2; |
|
rezult1 = (int)b; |
//Печатает b=222.222198 |
printf ("\n b=%f", b); |
printf("\nrezult1=%d",rezult1);//Печатает rezult1=222 b = (float)rezult1;
printf ("\n b=%f", b); //Печатает rezult1=222.000000 return 0;
}
Кроме классической записи оператора присваивания, в языке С++ ис- пользуются операции увеличения ++ и уменьшения −−. Операция увеличе- ния увеличивает свой операнд на 1, а операция уменьшения уменьшает свой операнд на 1. Существует две формы этих операций: постфиксная и пре- фиксная. Разница между ними заключается в том, что они показывают, в ка- кой момент осуществляется увеличение или уменьшение операнда:
x++ , x−− постфиксная запись; ++x, −−x префиксная запись.
В данных примерах форма записи никак не отражается на результате, а пример pr3 иллюстрирует разницу:
165
//Пример pr3 #include <cstdio> using namespace std; int main ()
{
int a, b, x; x = 0;
a = 5+x++; b = 5+ ++x;
printf ("a = %d\n b = %d", a, b); return 0;
}
Результатом работы этой программы будет вывод значений: a = 5
b = 7
При вычислении а к числу 5 добавляется х равное нулю, а потом х увеличивается на единицу. При вычислении b сначала х увеличивается на 1
истановится равным 2, а затем значение х добавляется к числу 5.
Воператорах присваивания можно использовать укороченную форму записи, например, запись a += 5 эквивалентна записи a = a + 5:
//Пример pr4 #include <cstdio> using namespace std;
int main () |
|
{ |
|
float a, b, x; |
|
a = b = x = 1; |
//Эквивалентно a = a+5 |
a += 5; |
|
b /= 5+x; |
//Эквивалентно b = b/(5+x) |
printf ("\na=%f\n b=%f", a, b); |
|
a- = 5; |
//Эквивалентно a = a-5 |
b* = 5+x; |
//Эквивалентно b = b*(5+x) |
printf ("\n a = %f\n b = %f", a, b); return 0;
}
Применение укороченной формы записи в операторах присваивания с небольшими выражениями делает их более "прозрачными", а операторы со сложными выражениями становятся более запутанными. Поэтому рекомен- дуется использовать эту возможность осторожно.
166
3.1.4. Функции ввода и вывода
Ввод/вывод связан с обменом информацией между оперативной памя- тью и внешними устройствами. Как уже говорилось, в языке С++ не преду- смотрены какие-либо встроенные средства для ввода и вывода. Ввод-вывод поддерживается с помощью библиотек. Поэтому, чтобы воспользоваться функциями ввода и вывода, необходимо с помощью директивы препроцессо- ра подключить файл, содержащий заголовки функций. В программах на язы- ке С++ можно использовать две библиотеки ввода-вывода: стандартную биб- лиотеку функций языка С и библиотеку классов, созданную специально для языка С++.
Функции ввода scanf и вывода printf
Функции ввода scanf и вывода printf – функции из стандартной библиотеки. Для их использования необходимо с помощью директивы пре-
процессора include подключить заголовочный файл stdio.h.
Функция вывода printf служит для вывода информации на монитор и имеет следующий синтаксис:
printf (<управляющая строка><список вывода>);
Здесь, <управляющая строка> − это строка символов, содержащая информацию, печатаемую текстуально, спецификации преобразования и спе- циальные символы. Управляющая строка определяет, каким образом будет распечатана информация.
В С++ чаще всего используются следующие специальные символы: \n – перевод курсора на новую строку;
\t – символ табуляции; \b – шаг назад;
\r – возврат каретки.
Также можно использовать константы, например ’\007’ (выдается короткий звуковой сигнал).
Спецификацию преобразования можно формально определить сле- дующим образом [1]:
%[флаг] [ширина] [.точность] [l, L] символ_формата
При описании синтаксиса в языках программирования принята нота- ция, означающая, что все, что стоит в квадратных скобках, является необяза- тельным. В данном случае обязательными являются только символ % и сим- вол_формата.
В качестве флага могут выступать следующие символы:
− выровнять значение по левому краю поля (т. е. добавить пробелы справа);
167
+ выровнять значение по правому краю поля, вывести обязательно знак значения.
При отсутствии флага выравнивание идет по правому краю и для неот- рицательных значений знак не выводится.
Ширина определяет минимальный размер поля вывода. Если в выво- димом числе символов больше, то поле автоматически увеличится. Точность
используется для определения количества выводимых позиций после запятой в поле вывода вещественного числа. Маркер l или L служит для указания це- лых длинных типов (long).
Назначение некоторых спецификаций преобразования приведены в табл. 6. <Список вывода> – это последовательность идентификаторов пе- ременных, констант, выражений, вычисляемых перед выводом на печать. Каждому аргументу из списка вывода должна соответствовать одна специ-
фикация преобразования.
Функция ввода scanf служит для чтения информации с клавиатуры и имеет следующий синтаксис:
scanf (<управляющая строка><список ввода>);
Здесь, <управляющая строка> − строка символов, содержащая спецификации преобразования и специальные символы. Каждому идентифи-
катору из списка ввода должна соответствовать строго одна спецификация преобразования; <cписок ввода> – это последовательность из одного или более идентификаторов переменных строкового типа, а также любого целого или вещественного типа. Перед каждым идентификатором должен стоять символ ам- персанд &, который означает, что в функцию передается адрес переменной, а не значение. Подробнее о передаче параметров в функции в разд.5. При вводе чи-
словых переменных функция scanf выделяет подстроку во входном потоке по следующему правилу: все ведущие пробелы, символы табуляции и маркеры кон- ца строки пропускаются, выделяется первый значащий символ, признаком конца
подстроки является любой из вышеперечисленных символов или символ конец файла. Выделенная таким образом подстрока рассматривается как символьное представление числовой константы, которое преобразуется в соответствии с ти- пом переменной, и полученное значение присваивается переменной. Если зна- чащих символов в строке нет, а список ввода еще не исчерпан, то автоматически осуществляется переход к новой строке.
168
Таблица 4
|
Спецификации преобразования |
|
|
Символ формата |
Тип выводимого объекта |
|
|
%c |
char |
|
|
%s |
Строка символов |
|
|
%d |
int |
|
|
%u |
unsigned int |
|
|
%ld |
long(в десятичном виде) |
|
|
%f |
float/double(с фиксированной точкой) |
|
|
%e |
float/double(в экспоненциальной форме) |
|
|
%lu |
unsigned long |
|
|
%g |
float/double(в виде f или е в зависимости от значения) |
|
|
%lf |
long double (с фиксированной точкой) |
|
|
%le |
long double(в экспоненциальной форме) |
|
|
%lg |
long double(в виде f или е в зависимости от значения) |
|
|
В pr5 приведены примеры различного использования функций ввода и вывода scanf и printf. Чтобы разобраться во всех нюансах работы этих функций, необходимо провести самостоятельно дополнительные экспери- менты.
//Пример pr5 #include <cstdio> using namespace std; int main ()
{
float a, b; int x, y;
printf ("Введите целые x и y");
scanf ("%d%d",&x, &y); //При вводе числа разделяются // пробелами или символом конец строки
printf (" x=%d y=%d \n x=%7d y=%2d",x, y, x, y); printf ("Введите вещественные a и b "); scanf("%g%f", &a, &b);
//Вывод с различными спецификациями преобразования printf ("a = %g b = %g\n a = %f b = %f\n a = %e b = %e \n", a, b,a, b, a, b);
// Вывод с различной точностью
169
printf ("a = %10.3f b = %10.3f \n a = %7.2e b = %7.2e \n", a, b, a, b);
return 0;
}
Если введем x = 12345, y = 6789, a = 1.2345 и b =0.0000001, то получим следующий результат:
x=12345 y=6789
x= |
12345 y=6789 |
|
a=1.2345 b=1e−07 |
||
a=1.234500 |
b=0.000000 |
a=1.234500e+00 b=1.000000e−07
a=1.2345 b=1e−07 |
0.000 |
|
a= |
1.235 b= |
a=1.23e+00 b=1.00e−07
Если для чисел с плавающей точкой указывается только количество по- зиций в числе, без указания числа позиций после запятой, то в этом случае по умолчанию выводится шесть знаков после запятой, занимая указанное коли- чество позиций. Если ширина поля не указывается совсем, то каждое число будет иметь шесть знаков после запятой, а ширина будет достаточной, чтобы напечатать число целиком.
Функции потокового ввода и вывода
На равных правах со стандартной библиотекой ввода-вывода использу- ется библиотека классов, которая становится доступной в программе, как
только в нее включен файл iostream.h.
Вэтом случае применяется механизм потокового ввода-вывода. Поток – это последовательность байтов (символов) и сточки зрения программы не за- висит от тех конкретных устройств (файл на диске, принтер, клавиатура, мо- нитор и т. д.), с которыми ведется обмен данными.
Впрограммах обычно используются стандартные потоки:
cout – стандартный поток вывода (экран)
cerr – стандартный поток вывода ошибок (экран) cin – стандартный поток ввода (клавиатура)
Помещение (направление) данных в поток осуществляется с помощью оператора <<. Переменную любого встроенного типа можно вывести, ис- пользуя следующую запись:
cout << "x=" << x;
Ввод данных из потока осуществляется аналогично с использованием обратного оператора >>. Переменную любого встроенного типа можно вве- сти (считать) из потока:
cin >>x;
170