- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
118
Глава 10. Указатели и ссылки
10.1.Указатели и адреса
Вязыке C++ можно определять переменные, значениями которых являются адреса других переменных. Такие переменные называются указателями. Для объявления указателя после имени типа ставится *,
например,
char *p; |
// p – указатель на переменную типа char |
Существует унарный оператор &, выдающий адрес своего операнда. После выполнения инструкций:
char c = ’0’; p = &c;
указатель p будет содержать адрес переменной c (говорят, что p ссылается на c). Схема расположения в памяти переменной c и указателя p, содержащего ее адрес, показана на рис.34. Символьная переменная c занимает один байт памяти, а указатель p – четыре. Такое количество памяти выделяется под указатели на 32 –разрядных компьютерах, в которых для формирования адресов используется 4 байта, состоящих из 8 двоичных разрядов – битов.
·· |
|
p |
с |
|
·· |
|||||
· |
|
|
|
|
··· |
|
|
|
|
|
|
|
|
|
|
|
|
|
· |
||
Рис.35. Связь объекта и указателя на него |
|
|
||||||||
|
|
|
|
К указателю можно применять унарный оператор *, возвращаюший объект, на который ссылается данный указатель, например,
*p = ’A’; |
// Теперь c = ’A’ |
Иначе говоря, если p указывает на c, то *p и c – это одно и то же. Можно создавать указатели на величины любых типов.
Программа 25. Расчет треугольника
Пусть требуется вычислить периметр и площадь треугольника по трем его сторонам a, b, c. Напишем для этого функцию triangle. Так как треугольник существует не для любых значений длин сторон, функция должна как-то информировать об этом. Пусть она будет возвращать 1,
Указатели и ссылки 119
если для заданных длин сторон треугольник существует, и 0, если не существует. Две остальные величины – периметр и площадь – будем возвращать из функции через аргументы, другого способа нет, но чтобы сформировать значения аргументов внутри функции, туда будем передавать их адреса.
Вычисления можно проводить по формулам: P = a + b + c – периметр, p = P2 – полупериметр,
A = p ( p − a)( p − b)( p − c) – площадь.
Вmain вводятся исходные данные, и вызывается функция triangle.
//Файл Triangle.cpp
#include <iostream.h> #include <math.h>
//triangle: вычисление периметра и площади треугольника
//возвращает 1, если треугольник существует и 0 если не существует int triangle(double a, double b, double c, double *p_perim, double *p_area)
//a, b, c - стороны треугольника
//p_perim - указатель на переменную для периметра
//p_area - указатель на переменную для площади
{ |
|
|
double p; |
|
// Полупериметр |
// Проверка существования треугольника |
|
|
if(a > b + c || b > a + c || c > a + b) |
|
|
return 0; |
// Треугольник не существует, выход из функции |
|
p = (a + b + c) / 2; |
|
|
*p_perim = 2 * p; |
|
// Периметр |
*p_area = sqrt(p * (p - a)*(p - b)*(p - c)); |
// Площадь |
|
return 1; |
|
|
} |
|
|
int main() |
|
|
{ |
|
|
double r, s, t; |
|
// Стороны треугольника |
double P, A; |
|
// Периметр и площадь |
cout << "Введите три стороны треугольника: "; cin >> r >> s >> t;
if(triangle(r, s, t, &P, &A) == 0)
cout << "Такого треугольника не существует\n"; else
cout << "Периметр: " << P << ", площадь: " << A <<"\n";
120 10
return 0;
}
Так как в функцию triangle передается указатель p_perim на переменную для периметра, сама эта переменная получается внутри функции с помощью выражения *p_perim и ей присваивается вычисленное значение. Аналогично используется указатель p_area на переменную для площади.
При вызове triangle ей в качестве аргументов передаются &P и &A – адреса переменных P и A. Возвращаемое triangle значение сравнивается с 0. Если результат сравнения положительный, то печатается сообщение, что треугольник не существует, иначе печатаются значения P и A, вычисленные внутри функции triangle. Ниже приведены результаты, выдаваемые программой.
Введите три стороны треугольника: 3 4 5 Периметр: 12, площадь: 6
Взаимодействие формальных параметров и фактических аргументов функции triangle иллюстрируется рис.36. При вызове функции формальные параметры a, b, c получают значения фактических аргументов r, s, t; формальные параметры p_perim, p_area получают значения адресов внешних переменных P и A.
|
main |
|
|
triangle |
|||
r |
|
|
|
|
|
|
a |
|
|
|
|
|
|
||
s |
|
|
|
|
|
|
b |
|
|
|
|
|
|
||
t |
|
|
|
|
|
|
c |
|
|
|
|
|
|
||
P |
|
|
|
|
|
p_perim |
|
|
|
|
|
||||
A |
|
|
|
|
|
p_area |
|
|
|
|
|||||
|
|
|
|
|
|||
|
|
|
|
|
|
m |
|
|
|
|
|
|
|
|
Рис.37. Формальные параметры a, b, c получают значения внешних переменных r, s, t; p_perim и p_area получают значения адресов P и A
Указатели и ссылки 121
10.2. Указатели и массивы
Определение: int a[10];
создает массив из 10 элементов, то есть блок из 10 расположенных последовательно переменных целого типа с именами a[0], a[1], …, a[9].
Пусть определен указатель: int *p;
После присваивания p = &a[0];
указатель p будет содержать адрес нулевого элемента массива a. На рис.38 это показано стрелкой, причем для p нарисован прямоугольник, чтобы подчеркнуть, что этот указатель размещен где-то в памяти.
p |
p+1 |
p+2 |
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
a: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
a[0] |
a[1] |
|
|
|
|
|
|
|
a[9] |
Рис.39. Массив в памяти и указатели на элементы массива
По определению, p + 1 указывает на следующий элемент массива, p + i указывает на i-й элемент после p, p - i указывает на i-й элемент перед p. Для выражений p + 1, p + 2 на рисунке прямоугольники не нарисованы, так как под них память не выделяется. Имея указатель на начало массива, можно получить доступ к любому его элементу, например, *p есть нулевой элемент массива, *(p + 1) – первый и т.д. Присваивание
*(p + 1) = 0;
обнуляет первый элемент массива.
По определению, имя массива имеет значение адреса начального элемента массива, поэтому имя массива имеет тип указателя на элемент массива, например, a имеет тип int*.
Доступ к i - му элементу массива можно получить, используя индексацию a[i] или выражение *(a + i).
Указатель – это переменная, которой можно присваивать различные значения, например,
p = a + 1;
Теперь p указывает на первый элемент массива a.