Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

учебное пособие. Часть1. Информатика

.pdf
Скачиваний:
42
Добавлен:
04.06.2015
Размер:
2.87 Mб
Скачать

Рис. 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=1e07

a=1.234500

b=0.000000

a=1.234500e+00 b=1.000000e07

a=1.2345 b=1e07

0.000

a=

1.235 b=

a=1.23e+00 b=1.00e07

Если для чисел с плавающей точкой указывается только количество по- зиций в числе, без указания числа позиций после запятой, то в этом случае по умолчанию выводится шесть знаков после запятой, занимая указанное коли- чество позиций. Если ширина поля не указывается совсем, то каждое число будет иметь шесть знаков после запятой, а ширина будет достаточной, чтобы напечатать число целиком.

Функции потокового ввода и вывода

На равных правах со стандартной библиотекой ввода-вывода использу- ется библиотека классов, которая становится доступной в программе, как

только в нее включен файл iostream.h.

Вэтом случае применяется механизм потокового ввода-вывода. Поток это последовательность байтов (символов) и сточки зрения программы не за- висит от тех конкретных устройств (файл на диске, принтер, клавиатура, мо- нитор и т. д.), с которыми ведется обмен данными.

Впрограммах обычно используются стандартные потоки:

cout стандартный поток вывода (экран)

cerr – стандартный поток вывода ошибок (экран) cin – стандартный поток ввода (клавиатура)

Помещение (направление) данных в поток осуществляется с помощью оператора <<. Переменную любого встроенного типа можно вывести, ис- пользуя следующую запись:

cout << "x=" << x;

Ввод данных из потока осуществляется аналогично с использованием обратного оператора >>. Переменную любого встроенного типа можно вве- сти (считать) из потока:

cin >>x;

170