Скачиваний:
2
Добавлен:
03.01.2024
Размер:
2.67 Mб
Скачать

Вещественные типы данных

Хранение вещественных чисел с фиксированной запятой (в первых ЭВМ):

11

2. Переменные и константы. Структура памяти в компьютере

 

Память состоит из нумерованных ячеек.

Переменная – это величина, имеющая имя, тип и значение.

 

Память имеет линейную структуру (адрес ячейки – одно

Значение переменной можно изменять во время работы

 

число).

программы

Байт (byte) — единица хранения и обработки цифровой информации; совокупность битов (8 бит), обрабатываемая компьютером одновременно.

В современных вычислительных системах байт состоит из 8

 

бит и, соответственно, может принимать одно из 256

 

(28 : от 0 до 255) различных значений (состояний, кодов).

 

память: 1 байт = 8 бит

0…FF16 = 28 - 1

 

диапазон значений 0…255,

Байт – это наименьшая ячейка памяти, имеющая

 

собственный адрес.

 

NotaBene (NB): 8-битные байты стали стандартом де-факто; с

 

начала 1970-х в большинстве компьютеров байты состоят из 8

 

бит, а размер машинного слова кратен 8 битам.

 

Си: unsigned char

Паскаль: byte

Машинное слово — это фрагмент данных фиксированного

 

размера, обрабатываемый как единое целое с помощью

 

набора команд или аппаратного обеспечения процессора.

Количество бит в машинном слове — размер слова (он же

 

ширина или длина слова) — является важной характеристикой

 

любой конкретной архитектуры процессора или компьютерной

 

архитектуры.

Для 32-битных процессоров архитектуры x86: исторически

 

машинным словом считается 16 бит (CPU 8086), реально —

 

32 бита

(CPU 80386).

Для CPU x86-64: 64 бита (CPU Intel CoreDuo и более новые

 

версии)

12

int d, e; float f;
...

Переменные и константы

Все переменные до их использования должны быть определены (объявлены). При этом задается тип, а затем идет список из одной или более переменных этого типа, разделенных запятыми. Например:

int a, b, c; char x, y;

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

определения.

Объявление устанавливает свойства объекта: его тип (например, целый), размер (например, 4 байта) и т.д.

Определение наряду с этим вызывает выделение памяти (в

приведенном примере дано определение переменных). Переменные можно разделять по строкам произвольным

образом, например:

float a; float b;

Переменные в языке Си могут быть инициализированы при их определении:

int a = 25, h = 6; char g = 'Q', k = 'm'; float r = 1.89;

long double n = r*123;

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

Первые определяются вне функций и, следовательно, доступны для любой из них. Локальные объекты по отношению к функциям являются внутренними. Они начинают существовать, при входе в функцию и уничтожаются после выхода из нее.

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

int a; /* Определение глобальной переменной */

int function (int b, char c); /* Объявление функции (т.е. описание ее заголовка)*/

void main (void)

{ // Тело программы // Определение локальных переменных

// Определение локальной переменной

}

int function (int b, char c) /* Определение функции и формальных параметров (по существу - локальных переменных) b

и c {*///Тело функции

char g; //Определение локальной переменной

}

...

Отметим, что выполнение программы всегда начинается с вызова функции main( ), которая содержит тело программы. Тело программы, как и тело любой другой функции, помещается между открывающей и закрывающей фигурными скобками.

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

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

Если они сделаны в функции, то соответствующие объекты будут локальными, а если вне функций, то глобальными.

13

Переменные и константы

Что определяет тип переменной:

область допустимых значенийдопустимые операцииобъём памяти

формат хранения данныхдля предотвращения случайных ошибок

Минутка юмора: Первым андроидом был Буратино

А, поскольку единственный способ для деревянного существа запомнить что-нибудь — это зарубить себе на носу, то папа Карло был вынужден обеспечить его достаточно большим объёмом памяти…

NB: Андроид (греч. «человек, мужчина» и суффикса «подобие; человекоподобный, антропоморфный») — робот-гуманоид или синтетический организм, предназначенный для того, чтобы выглядеть и действовать наподобие человека. Такой робот может быть оснащён органами биологического происхождения, либо другими, не уступающими по функциональности и внешнему виду.

NB: Андроид — операционная система для смартфонов, планшетов, электронных книг, цифровых проигрывателей, наручных часов, фитнес-браслетов, игровых приставок, ноутбуков, нетбуков, смартбуков, очков Google Glass, телевизоров, проекторов и других устройств (в 2015 году появилась поддержка автомобильных развлекательных систем и бытовых роботов).

Изначально разрабатывалась компанией Android, Inc., которую затем приобрела Google.

Основана на ядре Linux и собственной реализации виртуальной машины Java компании Google.

Впоследствии Google инициировала создание альянса Open Handset Alliance (OHA), который занимается поддержкой и дальнейшим развитием платформы.

