- •Экзамен 374 Предварительные рассуждения Вступительное слово
- •Исторические факты
- •Начнем!
- •Проба пера
- •Открытие сохраненного проекта
- •Вывод данных
- •Типы данных
- •Хороший стиль программирования
- •Переменные и константы
- •Практический пример
- •Ввод данных
- •Например:
- •Пример:
- •Арифметические операции с числами
- •Литералы
- •Некоторые примеры
- •Домашнее задание
- •Напишите программу, которая вводит число из трех цифр, разделяет число на отдельные цифры и печатает их отдельно друг от друга с тремя пробелами между ними. Преобразование типов
- •Перечисляемые типы
- •Типичная ошибка
- •Хороший стиль программирования
- •Типичная ошибка
- •Выражения
- •Оператор if
- •Структура программы
- •Логические операции
- •Структура множественного выбора switch
- •Практический пример
- •Цикл for
- •Практический пример
- •Цикл do-while
- •Домашнее задание
- •Вызов функции
- •Прототипы функций
- •Разбор программы
- •Область видимости
- •Аргументы по умолчанию
- •Встраивание
- •Перегрузка функций
- •Учебный пример перегруженных функций. Иллюстрация перегрузки
- •Результат работы программы
- •Практические примеры
- •Домашнее задание
- •Примеры домашней работы урока 1 Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Примеры домашних работ на создание функций Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Массивы
- •Объявление массивов
- •Примеры использования массивов
- •Программа 1
- •Программа 2
- •Обратите внимание!
- •Типичная ошибка программирования
- •Типичная ошибка программирования
- •Программа 3
- •Типичная ошибка программирования
- •Замечание по технике программирования
- •Программа 4
- •Программа 5
- •Программа нахождения минимального и максимального элементов массива
- •Сортировка массивов
- •Домашнее задание
- •Что такое указатели?
- •За кулисами...
- •Как работать с указателями?..
- •Зачем нужны указатели?
- •Указатели и Массивы.
- •Примеры задач
- •Пример 1
- •Пример 2
- •Пример 3
- •Указатели - аргументы функций.
- •Ссылочные параметры
- •Примеры решения задач
- •Домашнее задание
- •Операторы свободной памяти new и delete
- •Функции работы со строками из библиотеки обработки строк
- •Пример 1.
- •Пример2
- •Пример 3
- •Пример задачи на новый материал
- •Домашнее задание
- •Двухмерные массивы, как частный случай многомерных массивов
- •Программа.
- •Результаты работы программы.
- •Многомерные динамические массивы
- •Пример на многомерные динамические массивы
- •Домашнее задание
- •Рекурсия
- •Рекурсии или итерации
- •Указатели на функции
- •Пример №1
- •Результат выполнения программы:
- •Пример №2
- •Результат выполнения программы
- •Пример №3
- •Результаты выполнения программы
- •Определения структур
- •Пример #1 на использование структур
- •Пример #2 на использование структур
- •Оператор указателя на структуру
- •Домашнее задание
- •Тест по c Группа ___________________ф. И. О. ______________________
- •Объектно-ориентированное программирование.
- •Наследование (Inheritance).
- •Инкапсуляция (Encapsulation).
- •Определение класса
- •Конструкторы и деструкторы Инициализация объектов класса: конструкторы
- •Основное назначение конструкторов - инициализация объектов.
- •Использование конструкторов с аргументами по умолчанию
- •Если параметры не передаются конструктору, в определении объекта не нужно включать пустые круглые скобки.
- •Использование деструкторов
- •Когда вызываются конструкторы и деструкторы.
- •Домашнее задание
- •Конструктор копирования
- •Синтаксис конструктора копирования
- •Памятка
- •Пример использования конструктора копирования.
- •Перегруженные конструкторы
- •Экскурс в историю
- •Послесловие к примеру
- •Маленькое замечание
- •Домашнее задание
- •Создание класса ''строка''
- •Перегрузка операций.
- •Общие принципы перегрузки операторов.
- •Преобразования, определяемые классом
- •Пример строкового класса с перегруженными операторами
- •Домашнее задание
- •Дружественные функции (Friend Functions)
- •Пример строкового класса с перегруженными операторами и дружественными функциями
- •Перегрузка операторов new и delete
- •Перегрузка оператора индексирования
- •Класс вектор. Часть1.
- •Класс вектор. Часть 2.
- •Класс вектор. Часть 3.
- •Домашнее задание
- •Наследование (Inheritance). Часть 1.
- •Наследование (Inheritance). Часть 2.
- •Множественное наследование (multiple inheritance)
- •Пример множественного наследования
- •Домашнее задание
- •Статические члены данных
- •Раннее и позднее связывание
- •Виртуальные функции
- •Пример.
- •Абстрактные классы
- •Виртуальный базовый класс
- •Практический пример
- •Домашнее задание
- •Потоки ввода-вывода.
- •Iostream.H: stream - поток, "I" - сокр. Input - ввод, "o" - сокр. Output - вывод.
- •Предопределенные потоки.
- •Операции помещения в поток и извлечения из потока.
- •Файловый ввод-вывод с применением потоков.
- •Конструкторы файловых потоков.
- •Функции для открытия и закрытия файлов.
- •Функции для обмена с потоками.
- •Часто применяемые функции потока.
- •Ввод/вывод массива в/из файл(-а).
- •Практический пример: перекодировка файла.
- •Домашнее задание
- •Немного о файлах...
- •И снова файлы...
- •Пример "Телефонная книга"
- •Файл abonent.H
- •Форматирование данных при обменах с потоками.
- •Состояние потока.
- •Использование аргументов командной строки.
- •Ввод/вывод в с.
- •Домашнее задание
- •Определение шаблонов функций
- •Переопределение шаблонов функций
- •Шаблоны классов
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Введение
- •Обработка исключительных ситуаций
- •Практический пример
- •Программа
- •Домашнее задание
- •Экзамен
Указатели - аргументы функций.
Работая с аргументами функций в С++, Вы, наверное, обратили внимание на следующий факт: передавая аргументы в функцию по значению, сами переменные, после отработки функции, свое значение не изменяли. Это можно объяснить следующим образом: функции в качестве своих аргументов получают значения параметров, поэтому прямой возможности, находясь в вызванной функции, изменить переменную функции, откуда произошел вызов, нет. Однако, большинство практических приложений, как раз требуют от программиста решения следующей задачи: передать в функцию переменные; произвести изменения значений переменных; после отработки функции, переменные должны остаться с измененными значениями. Есть ли решение данной проблемы?.. Ответ может быть только один - да и, как один из вариантов, с помощью указателей.
Для того, чтобы разобраться с механизмом передачи аргументов в функцию, с последующим изменением их значений внутри вызванной функции, рассмотрим функцию my_swap, которая меняет местами значения своих параметров. Другими словами, если объявлены две переменные типа int a, b; причем, a=7 и b=10, то после вызова функции my_swap(&a, &b) результат будет следующим: а=10 и b=7.
Чтобы получить желаемый эффект, надо вызываемой функции передать указатели на те значения, которые должны быть изменены: my_swap(&a, &b); Так как оператор & получает адрес переменной, то &a вернет нам адрес переменной а. Таким образом, используя оператор & для получения адреса переменных (значение которых должно будет измениться в функции), мы сможем передать в функцию адреса наших переменных.
Графически это можно представить следующим образом:
В самой функции my_swap параметры должны быть описаны как указатели, при этом доступ к значениям параметров будет осуществляться через них косвенно. Такой вызов функции называется вызовом функции с передачей параметров по ссылке, причем, при обращении к функции адреса переменных должны передаваться как аргументы.
Рассмотрим реализацию функции, которая будет изменять значения своих параметров:
//реализация функции, которая будет изменять значения своих параметров
void my_swap(int *px, int *py)
{
int temp;
//производим стандартную перестановку через дополнительную переменную temp
temp=*px; //переменной temp писвоили 7
*px=*py; //переменная а приняла значение 10
*py=temp; //переменная b приняла значение 7
}
Теперь, вызов функции из main() будет выглядеть следующим образом:
my_swap(&a, &b);
Разобрав механизм вызова функции с передачей параметров по ссылке, рассмотрим практический пример использования, опять таки, нашей функции:
/*Иллюстрация использования механизма вызова функции с
передачей параметров по ссылке*/
#include <iostream.h>
//реализация функции, которя будет изменять значения своих параметров
void my_swap(int *px, int *py)
{
int temp;
//производим стандартную перестановку через дополнительную переменную temp
temp=*px; //переменной temp писвоили 7
*px=*py; //переменная а приняла значение 10
*py=temp; //переменная b приняла значение 7
}
void main()
{
int a,b;
//объявили две переменные типа int
cout<<"Enter a = ";
//вывели на экран предложение ввести значение переменной а
cin>>a;
cout<<"Enter b = ";
//вывели на экран предложение ввести значение переменной b
cin>>b;
my_swap(&a, &b);
//ВЫЗОВ ФУНКЦИИ С ПЕРЕДАЧЕЙ ПАРАМЕТРОВ ПО ССЫЛКЕ
cout<<"New value of a = "<<a<<endl;
//выведем на экран результат работы нашей программы
cout<<"New value of b = "<<b<<endl;
}
Давайте, подведем итоги:
аргументы-указатели позволяют функции осуществлять доступ к объектам вызвавшей ее функции и дают ей возможность изменить эти объекты. Если Вы хотите произвести вызов функции с передачей параметров по ссылке с ипользованием указателей, придерживайтесь следующих инструкций:
Объявите параметры-указатели в заголовке функции.
Используйте разыменованный указатель в теле функции.
Передавайте адреса в качестве аргументов при вызове функции.
Ссылки
В языке С++ ссылка определяется как другое имя уже существующего объекта. Например, в жизни, каждый из нас имеет, как правило, несколько имен и разные люди зовут нас по-разному (Саша, Алескандр, Шурик, Сан Саныч). Многих Великих мира сего мы вообще знаем только под их псевдонимами, например: Леонида Утесова или Софи Лорен :)
Так и ссылка есть другое имя для объекта. Например:
int L = 999;
int& RL = L;
Здесь RL является ссылкой. Теперь к L можно обращаться как по имени L, так и по имени RL. Т.е. по сути ссылка является синонимом, псевдонимом переменной L.
Основные достоинтсва ссылок проявляются при работе с функциями, но ссылки могут использоваться и самостоятельно.
Итак, давайте запишем в общем виде, как определяется ссылка:
тип& имя_ссылки = инициализирующее_выражение;
Для определения ссылки используется оператор ссылки & (символ амперсанд). Его можно найти над цифрой 7 на основной клавиатуре. При определении ссылки необходимо обязательно задать инициализирующее_выражение, псевдонимом которого и будет ссылка. Например:
float& ref; // ошибка
int Count = 0;
int &RefCount = Count; // правильно
В этом примере переменная RefCount объявлена как ссылка на данные типа int и инициализирована так, что ссылается на переменную Count типа int. Это определение заставляет RefCount стать псевдонимом переменной Count, т.е. и RefCount, и Count будут ссылаться на одно и то же место в памяти. Две переменные всегда имеют одинаковые значения, а присвоение, сделанное для одной переменной, изменяет значение другой. Например:
int Count = 0;
int &RefCount = Count;
// здесь и Count и RefCount равны 0
RefCount = 1;
// здесь и Count и RefCount равны 1
++Count;
// здесь и Count и RefCount равны 2
Примечание. Пробел непосредственно перед или после оператора ссылки несущественен. Т.е можно объявить RefCount как int& RefCount, int &RefCount или int & RefCount
Если переменная определяется как ссылка, она должна быть инициализирована переменной объявленного типа. Как только эта инициализация выполнена, ссылаться на другие переменные уже нельзя. Т.е. после определения ссылка всегда "смотрит" на тот участок памяти (на тот объект), с которым она связана инициализацией. Другими словами, после определения ссылка не может быть никаким способом "оторвана" от объекта инициализации и связана с другим объектом. Ни одна из операций не действует на ссылку, а относится к тому объекту, с которым она связана. Таким образом, ссылка полностью аналогична исходному имени объекта.
int Count1 = 1, Count2 = 2;
int &refCount = Count1; // refCount = 1
refCount = Count2; // refCount = 2 и Count1 = 2;
Count2++; // refCount = 2, Count1 = 2, а Count2 = 3
cout << sizeof(refCount);
Обратите внимание на оператор cout << sizeof(refCount); Результатом выполнения операции sizeof к ссылке является не ее размер, а размер именуемого ею объекта, в данном случае переменной Count1. Аналогично, применив к ссылке операцию взятия адреса &, определим не адрес ссылки, а адрес того объекта, которым инициализирована ссылка. В общем, какие бы операции мы не рассматривали, вывод один - каждая операция над ссылкой является операцией над тем объектом, с которым она связана.
Т.к. ссылка есть "другое имя уже существующего объекта", то инициализирующим выражением может быть только Lvalue-выражение, т.е. выражение, которое может стоять в левой части оператора присваивания. Другими словами в качестве инициализирующего выражения должно выступать имя некоторого объекта, имеющего место в памяти.
float val = 1.1f;
float &ref_val = val; // правильно
float &ref_pi = 3.14f; // ошибка
Ссылочная переменная существенно отличается от указателя. Указатель ссылается на область памяти, содержащую адрес ячейки, в которой хранится значение некоторой переменной (т.е. косвенная адресация). Поэтому, чтобы обратиться к значению с помощью указателя нужно использовать операцию разыменования. А ссылочная переменная ссылается прямо на ячейку со значением (поскольку в точности совпадает с переменной, используемой для инициализации). Поэтому обратиться к данной ячейке памяти можно просто по имени ссылки.
int L = 100;
int &rL = L; // ссылка на L
int *pL= &L; // указатель на L
cout << L << endl; // выводим значение L
cout << rL << endl; /* выводим значания L,
обращаясь к ней по имени rL */
cout << *pL << endl; /* выводим значение L,
используя операцию разыменования указателя pL */
Существуют некоторые ограничения использования операции ссылка &, в частности запомните три "нельзя":
Нельзя выполнять ссылку на ссылку.
int a;
int& &ra = a; // ошибка
Нельзя создавать массивы ссылок.
int a;
int& ra[10]; // ошибка
Нельзя создавать указатель на ссылку.
int a;
int& *pra = &a; // ошибка