Файл: Лабораторная работа 1 Изучение среды разработки программ 3 Лабораторная работа 2 Исследование базовых типов данных языка Си 18.doc

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 05.12.2023

Просмотров: 281

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

Лабораторная работа № 1Изучение среды разработки программ

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

Лабораторная работа № 2Исследование базовых типов данных языка Си

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

Лабораторная работа № 3Исследование операций языка Си Цель занятия: Совершенствование навыков объявления, инициализации переменных и ввода и вывода информации Совершенствование навыков разработки программ в среде программирования MS Visual C++ Исследование возможностей языка С++ для реализации арифметических, логических и поразрядных операций над данными Время на выполнение работы: 4 часаПрограмма исследований: Исследование арифметических операций Исследование логических операций Исследование поразрядных операций Подготовка к выполнению работы: Изучить рекомендованную литературу (структура программы на языке высокого уровня, алфавит и элементарные конструкции языка Си, переменные и константы, стандартные типы данных, выражения и операции в языке Си). Изучить материал настоящего руководства. Материалы для подготовки к занятию: Конспект лекций. [1] стр. 31-38. Содержание отчета: Цели исследования. Программа работы. Листинги программ. Результаты исследований. Выводы по каждому пункту и общий вывод. МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ Любое выражение языка состоит из операндов (переменных, констант и др.), соединенных знаками операций. Знак операции - это символ или группа символов, которые сообщают компилятору о необходимости выполнения определенных арифметических, логических или других действий. Операции выполняются в строгой последовательности. Величина, определяющая преимущественное право на выполнение той или иной операции, называется приоритетом. В таблице 3.1 перечислены различные операции языка Си. Их приоритеты для каждой группы одинаковы. Чем большим преимуществом пользуется соответствующая группа операций, тем выше она расположена в таблице. Приоритеты могут регулироваться с помощью круглых скобок. Таблица 3.1 – Операции языка Си Знак операции Назначение операции ( ) Вызов функции [ ] Выделение элемента массива . Выделение элемента записи -> Выделение элемента записи (тождественно(.)) ! Логическое отрицание Поразрядное отрицание - Изменение знака ++ Увеличение на единицу -- Уменьшение на единицу & Взятие адреса * Обращение по адресу (тип) Преобразование типа (т.е. (float) a) sizeof( ) Определение размера в байтах * Умножение / Деление % Определение остатка от деления + Сложение - Вычитание << Сдвиг влево >> Сдвиг вправо < Меньше, чем <= Меньше или равно > Больше, чем >= Больше или равно = = Равно != Не равно & Поразрядное логическое "И" ^ Поразрядное исключающее "ИЛИ" | Поразрядное логическое "ИЛИ" && Логическое "И" || Логическое "ИЛИ" ?: Условная (тернарная) операция = Присваивание +=, - =, *=, /=, %=, <<=,>>=, &=, |=, ^= Бинарные операции (например, а *= b(т.е. a = a * b) и т.д.) , Операция запятая Для исключения путаницы в понятиях "операция" и "оператор", необходимо отметить, что оператор - это наименьшая исполняемая единица программы. Различают операторы выражения, действие которых состоит в вычислении заданных выражений (например: a = sin(b)+c; j++;), операторы объявления, составные операторы, пустые операторы, операторы метки, цикла и т.д. Для обозначения конца оператора в языке С++ используется точка с запятой. Что касается составного оператора (или блока), представляющего собой набор логически связанных операторов, помещенных между открывающей ({) и закрывающей (}) фигурными скобками ("операторными скобками"), то за ним точка с запятой не ставится. Отметим, что блок отличается от составного оператора наличием определений в теле блока. Охарактеризуем основные операции языка С++. Сначала рассмотрим одну из них - операцию присваивания (=). Выражение вида х = у + z;присваивает переменной х значение суммы переменных у и z. Наличие « ; » в конце операции говорит о том, что записан оператор. На первый взгляд все просто. Но очень часто у начинающих программистов возникает путаница в понимании этого оператора. Это связано с тем, что с точки зрения математики следующие два выражения в общем-то эквивалентны:х = у + z;у + z = х;Но программирование – есть процесс записи на формализованном языке последовательности команд, которые необходимо выполнить для достижения конечного результата. Из этого аспекта и вытекает ключевая разница из этих, казалось бы, тождественных выражений.Для любого языка программирования операция присваивания « = » в обязательном порядке подразумевает следующий порядок ее выполнения. Справа от знака « = » задается источник присваивания (то, что присваивается), а слева – приемник (или то, чему присваивается источник): х = у + z; Приемник Источник Первым вычисляется результат источника, который затем присваивается приемнику, НО НЕ НАОБОРОТ! Именно поэтому выражение у + z = х не имеет смысла! Источником может быть любая последовательность операций. Приемником – только переменная.По этой же причине оператор у + z;тоже бессмыслен, так как результат операции никуда не сохранен! (За исключением использования механизма перегрузки операции в классах, который будет рассмотрен во втором семестре). Операцию "=" разрешается использовать многократно в одном выражении, например: x = y = z = 100;Различают унарные, бинарные итернарные операции. У первых из них один операнд, у вторых – два и у третьих - три. В языке Си выделяют три группы операций: арифметические операции; логические операции и операции отношения; операции с битами. 1. Арифметические операции задаются следующими символами (таблица 3.1): +, -, *, /, %, -, !, . Например: a = b + c;a = b - c;a = b * c;a = b / c;a = b % c; a = !b;a = -b;a = b;a = sizeof (b);Операции +, -, * интуитивно понятны и не нуждаются в объяснении.Операции увеличения и уменьшения на 1 (++ и --).Эти операции, называемые также инкрементом и декрементом, имеют две формы записи - префиксную, когда операция записывается перед операндом, и постфиксную. В префиксной форме сначала изменяется операнд, а затем его значение становится результирующим значением выражения, а в постфиксной значением выражения является исходное значение операнда, после чего он изменяется.Операция определения размера sizeof предназначена для вычисления размера объекта или типа в байтах, и имеет две формы:sizeof выражение или sizeof( тип )Операции отрицания (-, ! и ). Арифметическое отрицание (унарный минус-) изменяет знак операнда целого или вещественного типа на противоположный. Логическое отрицание(!) дает в результате значение 0, если операнд есть истина( не нуль), и значение 1, если операнд равен нулю. Операнд должен быть целого или вещественного типа, а может иметь также тип указатель. Поразрядное отрицание(), часто называемое побитовым, инвертирует каждый разряд в двоичном представлении целочисленного операнда.Деление (/) и остаток от деления(%). Операция деления применима к операндам арифметического типа. Если оба операнда целочисленные, результат операции округляется до целого числа, в противном случае тип результата определяется правилами преобразования. Операция остатка от деления применяется только к целочисленным операндам. Знак результата зависит от реализации.Бинарные операции +=, -=, *= и /= эквивалентны следующим: a += 3;a -= 3;a *= 3;a /= 3;  a = a + 3;a = a - 3;a = a * 3;a = a / 3; 2. Поразрядные операции задаются следующими символами (таблица 3.1): <<, >>, &, |, ^. Например:a = b << 3;a = b >> 2;a = b & c;a = b | c;a = b ^ c;Операции сдвига (<< и >>) применяются целочисленным операндам. Они сдвигают двоичное представление первого операнда влево или вправо на количество двоичных разрядов, заданное вторым операндом. При сдвиге влево (<<) освободившиеся разряды обнуляются. При сдвиге вправо (>)освободившиеся биты заполняются нулями, если первый операнд беззнакового типа, и знаковым разрядом в противном случае. Операции сдвига не учитывают переполнение и потерю значимости.Примеры: int i=10, j, k ; /* i = 0000 1010 */k = i<<2 ; /* k = 0010 1000 */j = k<<1 ; /* j = 0101 0000 */i = j>>4 ; /* i = 0000 0101 */Битовые операции (&, |, ^) применяются только к целочисленным операндам и работают с их двоичными представлениями. При выполнении операций операнды сопоставляются побитового (первый бит первого операнда с первым битом второго, второй бит первого операнда со вторым битом второго, и т д.).При поразрядной конъюнкции, или поразрядном И (операция обозначается &) бит результата равен 1 только тогда, когда соответствующие биты обоих операндов равны 1.При поразрядной дизъюнкции, или поразрядном ИЛИ (операция обозначается |) бит результата равен 1 тогда, когда соответствующие биты хотя бы одного из операндов равен 1.При поразрядном исключающем ИЛИ (операция обозначается ^) бит результата равен 1 только тогда, когда соответствующий бит только одного из операндов равен 1.Примеры: int i=6, j=5, k ; /* i = 0110, *//* j = 0101 *//* --------- */k = i&j ; /* k = 0100 */k = i|j ; /* k = 0111 */k = j^j ; /* k = 0011 */3. Логические операции и операции отношения задаются следующими символами (таблица 3.1): <, <=, >, >=, ==, !=, &&, ||.Логические операции (&&и ||). Операнды логических операций И (&&) и ИЛИ (||) могут иметь арифметический тип или быть указателями, при этом операнды в каждой операции могут быть различных типов. Преобразования типов не производятся, каждый операнд оценивается с токи зрения его эквивалентности нулю (операнд, равный нулю, рассматривается как false, не равный нулю - как true).Результатом логической операции является true или false. Результат операции логическое И имеет значение true только если оба операнда имеют значение true. Результат операции логическое ИЛИ имеет значение true, если хотя бы один из операндов имеет значение true. Логические операции выполняются слева направо. Если значение первого операнда достаточно, чтобы определить результат операции, второй операнд не вычисляется. Результаты логических операций могут быть представлены следующим образом:Таблица 3.2 – Логические операции языка Си x y x && y x || y 0 0 0 0 0 1 0 1 1 0 0 1 1 1 1 1 Операции отношения (<, <=, >, >=, = =, !=) сравнивают первый операнд со вторым. Операнды могут быть арифметического типа или указателями. Результатом операции является значение true или false (любое значение, не равное нулю, интерпретируется как true). Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции сравнения. Результаты операций отношения могут быть представлены следующим образом:Таблица 3.3 – Операции отношения языка Си  x y x < y x <= y x > y x >= y x = = y x != y 0 0 false true false true true false 0 1 true true false false false true 1 0 false false true true false true 1 1 false true false true true false 1>2>1   2   3   4   5   6   7   8   9   ...   22

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ Исследование арифметических операций для заданных исходных данных исследовать влияние типа данных на конечный результат для всех арифметических операций. Пример:typedef signed short int INT;int main(int argc, char* argv[]){INT a=12678, b=-19003, c;float x=a,y=b,z;char d=156,e=68,f;cout<<"\n------------------\nInteger: a="<c=a-b; cout<<"\n-: "<c=a*b; cout<<"\n*: "<c=a/b; cout<<"\n/: "<c=a%b; cout<<"\n%: "<c=-a; cout<<"\n-: "<c=!a; cout<<"\n!: "<c=a; cout<<"\n

Лабораторная работа № 4Применение управляющих инструкций языка для организации ветвлений в программе

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

ЗАДАНИЕ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ

Лабораторная работа № 5Исследование циклов

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

Лабораторная работа № 6Применение массивов и указателей для решения прикладных задач

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

Лабораторная работа № 7Исследование массивов и указателей

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

Лабораторная работа № 8Применение функций работы со строками для решения прикладных задач

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

Практическое занятие № 6Использование функций для работы с массивами

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

Практическое занятие № 7Программирование рекурсивных алгоритмов

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

Практическое занятие № 8Применение производных типов данных для решения прикладных задач

ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

ПРОГРАММА РАБОТЫ

Лабораторная работа № 5Исследование методов доступа к файлам данных

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

Лабораторная работа № 6Исследование связанных списков данных

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

ЗАДАНИЕ НА ИССЛЕДОВАНИЕ

ЛИТЕРАТУРА



Цель занятия:


  • Совершенствование навыков разработки программ в среде программирования MS Visual C++

  • Исследование диапазонов представимости стандартными типами данных числовой информации

  • Исследование допустимых преобразований типов данных в языке Си


Время на выполнение работы: 2 часа
Программа исследований:


  1. Исследование размерности типов данных и диапазона их представимости

  2. Исследование порядка преобразования типов данных


Подготовка к выполнению работы:


  1. Изучить материал настоящего руководства и рекомендованную литературу (структура программы на языке высокого уровня, алфавит и элементарные конструкции языка Си, переменные и константы, стандартные типы данных).

  2. Практически освоить порядок работы на ПЭВМ в среде программирования Visual C++.


Материалы для подготовки к занятию:


  1. Конспект лекций

  2. [1] стр. 22-26


Содержание отчета:


  1. Цели исследования.

  2. Программа работы.

  3. Листинги программ.

  4. Результаты исследований.

  5. Выводы по каждому пункту и общий вывод.

МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ



Как известно, принцип микропрограммного управления предполагает хранение и программы и данных в памяти вычислительной системы. Каждая отдельная единица этих данных хранится в ячейках памяти, имеющих свои адреса. С точки зрения принципа действия ЭВМ заранее неизвестно, в каких конкретно ячейках памяти и с какими адресами будут храниться эти данные. Поэтому удобно абстрагироваться от знания конкретного адреса той или иной ячейки памяти, в которую будет записано то или иное данное. Удобно позволить программисту дать некоторое смысловое имя той области памяти, в которую он планирует записать данные, а операционную систему обязать выделять ячейки памяти для хранения этих данных. При этом, операционная система (а не программист!) будет отслеживать соответствие между этим смысловым именем и адресами ячеек, в которых хранятся данные, помеченные смысловым именем. Программист же будет помнить не конкретный физический адрес хранения своих данных, а понятное и легко запоминаемое смысловое имя. Поэтому в языках программирования введено понятие переменной, позволяющее отвлечься от конкретных адресов и обращаться к содержимому памяти с помощью идентификатора (смыслового имени или имени переменной). При этом имя переменной будет указывать на хранимое в памяти значение, о реальном адресе и способе хранения которого можно забыть.


В языке Си определены требования к назначению имен идентификаторов:

  • идентификатор может содержать только буквы латинского алфавита, цифры и символ подчеркивания «_»;

  • идентификатор не должен начинаться с цифры;

  • в имени идентификатора не допускаются пробелы;

  • в идентификаторе строчные и прописные буквы различаются;

  • идентификатор не должен совпадать ни с одним из ключевых слов.

Приведем примеры правильных и неправильных идентификаторов (имен переменных):


Правильно

Неправильно

Правильно

Неправильно

Step10

10Step

F_I_O

F.I.O

Step_10

Step-10

MyAge

My Age

_Step10

_Step 10

Floor3

Этаж3


При этом, переменные MyName, Myname, myname, myName, MYNAME являются разными!!!

Таким образом, переменные предназначены для хранения данных. Здесь уместен вопрос – а каких данных? Ведь данные бывают разные. Например 3.14159 – это вещественное число, ‘W’ – символ, а «встретимся завтра в 8» - набор символов, называемых строкой. И число, и символ, и строка – это данные. Следовательно, для хранения этих данных необходимо различное количество ячеек памяти. Тогда, целесообразно выделить основные типы данных (то есть, произвести их классификацию) и для каждого типа данных выделить свое количество ячеек памяти, достаточное для хранения этих данных.

В языке Си выделены следующие основные типы данных:

  • целое число – тип данных int;

  • вещественное число – тип данных float, double;

  • символ – тип данных char;

  • логическая величина – тип данных bool.

Теперь необходимо вспомнить из курса «Информатика», что вся память ЭВМ разбита на ячейки памяти длиной по 8 бит, или 1 байт. В одну ячейку памяти можно записать 256 различных комбинаций 0 и 1, так как данные в памяти хранятся в двоичной системе исчисления. Таким образом, в одну ячейку памяти можно записать, например, целые числа от 0 до 255, в две – до 65535, в четыре – до 4294967295 и так далее. При этом, числа бывают не только положительными, но и отрицательными. Следовательно, к стандартным типам данных необходимо добавить некоторые модификаторы, которые говорили бы, какое это число. Например, двухбайтное знаковое целое – диапазон от – 32768 до + 32767.



Итак, в языке Си существует четыре спецификатора типа, уточняющих внутреннее представление и диапазон значений стандартных типов:

  • short – короткий;

  • long – длинный;

  • signed – знаковый;

  • unsigned – беззнаковый.

В соответствии с этими модификаторами приведем классификацию основных типов данных (размеры для 32-х битного процессора):
Таблица 1 – Классификация основных типов данных


Тип

Диапазон значений

Размер (байт)

bool

true

и

false

1

signed char

-128



+127

1

unsigned char

0



255

1

signed short int

-32768



+32767

2

unsigned short int

0



65535

2

signed long int

-2147483648



+2147483647

4

unsigned long int

0



4294967295

4

float

-3.4*1038



+3.4*1038

4

double

-1.7*10308



+1.7*10308

8

long double

-3.4*104932



+3.4*104932

10


Необходимо обратить внимание на то, что ЭВМ хранит вещественные числа в научном формате, который отличен от общепринятого. Так, число -1.7*10308, записанное в обычном формате, в научном будет выглядеть следующим образом: -1.7e308, или, например +1.7*10-308 будет выглядеть как 1.7е-308.

Любая переменная в языке Си имеет еще одну немаловажную характеристику, о которой необходимо поговорить отдельно. Любой объект или процесс в окружающем нас мире (как и сама наша жизнь) имеет свою продолжительность, или время жизни (существования). Вечна разве что Вселенная. Аналогично, и любая переменная имеет свое время жизни. Только для переменных время жизни определяется местом ее определения. Переменные в языке Си классифицируются по области видимости и делятся на две категории: локальные и глобальные. Рассмотрим их.


Локальная переменная – это такая переменная, которая объявлена внутри какого-либо блока (под блоком в языке Си понимается последовательность операторов, заключенная в фигурные скобки). Память под эту переменную выделяется в момент выполнения оператора ее объявления. По завершении работы блока эта переменная разрушается, а занимаемая ей память высвобождается. Таким образом, время жизни такой переменной ограничено тем блоком, в котором она объявлена.

Глобальная переменная – это такая переменная, которая объявлена вне любого блока. Следовательно, время ее жизни – время жизни самой программы.

Еще одним отличием локальной переменной от глобальной является процедура их инициализации. Любая глобальная переменная при объявлении автоматически обнуляется, локальная – нет. Поэтому, если начальное значение локальной переменной при объявлении еще не известно, лучше ее принудительно обнулить.

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

  • выбрать имя переменной (описать идентификатор);

  • определить исходя из необходимого диапазона представления чисел тип переменной;

  • определить область видимости переменной;

  • обнулить или проинициализировать переменную начальным значением.


Пример 1.

signed short int a=0.5; - объявлена двухбайтная знаковая целая переменная с именем a, которая проинициализирована начальным значением 0.5

unsigned char letter=’G’; - объявлена беззнаковая символьная переменная с именем letter, которая проинициализирована начальным значением ‘G’. Обратите внимание на то, что значения символьных переменных берутся в знаки апостроф – ‘’, а не в кавычки “”!

Для упрощения формы записи типов переменных некоторые наиболее часто используемые типы можно использовать по умолчанию без модификаторов. Так:

  • char равносильно signed char;

  • int равносильно signed long int;

  • long равносильно signed long int.

Одинаковость записи по умолчанию для int и long обусловлена тем, что ранее для 16-разрядного процессора под тип int по умолчанию выделялось 2 байта памяти, а не 4, как для 32-разрядного.

Неправильный выбор типа переменной зачастую ведет к потере исходных данных.


Рассмотрим пример 2.

. . .

signed short int a=-12350,b=0;

b=a*5;

cout<<b;

. . .

Вполне ожидаемый результат: - 61750. Но этого результата мы не увидим. На экране появится 3786!!! Откуда же это число. Давайте разберемся в том, что же произошло.

Под переменные a и b в памяти отведено по два байта. Причем, переменные объявлены как знаковые, следовательно, под значение самого числа выделено не 16 бит, а только 15, так как первый бит указывает на знак числа. Следовательно, диапазон представления числа не от 0 до 65535, а от -32768 до 32767. Число -61750 выходит за диапазон представления выбранного типа данных. Тогда как же оно связано с числом 3786?

Запустим программу в режиме отладки и выполним оператор b=a*5;. Затем откроем окно просмотра ассемблерного кода программы (Debug -> Windows -> Disassembly) и найдем там команду

0040106B mov word ptr [ebp-8],ax

О чем эта команда? 0040106Bэто адрес команды mov word ptr [ebp-8],ax в сегменте кода программы. mov – команда пересылки данных между регистрами и памятью: она пересылает содержимое регистра ax в область памяти по адресу [ebp-8], где ebp – адрес начала сегмента стека программы, а 8 – смещение относительно начала этого сегмента. Другими словами, эта команда как раз и заносит результат операции b=a*5;

в аккумулятор процессора. Давайте посмотрим, что же находится в этом самом регистре ax. Для этого откроем окно просмотра состояния регистров процессора (Debug -> Windows -> Registers), где найдем строку EAX = FFFF0ECA. FFFF0ECA – это и есть записанный в шестнадцатеричном формате результат нашей операции. Но этот результат четырехбайтный, так как регистры процессора 32-разрядные. Наша же переменная двухбайтная, поэтому в нее запишется только 2 байта, то есть, 0ECA. Давайте запустим стандартный Windows-калькулятор и приведем его к инженерному виду. Затем переключим представление чисел в Hex-формат и введем число 0ECA. Затем переключим в Dec-формат (десятичный) и увидим число 3786!!!

Давайте рассмотрим другой пример.

Пример 3.

. . .

float a=-1.34872e23;

unsigned int b=3856956264;

cout<<"\na="<

cout<<"\nb="<

. . .

В этом фрагменте программы нет ничего странного. Но это на первый взгляд! Мы знаем, что все данные хранятся в памяти ЭВМ. Давайте посмотрим, как будут храниться эти два числа в памяти. Для этого запустим программу в режиме отладки. Затем откроем окно просмотра ассемблерного кода программы (View -> Debug Windows -> Disassembly) и найдем там команды:

10: float a=-1.34872e23;

00401038 mov dword ptr [ebp-4],0E5E47B68h

11: unsigned int b=3856956264;

0040103F mov dword ptr [ebp-8],0E5E47B68h

Очевидно, что эти два разных не только по значению, но и по типу числа запишутся в памяти абсолютно одинаково! Но ведь в последующем они опять считаются из памяти как два разных числа!!! Именно из этого вытекает главное назначение типизации данных:




Типизация данных предназначена для

задания размера памяти под хранение значения переменной и

определения формата записи и считывания значения этой переменной из памяти ЭВМ



Преобразование типов. Если в выражении появляются операнды различных типов, то они преобразуются к некоторому общему типу, при этом к каждому арифметическому операнду применяется такая последовательность правил:

  1. Если один из операндов в выражении имеет тип long double, то остальные тоже преобразуются к типу long double.

  2. В противном случае, если один из операндов в выражении имеет тип double, то остальные тоже преобразуются к типу double.

  3. В противном случае, если один из операндов в выражении имеет тип float, то остальные тоже преобразуются к типу float.

  4. В противном случае, если один из операндов в выражении имеет тип unsigned long, то остальные тоже преобразуются к типу unsigned long.

  5. В противном случае, если один из операндов в выражении имеет тип long, то остальные тоже преобразуются к типу long.

  6. В противном случае, если один из операндов в выражении имеет тип unsigned, то остальные тоже преобразуются. к типу unsigned.

  7. В противном случае все операнды преобразуются к типу int. При этом тип char преобразуется в int со знаком; тип unsigned char в int, у которого старший байт всегда нулевой; тип signed char в int, у которого в знаковый разряд передается знак из сhar; тип short в int (знаковый или беззнаковый).

Предположим, что вычислено значение некоторого выражения в правой части оператора присваивания. В левой части оператора присваивания записана некоторая переменная, причем ее тип отличается от типа результата в правой части. Здесь правила преобразования очень простые: значение справа от оператора присваивания преобразуется к типу переменной слева от оператора присваивания. Если размер результата в правой части больше размера операнда в левой части, то старшая часть этого результата будет потеряна.

В языке С++ можно явно указать тип любого выражения. Для этого используется операция преобразования ("приведения") типа. Она применяется следующим образом:

(тип) выражение

(здесь можно указать любой допустимый в языке Си тип).

Рассмотрим пример 4:

int a = 30000; float b;

........

b = (float) a * 1000000;

(переменная a целого типа явно преобразована к типу float; если этого не сделать, то результат будет потерян, т.к. a * 1000000 > 2147483647).

Другой пример.

Пример 5.

. . .

int a=850; char b;

b=a;

cout<<b;

. . .

Возникает вопрос: что появится на экране? Ответ – символ с кодом 82, или “R”.

Переменная типа int занимает 4 байта в памяти, а переменная типа char – 1 байт. При присвоении значения переменной a переменной b в переменную b занесется только младший байт числа a, то есть:

a = 00000000 00000000 00000011 01010010(2) = 00 00 03 52(16) = 850(10)

b = 01010010(2) = = 00000052(16) = 82(10)

Как видно из примера, две значащие единицы 2-го байта числа a были в результате преобразования типа отброшены. Аналогичного результата можно было достичь вычитанием из числа 850 числа 256 до тех пор, пока не получится число, которое меньше 256:

850 – 256 = 594 > 256

594 – 256 = 338 > 256

338 – 256 = 82 < 256 СТОП

Почему это происходит именно так, необходимо сформулировать самому в выводах по лабораторной работе.

1   2   3   4   5   6   7   8   9   ...   22