— Буратино дали три яблока. Два он съел. Сколько яблок осталось у Буратино?..

14

Переменные и константы

Что определяет тип переменной:область допустимых значенийдопустимые операцииобъём памяти

формат хранения данныхдля предотвращения случайных ошибок

Задача:

Буратино дали три яблока. Два он съел. Сколько яблок осталось у Буратины?

— Думаете, одно? А вот и нет! Это может в первом классе на уроке арифметики оно одно осталось. А если задать эту задачку программистам?

Программист №1

— Неизвестно сколько. Никто ж не знает, сколько яблок было у него до этого.

Мораль: инициализируйте/обнуляйте начальные переменные.

Программист №2

— Даже если обнулить переменные, никто не гарантирует, что Мальвина не отдала ему свои яблоки, пока он уничтожал те два. Или не съела третье.

Мораль: не используйте глобальные переменные.

Программист №3

— А где гарантия, что Буратино съел именно два яблока, а не два чего-то другого? Там написано что он съел два…

Программист №4 (самый продвинутый с претензиями на философское мышление)

— Количество яблок у Буратино не изменилось. Они только поменяли область видимости: часть из них переместилась внутрь Буратино!

— Буратино дали три яблока. Два он съел. Сколько яблок осталось у Буратино?..

15

Переменные и константы

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

вещественные, например 123.456, 5.61е-4. Они могут снабжаться суффиксом F (или f), например 123.456F, 5.61e-4f;

целые, например 125;

короткие целые, в конце записи которых добавляется буква (суффикс) H (или h), например 275h, 344H;

длинные целые, в конце записи которых добавляется буква (суффикс) L (или l), например 361327L;

беззнаковые, в конце записи которых добавляется буква U (или u), например 62125U;

восьмеричные, в которых перед первой значащей цифрой записывается нуль (0), например 071;

шестнадцатеричные, в которых перед первой значащей цифрой записывается пара символов нуль-икс (0x), например 0x5F;

символьные - единственный символ, заключенный в одинарные кавычки, например 'О', '2', '.' и т.п. Символы, не имеющие графического представления, можно записывать, используя специальные комбинации, например \n (код 10), \0 (код 0). Эти комбинации выглядят как два символа, хотя фактически это один символ.

Так же можно представить любой двоичный образ одного байта: '\NNN', где NNN - от одной до трех восьмеричных цифр. Допускается и шестнадцатеричное задание кодов символов, которое представляется в виде: '\х2В', '\хЗ6' и т.п.;

строковые - последовательность из нуля символов и более, заключенная в двойные кавычки, например: "Это строковая константа". Кавычки не входят в строку, а лишь ограничивают ее. Строка представляет собой массив из перечисленных элементов, в конце которого помещается байт с символом '\0'. Таким образом, число байтов, необходимых для хранения строки, на единицу превышает число символов между двойными кавычками;

константное выражение, состоящее из одних констант, которое вычисляется во время трансляции (например: а=60+301);

типа long double, в конце записи которых добавляется буква L (или l), например: 1234567.89L.

16

3. Преобразование типов

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

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 (знаковый или беззнаковый).

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

Здесь правила преобразования очень простые: значение справа от оператора присваивания преобразуется к типу переменной слева от оператора присваивания.

Если размер результата в правой части больше размера операнда в левой части, то старшая часть этого результата будет потеряна.

В языке Си можно явно указать тип любого выражения.

Для этого используется операция преобразования ("приведения") типа.

Она применяется следующим образом:

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

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

Рассмотрим пример: int a = 30000; float b;

........

b = (float) a * 12;

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

a * 12 > 32767).

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

Например, оператор flag_pole = i;

разрешен, даже если i имеет тип int, а flag_pole long.

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

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

Например:

р ( (long) i);

предписывает преобразовать целое число i в long перед передачей его в качестве параметра в процедуру p, которая ожидает именно параметр long.

17

4. Составные типы и указатели

Здесь мы рассмотрим четыре способа построения более

сложных типов данных:

 

массивы (arrays)

 

структуры (structures)

 

объединения (unions)

 

указатели (pointers)

Массив — это коллекция/множество элементов одного

типа.

 

Все массивы в начинаются с элемента 0.

Объявление:

int a [10];

объявляет массив a с 10 целыми числами, которые будут хранится в элементах массива от [0] до a [9].

Массивы могут быть двух, трех и более измерений.

Структура — это набор переменных, обычно разных типов.

Структура в похожа на record в Паскале.

Оператор struct {int i; char c;} s;

объявляет s как структуру, содержащую два члена, целое число i и символ c.

Чтобы присвоить члену i структуры s значение 6, нужно записать следующее выражение: s.i = 6;

где оператор точка указывает, что элемент i принадлежит структуре s.

Объединение — это также набор членов, аналогично структуре, за исключением того, что в любой момент в объединение может находится только один из них.

Объявление union {int i; char c;} u;

