Вещественный тип данных, указатели, функции

Содержание

Слайд 2

Вещественные типы данных Стандарт C++ определяет три типа данных для хранения

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

Стандарт C++ определяет три типа данных для хранения вещественных

значений: float, double и long double. Все эти типы предназначены для представления отрицательных и положительных значений (спецификатор unsigned к ним не применим) в разных диапазонах:
тип float занимает в памяти 4 байта с диапазоном абсолютных значений от 3.4е-38 до 3.4е+38;
тип double занимает в памяти 8 байт с диапазоном абсолютных значений от 1.7е-308 до 1.7е+308;
тип long double занимает в памяти 10 байт с диапазоном абсолютных значений от 3.4e-4932 до 3.4e+4932.
Замечание. В консольных приложениях Windows тип данных long double занимает в памяти 8 байт, то есть ничем не отличается от типа double.
Слайд 3

Представление констант Константы вещественных типов задаются двумя способами: нормальный формат: 123.456

Представление констант

Константы вещественных типов задаются двумя способами:
нормальный формат: 123.456 или -3.14;
экспоненциальный

формат: 1.23456e2 (1.23456е+2). Привести другие примеры.
Дробная часть отделяется от целой части точкой, а не запятой.
Слайд 4

Представление вещественных чисел в компьютере Внутреннее представление вещественного числа состоит из

Представление вещественных чисел в компьютере

Внутреннее представление вещественного числа состоит из двух

частей — мантиссы и порядка:
  -1.2345e+2
| |
мантисса порядок
Тип float занимает 4 байта, из которых один двоичный разряд отводится под знак мантиссы, 8 разрядов под порядок и 23 под мантиссу.
Для величин типа double, занимающих 8 байт, под порядок и мантиссу отводится 11 и 52 разряда соответственно.
Длина мантиссы определяет точность числа, а длина порядка — его диапазон.
Слайд 5

Точность вычислений и «ловушка» для программиста Все вычисления с вещественными значениями

Точность вычислений и «ловушка» для программиста

Все вычисления с вещественными значениями осуществляются

приближенно, при этом, ошибки вычислений могут достигать весьма существенных значений. Это объясняется дискретностью внутреннего (машинного) представления непрерывного диапазона вещественных значений. Точность представления значений вещественных типов зависит от размера мантиссы. Относительная точность представления вещественных значений остается постоянной при различных значениях порядка. Однако, абсолютная точность существенно зависит от значения порядка (с уменьшением порядка абсолютная точность возрастает).
Слайд 6

Преобразования типов данных При выполнении различных операций над разнотипными данными необходимы

Преобразования типов данных

При выполнении различных операций над разнотипными данными необходимы преобразования

одних типов данных к другим.
В языке C++ различают неявное (автоматическое) и явное преобразование типов данных.
Слайд 7

Правила неявного (арифметического) преобразования Все данные типов char и short int

Правила неявного (арифметического) преобразования

Все данные типов char и short int преобразуются

к типу int.
Если хотя бы один из операндов имеет тип double, то и другой операнд преобразуется к типу double (если он другого типа); результат вычисления имеет тип double.
Если хотя бы один из операндов имеет тип float, то и другой операнд преобразуется к типу float (если он другого типа); результат вычисления имеет тип float.
Если хотя бы один операнд имеет тип long, то и другой операнд преобразуется к типу long (если он другого типа); результат имеет тип long.
Если хотя бы один из операндов имеет тип unsigned, то и другой операнд преобразуется к типу unsigned (если его тип не unsigned); результат имеет тип unsigned.
Если ни один из случаев 1-5 не имеет места, то оба операнда должны иметь тип int; такой же тип будет и у результата.
Слайд 8

Преобразование типов данных при операции присваивания При выполнении операции присваивания тип

Преобразование типов данных при операции присваивания

При выполнении операции присваивания тип значения

выражения автоматически преобразуется к типу левого операнда (к типу данных переменной в левой части). При этом возможны потери данных или точности.
Слайд 9

