- •3.8. Упражнения 49
- •Введение
- •1. Базовые элементы
- •1.1. Комментарии
- •1.2. Функция «main»
- •1.3. Идентификаторы и пространства имен
- •1.4. Типы
- •1.5. Переменные
- •1.7. Константы
- •1.6. Преобразование типов
- •1.8. Потоковый ввод – вывод
- •1.9. Операции
- •1.9.1. Арифметические операции
- •1.9.2. Поразрядные операции
- •1.9.3. Условный оператор
- •1.9.4. Операции отношения
- •1.9.5. Логические операции
- •1.10. Стандартные математические функции
- •1.11. Упражнения
- •2. Базовые конструкции
- •2.1 Ветвление
- •2.1.1. Конструкция «if – else»
- •2.1.2. Конструкция «switch»
- •2.2. Циклы
- •2.2.1. Цикл «for»
- •2.2.2. Цикл «while»
- •2.2.3. Цикл «do – while»
- •2.2.4. Операторы циклов
- •2.2.5. Вложенность
- •2.3. Упражнения
- •2.3.1. Ветвления
- •2.3.2. Циклы
- •2.3.3. Вложенность
- •3. Указатели. Массивы. Структуры
- •3.1. Указатели
- •3.2. Массивы
- •3.2.1. Статические массивы
- •3.2.2. Динамические массивы
- •3.4. Ссылки
- •3.5. Структуры
- •3.6. Объединение
- •3.7. Переопределение типов
- •3.8. Упражнения
- •3.8.1. Статические и динамические массивы
- •3.8.2. Многомерные массивы
- •3.8.3. Строки
- •4. Функции
- •4.1. Простые функции
- •4.2. Рекурсия
- •4.3. Указатели и ссылки
- •4.3.1. Передаваемые параметры
- •4.3.2. Возвращаемые значения
- •4.3.3. Ссылки и структуры в функциях
- •4.3.4. Указатели и массивы в функциях
- •4.3.5. Указатели и ссылки на функцию
- •4.4. Шаблоны функций
- •4.5. Упражнения
- •4.5.1. Простые функции
- •4.5.2. Параметры – ссылки и параметры — указатели
- •5. Стандартные классы
- •5.1. Класс «pair»
- •5.2. Класс «complex»
- •5.3. Класс «string»
- •5.4. Контейнеры. Алгоритмы. Итераторы
- •5.5. Класс «vector»
- •5.6. Упражнения
- •5.6.1. Класс «string»
- •5.6.2. Класс «vector»
- •6. Файловый ввод – вывод
- •6.1. Операции
- •6.2. Методы
- •6.3. Флаги
- •6.4. Двоичный режим
- •6.5. Упражнения
- •Ллитература
2.3. Упражнения
2.3.1. Ветвления
Найти решения заданных функций, используя ветвления «if – else», «switch» или условный оператор. Число «x» вводится пользователем с клавиатуры.
2.3.2. Циклы
Найти решения заданных функций, используя циклы «for», «while», «do – while». Число «n» вводится пользователем с клавиатуры.
2.3.3. Вложенность
Найти решения заданных функций, используя циклы «for», «while», «do – while». Числа «n» и «m» вводятся пользователем с клавиатуры.
3. Указатели. Массивы. Структуры
Память любого С++ – приложения делится на две части: область «heap» и область «stack». Наглядной абстракцией для представления стека может служить колода карт. Так в стеке верхняя карта – текущая область видимости программы, например, область видимости выполняемой в данный момент функции. В тот момент, когда текущая функция вызывает очередную, то уже новая текущая карта располагается поверх данной, а при завершении ее работы – удаляется. Такие карты часто называют фреймами. Стековые фреймы эффективны для реализации изолированной работы функций. Другая область – «heap» – не зависит от текущего стекового фрейма. В эту область можно поместить и переменные, объявленные в теле функции, с тем, чтобы они существовали после ее завершения («static»). Область «heap» не является структурированной, по этому представима как некоторый набор ячеек памяти.
3.1. Указатели
Язык С++ предусматривает два способа выделения памяти для объектов: статическое выделение во время компиляции, и динамическое – во время выполнения программы. Статическое выделение памяти является более эффективным, однако размер того или иного объекта не всегда известен до компиляции, что делает динамическое выделение памяти более гибким.
Реализация указателей происходит посредством встроенного типа, объекты которого хранят адреса других объектов. Указатель объявляется, как указатель на определенный тип, и не может указывать на объекты другого типа. Исключением является «void» – указатель, способный указывать на объекты любого типа. Однако, такие указатели не могут быть разыменованы.
Для работы с указателями необходимы две специальные операции: взятие адреса «&» и разыменование «*», называемое также косвенной адресацией. Результат операции «&» – адрес объекта, а использование «*» позволяет обратиться к значению в памяти, на которую указывает разыменовываемый объект. К числу необходимых для динамического выделения памяти операторов относятся операторы «new» и «delete», аналогичные С – функциям «malloc()» и «free()». Следующий листинг дает первоначальное представление об указателях.
Листинг 3.1. Применение указателей.
#include <iostream>
using namespace std;
int main (void)
{
int i = 1;
int *pint = &i; //указатель на int – переменную i;
*pint = 2; //косвенное присвоение i числа 2;
cout << i << endl;
int j = 3;
pint = &j; //указатель на int – переменную j;
(*pint)++; //косвенный инкремент j;
cout << j << endl;
//выделение участка памяти размером int, занесение туда числа 255 и
//создание указателя на данный участок;
int *ptr = new int(255);
//вывод адреса участка памяти и хранящегося в нем значения;
cout << ptr << " : [ " << *ptr << " ] " << endl;
//освобождение связанной с указателем памяти;
delete ptr;
return 0;
}
Особое внимание следует уделить использованию скобок в строке с инкрементом. При их отсутствии увеличилось бы не то значение, на которое указывает «pint», а адрес, хранимый указателем. При этом, адрес был бы увеличен на число, равное размеру типа указателя.
Листинг 3.1. Инкремент указателя и приоритет разыменования.
#include <iostream>
using namespace std;
int main (void)
{
double *pint = new double(0);
cout << pint << " + " << sizeof(*pint) << " = ";
*pint++;
cout << pint << endl;
return 0;
}
Указатель, как и другие объекты, может быть объявлен как константа. Существенное влияние на интерпретацию спецификатора «const» оказывает его положение. В случае если «const» поставлен перед символом «*», он защищает от изменения то значение, которое адресует указатель. В случае, если «const» поставлен после указанного символа, он защищает сам адрес, хранимый указателем.