означает, что вы можете иметь целое число или символ, но никак не оба.

 

Компилятор должен выделить достаточно места для

объединения, чтобы в нем мог разместиться самый большой (с

точки зрения занимаемой памяти) элемент объединения.

 

Пример использования объединения:

для определения сообщения как объединения нескольких

 

различных структур;

для определения дискового блока как объединения блока

 

данных, блока i-узла, блока каталога и т. д.).

Указатели используются для хранения машинных адресов в Cи.

Они используются очень и очень часто.

Символ звездочка (*) используется для обозначения указателя в объявлениях.

Объявление

int i, *pi, a [10], *b[10], **ppi;

объявляет целое число i, указатель на целое число pi, массив a из 10 элементов, массив b из 10 указателей на целые числа и указатель на указатель ppi на целое число.

Точные правила синтаксиса для сложных объявлений, объединяющих массивы, указатели и другие типы несколько сложны.

Ниже показано объявление массива z структур struct table, каждая из которых имеет три члена, целое число i, указатель cp на символ и символ с.

struct table /* каждая структура имеет тип таблицы */

{ int i; / *целое число */

char *cp, c; /* указатель на символ и символ */ } z [20]; /* это массив из 20 структур */

18

Указатели

Чтобы сделать p указателем на z [4], достаточно написать p = &z[4];

где амперсанд в качестве унарного оператора означает «взять адрес того, что за ним следует».

Скопировать в целочисленную переменную n значение члена i структуры, на которую указывает указатель р, можно следующим образом:

n = p->i;

Обратите внимание, что стрелка используется для доступа к члену структуры через указатель. Если мы будем использовать переменную z, то тогда мы должны использовать оператор с точкой:

n = z [4] .i;

Разница в том, что z [4] является структурой, и оператор точки выбирает элементы из составных типов (структуры, массивы) напрямую.

С помощью указателей мы не выбираем участника напрямую.

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

Иногда удобно дать имя составному типу. Например: typedef unsigned short int unshort;

определяет unshort как unsigned short (короткое целое число без знака).

Теперь unshort может быть использован в программе как основной тип. Например,

unshort ul, *u2, u3[5];

объявляет короткое целое число без знака, указатель на короткое целое число без знака и массив коротких целых без знака.

Комплексные числа в СИ

Комплексные числа введены в стандарте C99.   float _Complex

  double _Complex   long double _Complex

Все это «счастье» находиться в библиотеке complex.h

Минимальные и максимальные значения всех базовых типов данных языка Си описаны в библиотеках:

limits.h – содержит диапазоны целочисленных значений, float.h – содержит диапазоны вещественных значений.

Стандарт С89: Логический тип данных в Си

  Логический тип: int

   0 – ложь (false);

   не 0 – истина (true).

Т.е как такового логического типа не создано, а вместо него используется int.

Стандарт С99:  Логический тип: _Bool

Ключевые слова: bool, true, false

И это «счастье» в библиотеке stdbool.h

19

Оператор создания типов данных в Си

Оператор typedef используется для создания

пользовательских типов данных, синтаксис его использования:

typedef имя_старого_типа имя_нового_типа;

Пример:

 

 

 

 

 

   typedef unsigned int word;

Т

 

 

 

В Си согласно стандарту, определение типов может

 

 

СиА

 

 

 

 

 

Ве

 

 

 

производиться практически в любом месте программы (т.е нет

 

 

рипеО

 

 

 

 

 

кап

 

 

 

 

 

Сощ

 

 

 

 

 

бъСтреУкПфи

 

 

типов данных).

строго определенного блока для определенияы

 

 

есМстЦ

 

 

 

 

 

едолчируазм

 

 

 

 

 

еластвдяв

 

 

 

 

 

воатиктеся-

 

 

 

 

 

енсиыран

 

или переменной

Функция для определения размера бинелеелтитипа,у-

 

 

ынев

 

 

 

 

 

нирачеыит

количество

какого-либо типа: sizeof, она возвращаеты

 

 

скыня

 

 

 

занимаемых байт в памяти.

е

 

 

 

иеые

 

 

 

Пример:

//вернет 4

х

 

 

 

  sizeof(int)

 

 

 

 

  sizeof(char)

//результат 1

 

 

 

  sizeof(double)

// вернет 8

 

 

 

 

Перечислимый тип enum

Пример описания перечислимого типа (enumeration

«перечисление»):

enum colors { red, orange, yellow, green, blue, violet };

Здесь идентификаторы red, orange и т. д. представляют набор значений нового типа, colors — это имя перечисления , но, как ни странно, именем типа этот идентификатор сам по себе не является, хотя, несомненно, новый тип здесь введён.

По правилам языка Си имя только что введённого типа состоит из двух слов: enum colors, то есть мы можем, например, описать переменную такого типа:

enum colors one_color;

Резюме по типам языка Си

20

Соседние файлы в папке Лекции