Явное преобразование типов данных Явное преобразование типов данных осуществляется с помощью

Явное преобразование типов данных

Явное преобразование типов данных осуществляется с помощью соответствующей

операции преобразования типов данных, которая имеет один из двух следующих форматов:
(<тип данных>) <выражение> или <тип данных> (<выражение>)
Например:
(int) 3.14 int (3.14)
(double) a или double (a)
(long) (a + 1e5f) long (a + 1e5f)
Слайд 10

Исходы явного преобразования типов данных Явные преобразования типов данных имеют своим

Исходы явного преобразования типов данных

Явные преобразования типов данных имеют своим исходом

три ситуации:
преобразование без потерь;
с потерей точности;
с потерей данных.
При явном преобразовании типов значения преобразуемых величин на самом деле не изменяются – изменяется только представление этих значений при выполнении действий над ними.
Слайд 11

Исходы явного преобразования типов данных Преобразование происходит без потерь, если преобразуемое

Исходы явного преобразования типов данных

Преобразование происходит без потерь, если преобразуемое значение

принадлежит множеству значений типа, к которому осуществляется преобразование.
Преобразование любого вещественного типа к целому осуществляется путем отбрасывания дробной части вещественного значения, поэтому практически всегда такие преобразования приводят к потере точности (осуществляются приближенно)
Попытки преобразования значений выходящих за пределы диапазона типа данных, к которому осуществляется преобразование, приводят к полному искажению данных.
Слайд 12

Тип данных «Указатель» Указатели – это тоже обычные переменные, но они

Тип данных «Указатель»

Указатели – это тоже обычные переменные, но они служат

для хранения адресов памяти.
 Указатели определяются в программе следующим образом:
 <тип данных> *<имя переменной>
  Здесь <тип данных> определяет так называемый базовый тип указателя.
<Имя переменной> является идентификатором переменной-указателя.
Признаком того, что это переменная указатель, является символ *, располагающийся между базовым типом указателя и именем переменной-указателя.
Например: 
int *p1;
double *p2;
Слайд 13

Работа с указателями Присвоить указателю адрес некоторой переменной можно инструкцией присваивания

Работа с указателями

Присвоить указателю адрес некоторой переменной можно инструкцией присваивания и

операцией &, например,
int A = 2351, *p1;
double B = 3.14, *p2;
p1 = &A; // Указателю p1 присваивается адрес переменной А
p2 = &B; // Указателю p2 присваивается адрес переменной В
Слайд 14

Работа с указателями Получить значение объекта, на который ссылается некоторый указатель

Работа с указателями

Получить значение объекта, на который ссылается некоторый указатель можно

с помощью операции * (эту операцию обычно называют разыменованием указателя):
int A = 2351, *p1;
double B = 3.14, *p2;
p1 = &A; // Указателю p1 присваивается адрес переменной А
p2 = &B; // Указателю p2 присваивается адрес переменной В
cout << “Значение переменной А: ” << *p1 << endl;
cout << “Адрес переменной А: ” << p1 << endl;
cout << “Значение переменной В: ” << *p2 << endl;
cout << “Адрес переменной В: ” << p2 << endl;
Слайд 15

Внимание! При использовании указателей в выражениях важно помнить, что операция *

Внимание!

При использовании указателей в выражениях важно помнить, что операция * имеет

наивысший приоритет по отношению к другим операциям (за исключением операции унарный – (минус)).
Слайд 16

Арифметика указателей К указателям можно применять некоторые арифметические операции. К таким

Арифметика указателей

К указателям можно применять некоторые арифметические операции. К таким операциям

относятся: +, -, ++, --. Результаты выполнения этих операций по отношению к указателям существенно отличаются от результатов соответствующих арифметических операций, выполняющихся с обычными числовыми данными.
Добавлять к указателям или вычитать из указателей можно только целые значения.
Слайд 17

Преимущества использования функций Использование функций позволяет: значительно упростить разработку сложных программ;

