- •Аннотация
- •Предисловие
- •Г л а в а 1. Введение в указатели
- •§1. Понятие указателя. Операции разыменования и разадресации
- •§2. Инициализация и присваивание указателей
- •§3. Передача параметров функций с помощью указателей.
- •§4. Распределение динамической памяти.
- •4.1. Операция new
- •4.2. Операция delete
- •Упражнения, тесты.
- •Указатели и массивы
- •§1. Связь указателей и массивов
- •1.1. Указатели и одномерные массивы
- •1.2. Указатели и матрицы
- •Int MyFun (int *X, int n)
- •§3. Операции над указателями при работе с массивами.
- •3.1. Арифметические операции
- •3.2. Операции сравнения.
- •§4. Использование операций над указателями при работе с одномерными массивами
- •4.1. Использование индексов
- •4.2. Указатель в качестве параметра цикла
- •4.3. Использование указателя и индекса
- •§5. Строки.
- •5.1. Общая характеристика строк.
- •5.2. Примеры алгоритмов работы со строками.
- •5.3. Анализ строковых функций.
- •§6. Использование операций над указателями при работе со статической матрицей.
- •Упражнения, тесты.
- •Массивы указателей
- •§1. Статический массив указателей
- •§2. Частично динамическая матрица.
- •Int arr_of_size[n];
- •§3. Статический массив строк
- •§4. Динамический массив указателей
- •4.1. Указатель на указатель
- •4.2. Динамические “матрицы”.
- •Int *arr_of_size;
- •4.3. Передача матрицы в функцию
- •Int a[10]; FunArr1(a, 10,…);
- •Упражнения, тесты.
- •Задачи второго среднего уровня.
- •Структуры и другие типы, определяемые пользователем
- •§1. Структуры
- •Объявление структуры
- •1.2. Работа со структурой.
- •1.3. Вложенные структуры и статические массивы в структурах
- •1.4. Статический массив структур
- •§2. Cтруктуры и указатели
- •2.1. Указатели в структуре.
- •2.2. Указатели на структуру
- •2.3. Динамический массив структур
- •2.4. Ссылка на структуру.
- •2.5. Указатели и вложенные структуры
- •§3. Cтруктуры и функции
- •3.1. Передача полей структуры в функцию.
- •Void MyFun1 (int X, float &y, int *u1, float *u2, char *s);
- •3.2. Передача всей структуры в функцию
- •Void Fun1 (tst s,…);
- •Void Fun2 (tst & s,…);
- •Void Fun3 (tst* s,…);
- •§4. Cтруктуры и классы.
- •§5. Объединения.
- •Представление вещественных чисел в памяти компьютера.
- •§6. Поля битов (битовые поля)
- •Ввод в ы в о д
- •Symbol Code16 Code10 Code2
- •§7. Перечисления
- •Какие из строк (//1 – //9) правильные?
§4. Распределение динамической памяти.
4.1. Операция new
Использование операции new является одним из способов, как определить значение переменной указателя (другие способы смотри в §2). В простейшем случае синтаксис применения этой операции такой:
указатель=new имя_типа;
Например, пусть объявлена переменная-указатель float *p;. Тогда операция
p=new float;
выделяет и делает доступным свободный участок динамической памяти, размер которого соответствует типу данных, определяемому именем типа. В нашем примере резервируется память размером 4 байта для размещения одного вещественного числа. Кроме этого, в случае успешного выполнения операция new возвращает адрес начала выделенного участка. Значение этого адреса присваивается переменной- указателю (в примере переменной p). Но значение выделенной ячейки, которое в программе обозначается *p, после выполнения этой операции ещё не определено. Поэтому cout<<(*p) выведет случайное число. Для задания значения *p надо выполнить, например, ввод ( cin >> (*p);), или использовать другой способ ( присваивание, получение с помощью функции и т.п..). Напомним, что cin>>p; приводит к ошибке.
Если участок нужных размеров не может быть “найден”, то операция new возвращает нулевое (точнее, неопределённое) значение адреса, которое в программе обозначается константой NULL, которая записывается обязательно большими буквами. Тогда в программе можно записать
if (p==NULL) { cout<<”\nError”; exit(0);}
Как нулевое числовое значение, так для указателей значение NULL равносильно false в операциях сравнения. Поэтому последнее условие в if равносильно
if (!p) {cout<<”\nError”; exit(0);}
С помощью рассматриваемой операции new можно проинициализировать не только значение указателя, но и задать значение выделенной ячейки памяти. В таком случае операция применяется так:
указатель=new имя_типа(значение);
Например,
p=new float(4.1);
определяет как значение указателя p, так и значение *p. Это равносильно
p=new float; *p=4.1;
Заметим, что значение записывается в круглых, а не в квадратных скобках. Последние будем позже использовать для создания динамического массива. Но динамический массив так инициализировать нельзя! (см.глава 2).
Доступ к переменной, адрес которой находится в p, как и раньше, осуществляется с помощью той же операции “*” (разыменование). Поэтому
cout<<p<<” “ <<(*p);
выведет адрес в 16-й системе счисления и число 4.1.
4.2. Операция delete
Операция используется для явного освобождения выделенного операцией new участка памяти. В нашем случае её синтаксис такой: delete указатель;. Для примера (см. 4.1) delete p; освобождает ячейку, адрес которой хранился в переменной- указателе (p). Но при этом ячейка p, в которой находится адрес вещественного числа, из памяти не удаляется. В дальнейшем её можно использовать. Но значение как p, а, значит, и *p после выполнения операции не определено.
Операцию delete необходимо использовать только для указателя, получившего значение с помощью new. Например, если
float x; float *q=&x;
то результат операции delete q; непредсказуем. Нельзя использовать эту операцию и для статического массива. Следующий код
const n=10; int a[n]; … delete a;
приводит к ошибке.