Similar presentations:
Вещественный тип данных, указатели, функции
1. Вещественный тип данных, указатели, функции
2. Вещественные типы данных
Стандарт 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.
2
3. Представление констант
Константы вещественных типов задаются двумяспособами:
• нормальный формат: 123.456 или -3.14;
• экспоненциальный формат: 1.23456e2
(1.23456е+2). Привести другие примеры.
Дробная часть отделяется от целой части точкой, а
не запятой.
3
4. Представление вещественных чисел в компьютере
Внутреннее представление вещественного числа состоит издвух частей — мантиссы и порядка:
-1.2345e+2
|
|
мантисса порядок
• Тип float занимает 4 байта, из которых один двоичный разряд
отводится под знак мантиссы, 8 разрядов под порядок и 23 под
мантиссу.
• Для величин типа double, занимающих 8 байт, под порядок и
мантиссу отводится 11 и 52 разряда соответственно.
• Длина мантиссы определяет точность числа, а длина порядка —
его диапазон.
4
5. Точность вычислений и «ловушка» для программиста
• Все вычисления с вещественными значениямиосуществляются приближенно, при этом, ошибки
вычислений могут достигать весьма существенных
значений. Это объясняется дискретностью
внутреннего (машинного) представления
непрерывного диапазона вещественных значений.
Точность представления значений вещественных
типов зависит от размера мантиссы. Относительная
точность представления вещественных значений
остается постоянной при различных значениях
порядка. Однако, абсолютная точность существенно
зависит от значения порядка (с уменьшением
порядка абсолютная точность возрастает).
5
6. Преобразования типов данных
• При выполнении различных операций надразнотипными данными необходимы
преобразования одних типов данных к
другим.
• В языке C++ различают неявное
(автоматическое) и явное преобразование
типов данных.
6
7. Правила неявного (арифметического) преобразования
1.2.
3.
4.
5.
Все данные типов char и short int преобразуются к типу int.
Если хотя бы один из операндов имеет тип double, то и другой
операнд преобразуется к типу double (если он другого типа);
результат вычисления имеет тип double.
Если хотя бы один из операндов имеет тип float, то и другой
операнд преобразуется к типу float (если он другого типа);
результат вычисления имеет тип float.
Если хотя бы один операнд имеет тип long, то и другой
операнд преобразуется к типу long (если он другого типа);
результат имеет тип long.
Если хотя бы один из операндов имеет тип unsigned, то и
другой операнд преобразуется к типу unsigned (если его тип не
unsigned); результат имеет тип unsigned.
Если ни один из случаев 1-5 не имеет места, то оба операнда
должны иметь тип int; такой же тип будет и у результата.
7
8. Преобразование типов данных при операции присваивания
При выполнении операции присваиваниятип значения выражения автоматически
преобразуется к типу левого операнда (к
типу данных переменной в левой части).
При этом возможны потери данных или
точности.
8
9. Явное преобразование типов данных
Явное преобразование типов данных осуществляется с помощьюсоответствующей операции преобразования типов данных,
которая имеет один из двух следующих форматов:
(<тип данных>) <выражение> или <тип данных> (<выражение>)
Например:
(int) 3.14
(double) a
(long) (a + 1e5f)
или
int (3.14)
double (a)
long (a + 1e5f)
9
10. Исходы явного преобразования типов данных
Явные преобразования типов данных имеютсвоим исходом три ситуации:
• преобразование без потерь;
• с потерей точности;
• с потерей данных.
При явном преобразовании типов значения
преобразуемых величин на самом деле не
изменяются – изменяется только
представление этих значений при выполнении
действий над ними.
10
11. Исходы явного преобразования типов данных
• Преобразование происходит без потерь, еслипреобразуемое значение принадлежит множеству
значений типа, к которому осуществляется
преобразование.
• Преобразование любого вещественного типа к целому
осуществляется путем отбрасывания дробной части
вещественного значения, поэтому практически всегда
такие преобразования приводят к потере точности
(осуществляются приближенно)
• Попытки преобразования значений выходящих за
пределы диапазона типа данных, к которому
осуществляется преобразование, приводят к полному
искажению данных.
11
12. Тип данных «Указатель»
Указатели – это тоже обычные переменные, но они служат дляхранения адресов памяти.
Указатели определяются в программе следующим образом:
<тип данных> *<имя переменной>
Здесь <тип данных> определяет так называемый базовый тип
указателя.
<Имя переменной> является идентификатором переменнойуказателя.
Признаком того, что это переменная указатель, является символ
*, располагающийся между базовым типом указателя и именем
переменной-указателя.
Например:
int *p1;
double *p2;
12
13. Работа с указателями
Присвоить указателю адрес некоторойпеременной можно инструкцией
присваивания и операцией &, например,
int A = 2351, *p1;
double B = 3.14, *p2;
p1 = &A;
// Указателю p1 присваивается адрес
переменной А
p2 = &B;
// Указателю p2 присваивается адрес
переменной В
13
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;
14
15. Внимание!
При использовании указателей ввыражениях важно помнить, что операция
* имеет наивысший приоритет по
отношению к другим операциям (за
исключением операции унарный –
(минус)).
15
16. Арифметика указателей
• К указателям можно применять некоторыеарифметические операции. К таким операциям
относятся: +, -, ++, --. Результаты выполнения этих
операций по отношению к указателям
существенно отличаются от результатов
соответствующих арифметических операций,
выполняющихся с обычными числовыми
данными.
• Добавлять к указателям или вычитать из
указателей можно только целые значения.
16
17. Преимущества использования функций
• Использование функций позволяет:• значительно упростить разработку сложных
программ;
• сократить объем текста программы и
генерируемого результирующего кода программы;
• значительно упростить отладку и модификацию
программ;
• распределить работу над одной программой между
различными исполнителями программистами.
• Фактически разработка более-менее сложных
программ практически невозможна без
использования функций.
17
18. Описание функций в программе
• Любая функция состоит из двух основных элементов:заголовка и тела функции.
• Заголовок функции имеет следующий формат:
• <Тип возвращаемого значения> <Идентификатор – имя
функции> (<Параметры>)
• Тело функции представляет собой блок инструкций языка
программирования, разделенных символами “точка с
запятой”:
• {
<Инструкция 1>;
<Инструкция 2>;
………………….
<Инструкция N>;
• }
18
19. Пример описания функции
double Example (double d, int k){
double r;
r = d * k;
return r;
}
• Не все функции должны возвращать значения. В
этом случае <Тип возвращаемого значения>
задается ключевым словом void, которое означает
– “пусто”
19
20. Завершение работы функции (инструкция return)
• Если функция не возвращает через свое имя никакого значения, тоона завершается после выполнения последней инструкции тела
функции. При необходимости досрочного завершения работы
функции необходимо использовать инструкцию return, которая
приводит к немедленному завершению работы функции.
• В одной и той же функции могут быть использованы несколько
инструкций return.
• Если функция возвращает через свое имя некоторое значение, то
выход из функции обязательно должен осуществляться с помощью
инструкции return. В этом случае эта инструкция не только
вызывает окончание работы функции, но и осуществляет передачу
возвращаемого функцией значения.
• Значение, которое возвращает инструкция return, по типу должно
соответствовать типу возвращаемого функцией значения.
20
21. Список параметров функции
• Параметры функций служат для обеспечения взаимодействиямежду функцией и вызвавшей ее программой.
• Параметры функций перечисляются в заголовке через символ
‘,’ (запятая). Каждый параметр должен соответствовать
определенному типу данных. Параметры могут быть любых
типов данных. Тип данных для каждого параметра (даже если
все они имеют один и тот же тип данных) задается отдельно в
соответствии со следующим форматом:
• <Тип данных параметра> <Идентификатор – имя
параметра>
21
22. Примеры
• void Example1 (int a, int b)• или
• double Example2 (int A, double B)
22
23. Вызов функции
• При вызове функции на места параметровподставляются некоторые конкретные значения,
которые обычно называют аргументами функции
• Количество, типы данных и порядок следования
аргументов должны соответствовать списку
параметров функции.
• Функции, возвращающие значения, могут
использоваться в качестве элементов различных
выражений.
23
24. Передача данных по значению
• При вызове функции в определенной области памяти (встеке программы) для каждого параметра функции
создается переменная соответствующая типу данных
параметра.
• В эти переменные копируются значения аргументов,
использовавшихся при вызове функции. При
выполнении кода функции эти копии значений
аргументов могут использоваться для обработки, могут
изменять свои значения, но эти изменения никак не
затрагивают значений самих аргументов.
• Такой способ служит для передачи данных только
внутрь функции, но не из функции обратно в программу.
24
25. Передача данных с помощью указателей
Для использования передачи данных с помощьюуказателей необходимо обязательно выполнить три
следующих пункта:
1. Соответствующий параметр в заголовке функции
необходимо определить как указатель на тип
данных аргумента.
2. При вызове функции на месте параметровуказателей необходимо использовать адрес
аргумента, а не сам аргумент.
3. При обращении внутри функции к значению
аргумента через параметр-указатель необходимо
осуществить разыменование этого указателя.
25
26. Пример
Необходимо разработать функцию, возвращающуюрезультат деления и остаток от деления двух целых
чисел.
int Div (int N1, int N2, int *Ost) // int *Ost – параметруказатель
{
*Ost = N1 % N2; // *Ost – разыменование
параметра-указателя
return N1 / N2;
}
26
27. Передача массивов в качестве аргумента
• Несколько проще обстоит дело с передачеймассивов, так как переменные типа массив
сами являются указателями на первый
элемент массива. В связи с этим отпадает
необходимость в выполнении пунктов 2 и 3
из перечисленных выше.
27
28. Пример
• void WriteArr ( int Arr[], int n)• {
• for (int I = 0; I < n; ++I)
cout << Arr[I] << “ “;
• cout << endl;
• }
28
29. Передача данных по ссылке
• В языке C++ имеется более простой способпередачи данных по адресу, а именно –
передача данных по ссылке.
int Div (int N1, int N2, int &Ost) // int &Ost –
параметр-ссылка
{
Ost = N1 % N2; // Разыменования параметрассылки Ost не требуется
return N1 / N2;
}
29
30. Аргументы - константы
• Недостатком передачи данных по адресу является скрытыйпобочный эффект, связанный с возможным непредвиденным
изменением внутри функции значения аргумента переданного
по адресу. Однако этого эффекта можно избежать, если
определить соответствующий параметр функции как константу:
• void Proc(const double *D)
• {
……
*D = 3.14; // Ошибка в процессе компиляции
……
• }
30
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)
31
32. Параметры по умолчанию
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
32
33. Параметры по умолчанию
Количество параметров по умолчаниюможет быть любым. При использовании
параметров по умолчанию необходимо
помнить:
•все параметры по умолчанию должны
находиться в конце списка параметров
функции;
•если при вызове функции не указывается
аргумент для некоторого параметра по
умолчанию, то и все следующие аргументы
должны быть пропущены.
33
34. Рекурсивное использование функций
Функции внутри своего тела могут вызывать самисебя. Такой вызов называется рекурсией.
Рассмотрим функцию Pow(D,P)возведения
вещественного значения D в целую
положительную степень P.
Очевидно, что:
• Pow(D,P)=1 при P=0;
•Pow=Pow(D,P-1)*D при P>0;
34
35. Реализация функции
• double Pow (double D, unsigned P)• {
if (P)
return Pow ( D, P – 1 ) * D;
else
return 1;
• }
35
36. Передача функций в качестве параметров
• Используя тот факт, что имена функций являютсяобычными указателями, можно передавать
функции в качестве аргументов других функций.
• Для этого необходимо с помощью оператора
typedef определить тип данных указателя на
функции, передаваемые в качестве аргумента,
который должен соответствовать характеристикам
передаваемых функций (тип возвращаемого
значения, параметры функции).
36
37. Пример
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;}
37
38. Встраиваемые функции (inline - функции)
• Встраиваемые функции задаются ключевым словомinline:
inline int ReadInt(char *S)
Некоторые компиляторы накладывают определенные
ограничения на содержание встраиваемых функций. К
таким ограничениям обычно относятся использование
внутри встраиваемых функций:
• рекурсии;
• циклов, переключателей, инструкций goto;
• статических (static) переменных.
38
39. Прототипы функций
Прототипом функции называется заголовокфункции (со списком параметров),
заканчивающийся символом ;.
Например:
double F (int P1, double P2 ); // Это прототип
функции F
double F (int P1, double P2 ) // А это сама
функция F
{ return P1 * P2;}
39