Преимущества использования функций

Использование функций позволяет:
значительно упростить разработку сложных программ;
сократить объем текста

программы и генерируемого результирующего кода программы;
значительно упростить отладку и модификацию программ;
распределить работу над одной программой между различными исполнителями программистами.
Фактически разработка более-менее сложных программ практически невозможна без использования функций.
Слайд 18

Описание функций в программе Любая функция состоит из двух основных элементов:

Описание функций в программе

Любая функция состоит из двух основных элементов: заголовка

и тела функции.
Заголовок функции имеет следующий формат:
 <Тип возвращаемого значения> <Идентификатор – имя функции> (<Параметры>)
 Тело функции представляет собой блок инструкций языка программирования, разделенных символами “точка с запятой”:
 {
<Инструкция 1>;
<Инструкция 2>;
………………….
<Инструкция N>;
}
Слайд 19

Пример описания функции double Example (double d, int k) { double

Пример описания функции

 
double Example (double d, int k)
{
double r;
r = d

* k;
return r;
}
Не все функции должны возвращать значения. В этом случае <Тип возвращаемого значения> задается ключевым словом void, которое означает – “пусто”
Слайд 20

Завершение работы функции (инструкция return) Если функция не возвращает через свое

Завершение работы функции (инструкция return)

Если функция не возвращает через свое имя

никакого значения, то она завершается после выполнения последней инструкции тела функции. При необходимости досрочного завершения работы функции необходимо использовать инструкцию return, которая приводит к немедленному завершению работы функции.
В одной и той же функции могут быть использованы несколько инструкций return.
Если функция возвращает через свое имя некоторое значение, то выход из функции обязательно должен осуществляться с помощью инструкции return. В этом случае эта инструкция не только вызывает окончание работы функции, но и осуществляет передачу возвращаемого функцией значения.
Значение, которое возвращает инструкция return, по типу должно соответствовать типу возвращаемого функцией значения.
Слайд 21

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

Список параметров функции

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

и вызвавшей ее программой.
Параметры функций перечисляются в заголовке через символ ‘,’ (запятая). Каждый параметр должен соответствовать определенному типу данных. Параметры могут быть любых типов данных. Тип данных для каждого параметра (даже если все они имеют один и тот же тип данных) задается отдельно в соответствии со следующим форматом:
 <Тип данных параметра> <Идентификатор – имя параметра>
Слайд 22

Примеры void Example1 (int a, int b) или double Example2 (int A, double B)

Примеры

void Example1 (int a, int b)
или
double Example2 (int A, double B)

Слайд 23

Вызов функции При вызове функции на места параметров подставляются некоторые конкретные

Вызов функции

При вызове функции на места параметров подставляются некоторые конкретные значения,

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

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

Передача данных по значению

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

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

Передача данных с помощью указателей Для использования передачи данных с помощью

Передача данных с помощью указателей

Для использования передачи данных с помощью

указателей необходимо обязательно выполнить три следующих пункта:
Соответствующий параметр в заголовке функции необходимо определить как указатель на тип данных аргумента.
При вызове функции на месте параметров-указателей необходимо использовать адрес аргумента, а не сам аргумент.
При обращении внутри функции к значению аргумента через параметр-указатель необходимо осуществить разыменование этого указателя.
Слайд 26

Пример Необходимо разработать функцию, возвращающую результат деления и остаток от деления

Пример

Необходимо разработать функцию, возвращающую результат деления и остаток от деления двух

целых чисел.
int Div (int N1, int N2, int *Ost) // int *Ost – параметр-указатель
{
*Ost = N1 % N2; // *Ost – разыменование параметра-указателя
return N1 / N2;
}
Слайд 27

Передача массивов в качестве аргумента Несколько проще обстоит дело с передачей

Передача массивов в качестве аргумента

Несколько проще обстоит дело с передачей массивов,

так как переменные типа массив сами являются указателями на первый элемент массива. В связи с этим отпадает необходимость в выполнении пунктов 2 и 3 из перечисленных выше.
Слайд 28

Пример void WriteArr ( int Arr[], int n) { for (int

Пример

void WriteArr ( int Arr[], int n)
{
for (int I =

0; I < n; ++I)
cout << Arr[I] << “ “;
cout << endl;
}
Слайд 29

Передача данных по ссылке В языке C++ имеется более простой способ

Передача данных по ссылке

В языке C++ имеется более простой способ

передачи данных по адресу, а именно – передача данных по ссылке.
int Div (int N1, int N2, int &Ost) // int &Ost – параметр-ссылка
{
Ost = N1 % N2; // Разыменования параметра-ссылки Ost не требуется
return N1 / N2;
}
Слайд 30

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

Аргументы - константы

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

связанный с возможным непредвиденным изменением внутри функции значения аргумента переданного по адресу. Однако этого эффекта можно избежать, если определить соответствующий параметр функции как константу:
void Proc(const double *D)
{
……
*D = 3.14; // Ошибка в процессе компиляции
……
}
Слайд 31

Перегружаемые функции Перегруженными функциями называются функции, имеющие одинаковые имена, но различающиеся

Перегружаемые функции

Перегруженными функциями называются функции, имеющие одинаковые имена, но различающиеся

количеством, типами данных или порядком следования разнотипных параметров. Например:
 void f (char c)
void f (int c)
void f (char c, int i)
void f (int c, char i)
void f (char c, char i)
Нельзя перегружать функции, различающиеся только типами данных возвращаемых значений.
int f (char c, char i)
Слайд 32

Параметры по умолчанию void F (int I, double D, char C

Параметры по умолчанию

void F (int I, double D, char C =

’a’, int J = 10)
{
cout << C << “ “ << J << endl;
}
int main ()
{
F (0, 3.14); // Результат: а 10
F (0, 3.14, ’G’); // Результат: G 10
F (0, 3.14, ’G’, 1000); // Результат: G 1000
Слайд 33

Параметры по умолчанию Количество параметров по умолчанию может быть любым. При

Параметры по умолчанию

Количество параметров по умолчанию может быть любым. При использовании

параметров по умолчанию необходимо помнить:
все параметры по умолчанию должны находиться в конце списка параметров функции;
если при вызове функции не указывается аргумент для некоторого параметра по умолчанию, то и все следующие аргументы должны быть пропущены.
Слайд 34

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

Рекурсивное использование функций

Функции внутри своего тела могут вызывать сами себя. Такой

вызов называется рекурсией.
Рассмотрим функцию Pow(D,P)возведения вещественного значения D в целую положительную степень P.
Очевидно, что:
Pow(D,P)=1 при P=0;
Pow=Pow(D,P-1)*D при P>0;
Слайд 35

Реализация функции double Pow (double D, unsigned P) { if (P)

Реализация функции

double Pow (double D, unsigned P)
{
if (P)
return Pow

( D, P – 1 ) * D;
else
return 1;
}
Слайд 36

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

Передача функций в качестве параметров

Используя тот факт, что имена функций

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

Пример double add (double a, double b) { return a +

Пример

double add (double a, double b)
{ return a + b;}
 double mul

(double a, double b)
{return a * b;} 
typedef double (*f_Ptr) (double, double);
 double oper (f_Ptr F, double a, double b)
{return F (a, b);}
 int main ()
{ cout << oper (add, 20, 30) << endl; // 50
cout << oper (mul, 20, 30) << endl; // 600
return 0;}
Слайд 38

Встраиваемые функции (inline - функции) Встраиваемые функции задаются ключевым словом inline:

Встраиваемые функции (inline - функции)

Встраиваемые функции задаются ключевым словом inline: 
inline int

ReadInt(char *S)
Некоторые компиляторы накладывают определенные ограничения на содержание встраиваемых функций. К таким ограничениям обычно относятся использование внутри встраиваемых функций:
рекурсии;
циклов, переключателей, инструкций goto;
статических (static) переменных.