Указатель pchar хранит адрес динамически выделенной памяти для размещения символов строки
разными цветами. Название файла – index.html. Задайте странице цветной фон: подберите такой цвет, чтобы он не затруднял чтение текста .
2) Создайте HTML-страницу с фразой: "Каждый Охотник Желает Знать Где Сидит Фазан" .
Каждое слово должно быть соответствующего цвета: красный, оранжевый, желтый, зеленый, голубой, синий, фиолетовый. Дайте странице заголовок "Радуга" .
4) Измените нумерацию в списке на нумерацию буквами и римскими цифрами .
5) Измените тип списка на маркированный, используйте разные типы маркеров .
6) Создайте текстовую надпись большого размера. Примените к ней по очереди шрифты Wingdings, Wingdings 2, Wingdings 3 и Webdings .
7) Модифицируйте файл index.html: добавьте ссылку на страницу "Мое хобби" и ссылку на сайт отдела (должна открываться в новом окне). На странице "Мое хобби" добавьте гиперссылку, указывающую на страницу index.html .
8) Создайте страницу links.html. Разместите на ней ссылки на пять каких-либо сайтов .
Ссылки должны быть расположены в нумерованном или маркированном списке и открываться в новом окне .
9) Добавьте на первую страницу (index.html) свою фотографию вместо строк "Мой первый сайт, это пример" .
10) При помощи атрибутов width и height уменьшите и увеличьте размер изображения в 2 раза. Обратите внимание на потерю качества изображения при увеличении .
11) Сделайте изображение на первой странице гиперссылкой: при нажатии на фотографию должен открываться полноразмерный вариант в новом окне .
12) Добавьте графический фон на страницы сайта .
13) Создайте таблицу с объединёнными ячейками по горизонтали и вертикали .
14) Добавьте страницу "Мой компьютер" (computer.html), содержащую заголовок страницы и таблицу данных о вашем компьютере (аппаратное обеспечение: процессор, объем оперативной памяти и т.п., операционная система) и ссылку на главную страницу. Добавьте ссылку на computer.html на главной странице .
15) Создайте таблицу основных цветов палитры RGB и их комбинаций. Фон каждой ячейки должен соответствовать указанному цвету .
2. Каскадные таблицы стилей CSS. Встраивание CSS в HTML. Синтаксис CSS. Селекторы. Псевдоэлементы и псевдоклассы. Форматирование текста средствами CSS. Оформление HTML-документа средствами CSS .
1) Создайте внешний CSS файл. Подключите его ко всем страницам вашего сайта. Увеличьте размер шрифта, задайте для тега BODY фон свойством background-color и границу толщиной 5px .
2) На главной странице измените цвет фона на отличный от цвета на других страницах .
3) Создайте 2 различных класса стилей для ссылок на внутренние страницы (навигационное меню) и внешних ссылок. Добавьте атрибут class в теги a на страницах .
4) Сохраните на диск копию какой-либо страницы из Интернета. Отредактируйте ее код:
добавьте границу для всех элементов страницы .
5) Создайте новую страницу. Поместите на нее текст произвольного содержания. С помощью CSS задайте следующие параметры для заголовка: размер шрифта – 16 pt, полужирный, выравнивание по центру. Для текста – размер шрифта 12 pt, межстрочный интервал – полуторный, красная строка – 1,5 см. Подберите подходящий шрифт для заголовка и текста .
6) Добавьте на страницу пиктограммы с помощью шрифта Wingdings .
7) Реализуйте с помощью CSS элемент, располагающийся в блоке с заданными значениями полей, заполнения и границы. Отключите поля и заполнение для всех элементов на странице .
Проанализируйте результат. Добавьте заголовок тегом H1. Установите поля и отступы для тегов BODY, H1 и P. Для каждого абзаца установите разный вид и толщину границ .
8) Создайте параграф размерами 300*100 пикселей. Поместите туда текст большого объёма .
Сравните поведение страницы в различных браузерах .
9) Задайте для второго параграфа отрицательное верхнее поле. Оцените результат .
10) Cоздайте столбчатую диаграмму (гистограмму), используя элементы DIV заданной ширины .
11) С помощью псевдокласса first-letter создайте свой вариант буквицы. Подберите шрифт, размер, цвет и оформление .
12) Добавьте эффект выделения ссылок при наведении курсора на своем сайте .
13) Создайте буквицу, смещенную на одну строку вниз .
14) С помощью относительного позиционирования каждой буквы текста разместите их волной .
15) Создайте табличный макет для своего сайта. Выберите количество блоков/колонок, определите способ задания их ширины: фиксированный или "резиновый", напишите HTML и CSS код макета. Примените созданный шаблон для всех страниц сайта .
17) Переделайте табличный макет своего сайта в блочный .
3. Скриптовый язык программирования JavaScript. Переменные и типы данных .
Выражения. Циклы и ветвления. Функции и события. Объекты в JavaScript .
1) Определите переменные str, num, f lag и txt со значениями "Привет", 123, true, "true". При помощи оператора определения типа убедитесь, что переменных принадлежат типам string, number, boolean .
2) Создайте переменные a1, a2, a3, a4, a5. При помощи математических операторов (сложение, вычитание и т.д.) найдите значения выражений: 5 + 3, 5 - 3, 5 * 3, 5 / 3, поместив результат каждого выражения в соответствующую переменную. Например, let a 1 = 5 + 3 .
Создайте переменные a6, a7, a8, a9, a10. Поместите в них результат выражений: 5%3, 3%5, 5 + '3', '5'- 3, 75 + 'кг' .
3) а) Напишите скрипт, который находит площадь прямоугольника высота 23 см (числовая переменная height ), шириной 10 см (числовая переменная width), значение площади должно храниться в числовой переменной s .
б) Напишите скрипт, который находит объем цилиндра высотой 10 м (переменная heightC) и диаметром основания 4м (dC), результат поместите в переменную v .
в) У прямоугольного треугольника две стороны n (со значением 3) и m (со значением 4) .
Найдите гипотенузу k по теореме Пифагора (нужно использовать функцию Math.pow(число, степень) или оператор возведения в степень **) .
4) Напишите оператор if, такой, чтобы в качестве выражения в скобках у него были значения true, false (например, if(true) или if(false)) .
5) Создайте переменные m и n. В m поместите произвольное числовое значение. Напишите оператор ветвления if так, чтобы если m было больше 50, то в переменную n помещалось слово "большое", иначе – слово "маленькое" .
6) Определите, сколько раз выполнится цикл while .
7) а) Напишите скрипт, который используя оператор while выведет все числа от 45 до 67 .
б) Напишите скрипт, который используя оператор while выведет все числа от 45 до 670, кратные 10 .
в) Напишите скрипт, который используя оператор for выполнит два задания а) и б) .
8) Переменная n хранит целое число от 0 до 9. Используя оператор switch, написать скрипт, который в зависимости от числа будет выводить слово (например, если n равно 3, то будет выводиться слово "три") .
9) Используя document.write() и любую из циклических конструкций выведите десять одинаковых изображений (выводить img src="http://librus.dobrota.biz/40raznoe/"alt=". "/)
10) Создайте функцию repeat(str, n), которая возвращает строку, состоящую из n повторений строки str .
11) а) Напишите функцию mul(n,m), которая принимает два аргумента и возвращает произведение этих аргументов .
б) Создайте функцию m(a,b) оболочку для mul(). m() должна принимать два аргумента, а возвращать результат работы mul() с этими двумя аргументами. После выполнения задания создайте функцию log(), которая будет принимать одно значение, а вызывать console.log() с этим значением .
в) Напишите функцию operation(m,n,o), в которой m и n – числовые переменные, а o – функциональный литерал, который берет два аргумента и выполняет математическую операцию над ними .
4. Язык программирования PHP. Переменные. Управляющая логика. Работа с массивами. Классы .
1) Даны два числа. Найдите их сумму, произведение, сумму квадратов и среднее арифметическое .
2) Дано четырёхзначное число. Найдите сумму его цифр .
3) Дано число. Если оно больше 100, то найдите сумму его цифр, иначе найдите произведение его цифр .
5) Даны два числа. Если они отличаются не больше чем на 10, то выведите "Да", иначе – "Нет" .
6) В заданном четырёхзначном числе переставьте цифры так, чтобы полученное число оказалось наибольшим из возможных .
7) Пользователь вводит через форму номер дня недели от 1 до 7. Выведите название дня недели .
8) Пользователь выбирает из выпадающего списка страну (Греция, Испания или Турция), вводит количество дней отдыха и с помощью чекбокса указывает, есть ли у него скидка .
Рассчитайте стоимость отдыха, которая вычисляется как произведение количества дней на
400. Это число увеличивается на 10%, если выбрана Греция, на 15%, если выбрана Испания .
Полученное значение уменьшается на 5%, если у пользователя есть скидка .
9) Дан массив с элментами "Привет,", "мир" и "!". Выведите на экран фразу "Привет, мир!" .
10) Дан массив с числами. Выведите на экран только те числа, в которых есть цифра 3 .
11) Напишите функцию, реализующую последовательное слияние двух массивов .
12) Напишите функцию, реализующую слияние двух массивов одинаковой длины так, чтобы в полученном массиве чередовались элементы исходных массивов .
13) Дан массив строк, среди элементов которого есть пустые строки. Удалите все пустые строки из массива .
14) Напишите функцию сложения времени, выраженного в часах и минутах .
15) Создайте ассоциативный массив дней недели и их номеров .
16) Создайте ассоциативный массив сотрудников и их заработных плат .
17) Создайте многомерный массив и заполните его присваиванием (не перечислением) .
Индивидуальные задания (по два)
18) Реализуйте класс "Дробное число со знаком" (Fraction). Число должно быть представлено двумя полями: целая часть – целое со знаком, дробная часть – беззнаковое целое. Реализовать арифметические операции сложения, вычитания, умножения и операции сравнения .
19) Реализуйте класс "Деньги" для работы с денежными суммами. Число должно быть представлено двумя полями: рубли и копейки. Дробная часть (копейки) при выводе на экран должна быть отделена от целой части запятой. Реализовать сложение, вычитание, деление сумм, деление суммы на дробное число, умножение на дробное число и операции сравнения .
20) Реализуйте класс "Равнобочная трапеция", полями которого являются координаты 4-х точек. Предусмотреть в классе конструктор и методы: проверка, является ли фигура равнобочной трапецией; вычисления и вывод сведений о фигуре: длины сторон, периметр, площадь. Продемонстрируйте работу с классом: дано N трапеций, найти количество трапеций, у которых площадь больше средней площади .
21) Реализуйте класс "Строка". Обязательные поля класса: указатель pChar хранит адрес динамически выделенной памяти для размещения символов строки; длина строки в байтах .
Реализуйте методы следующего назначения: конструктор без параметров; конструктор, принимающий в качестве параметра строковый литерал; конструктор, принимающий в качестве параметра символ; метод получения длины строки; метод очистки строки (делает строку пустой); деструктор .
22) Реализуйте производный от "Строка" класс "Комплексное число". Строки данного класса должны состоять из двух полей разделочных символом “i”. Первое поле задает значение действительной части числа, второе – значение мнимой. Каждое из полей может содержать только символы десятичных цифр и символы “-” и “+”, определяющие знак числа. Символы “-” или “+” могут находиться только в первой позиции числа, причем символ “+” может отсутствовать, в этом случае число считается положительным. Если в составе инициализирующей строки будет встречен любой символ, отличный от допустимых, объект класса "Комплексное число" должен принимать нулевое значение. Примеры таких строк:
33il2, -7U00, +5i-21. Для класса "Комплексное число" определить следующие методы:
проверка на равенство; сложение чисел; умножение чисел .
23) Реализуйте класс List для работы с однонаправленными списками в динамической памяти. Для объектов класса List определить операции проверки списка на пустоту, добавления элемента в начало списка, в конец списка, подсчет числа вхождений элемента в список, удаление элемента из списка. Продемонстрируйте работу с шаблонным классом для списка с целыми элементами и с элементами-строками .
5. Создание сайта с (регистрации участников, отображение информации по участникам, аутентификация участников) .
С помощью изученных средств подготовки web-страниц и web-программирования реализовать сайт научной конференции со следующими функциями:
1) ввод информации об участнике (ФИО, секция, тема доклада, телефон, адрес и др.);
2) секции имеют ограниченное количество участников;
3) страницы зарегистриованных участников;
4) проверка корректности задания электронного адреса;
5) аутентификация адреса (участника) посылкой кода регистрации .
Проверка и сдача выполненного задания производится с возможной модификацией всех реализованных функций (сдающий должен уметь объяснить любую используемую строку, используемую функцию в сдаваемом коде и уметь производить его модификации) .
6. Список тем на зачёт
1. HTML и CSS (теги, атрибуты, события, селектор, стиль, классы CSS и два способа их задания, селектор с идентификатором, каскадирование, соседние селекторы, универсальный селектор, наследование, дочерние селекторы) .
2. Теги заголовка (метаинформация, кодировки страниц, title, content и др.) .
4. JavaScript (по заданиям) .
5. PHP. Классы в PHP. Конструкторы. Деструкторы. Наследование (по заданиям) .
6. Схема аутентификации e-mail пользователя сайта с отправкой кода и возможные угрозы безопасности (перехват) .
8. DNS (DNS-сервер, DNS-клиент, итеративный и рекурсивный DNS-запросы, иерархическая организация работы DNS-серверов и её необходимость, зона DNS,
Обязательные методы должны выполнять следующие действия:
- конструктор без параметров;
- конструктор, принимающий в качестве параметра Си-строку (заканчивается нулевым байтом);
- конструктор, принимающий в качестве параметра символ;
- конструктор копирования;
- получение длины строки;
- очистка строки (делать строку пустой);
- деструктор.
Описать производный от СТРОКА класс БИТОВАЯ_СТРОКА.
Строки данного класса могут содержать только символы ‘0’ или ‘1’. Если в составе инициализирующей строки будут встречены любые символы, отличные от допустимых, БИТОВАЯ_СТРОКА принимает нулевое значение. Содержимое данных строк рассматривается как двоичное число.
Отрицательные числа хранятся в дополнительном коде.
- конструктор без параметров;
- конструктор, принимающий в качестве параметра Си-строку (заканчивается нулевым байтом);
- конструктор копирования;
- деструктор;
- изменение знака на противоположный (перевод числа в дополнительный код). Переопределить следующие операции (длина строки результата равна длине большей из строк; в случае необходимости более короткая битовая строка расширяется влево знаковым разрядом);
- присваивание (=);
- сложение (+) – арифметическая сумма строк;
- операция (= =) – проверка на равенство.
Разработчик вправе вводить любое (с обоснованием необходимости) число дополнительных полей и методов.
Написать тестовую программу, которая:
- Динамически выделяет массив указателей на базовый класс (4-6);
- В режиме диалога заполняет этот массив указателями на производные классы, при этом экземпляры производных классов создаются динамически с заданием начальных значений;
- Для созданных экземпляров производных классов выполняет проверку всех разработанных методов с выводом исходных данных и результатов на дисплей.
Для конструкторов копирования каждого класса предусмотреть диагностическую печать количества его вызовов в определенное место дисплея (рекомендуется использовать статические члены класса).
Помогите,пожалуйста .Вообще не полнимаю что здесь делать
Вот такое задание:
Описать базовый класс СТРОКА.
Обязательные члены класса:
* указатель на char - хранит адрес динамически выделенной памяти
для размещения символов строки;
* значение типа int - хранит длину строки в байтах.
Обязательные методы должны выполнять следующие действия:
* конструктор без параметров;
* конструктор, принимающий в качестве параметра
Си-строку (заканчивается нулевым байтом);
* конструктор, принимающий в качестве параметра символ (char).
* конструктор копирования;
* деструктор.
* чтение символа из заданной позиции;
Производный от СТРОКА класс СТРОКА_ИДЕНТИФИКАТОР
Строки данного класса строятся по правилам записи идентификаторов
в СИ, и могут включать в себя только те символы, которые могут входить
в состав Си-идентификаторов. Если исходные данные противоречат правилам записи идентификатора, то создается пустая СТРОКА_ИДЕНТИФИКАТОР.
Обязательные методы:
* конструктор без параметров;
* конструктор, принимающий в качестве параметра Си-строку
(заканчивается нулевым байтом);
* конструктор, принимающий в качестве параметра символ (char).
* конструктор копирования;
* деструктор.
* перевод всех символов строки (кроме цифр) в нижний регистр;
Переопределить следующие операции:
* присваивание (=);
* оператор == - проверка на равенство;
Производный от СТРОКА класс БИТОВАЯ_СТРОКА.
Строки данного класса могут содержать только символы '0' или '1'. Если
в составе инициализирующей строки будут встречены любые символы, отличные
от допустимых, БИТОВАЯ_СТРОКА принимает нулевое значение.
Содержимое данных строк рассматривается как двоичное число.
Отрицательные числа хранятся в дополнительном коде.
Число считается отрицательным, если крайний левый(знаковый) разряд = 1,
при этом разрядность числа может быть любой в пределах ограничений, указанных в файле README.TXT. Таким образом, числа 11101 и 101 являются отрицательными и равными по значению.
Обязательные методы:
* конструктор без параметров;
* конструктор, принимающий в качестве параметра
Си-строку (заканчивается нулевым байтом);
* конструктор копирования;
* деструктор;
* удаление лишних ведущих символов (нулей или единиц в зависимости от
знака числа);
Переопределить следующие операции (длина строки результата равна длине большей из строк, в случае необходимости, более короткая битовая строка расширяется влево знаковым разрядом) :
* присваивание (=);
* операция == - проверка на равенство
* операция < - проверка на меньше (по значению).
Разработчик вправе вводить любое (с обоснованием необходимости) число дополнительных членов и методов.
Задание:
Разработать иерархию классов по следующей схеме:
СТРОКА
|
V
| |
СТРОКА_ИДЕНТИФИКАТОР БИТОВАЯ_СТРОКА
с обязательной поддержкой заданных членов и методов.
Написать тестовую программу, которая:
* динамически выделяет массив указателей на базовый класс размерностью,
заданной в п/п. 1.1.
* в режиме диалога заполняет этот массив указателями на производные классы,
при этом экземпляры производных классов создаются динамически с заданием
начальных значений;
* для созданных экземпляров производных классов выполняется
проверка всех разработанных методов (в соответствии с вариантом задания),
с выводом исходных данных и результатов на дисплей.
Описать базовый класс СТРОКА. Обязательные члены класса: * указатель на char - хранит адрес динамически выделенной памяти для размещения символов строки; * значение типа int - хранит длину строки в байтах. Обязательные методы должны выполнять следующие действия: * конструктор без параметров; * конструктор, принимающий в качестве параметра Си-строку (заканчивается нулевым байтом); * конструктор, принимающий в качестве параметра символ (char). * конструктор копирования; * деструктор. * чтение символа из заданной позиции; |
* конструктор, принимающий в качестве параметра символ (char).
* чтение символа из заданной позиции;
вот эти я не сделал
конструктор, принимающий в качестве параметра символ (char) |
Видимо, имеется в виду метод, который на вход принимает индекс, на выходе - символ.
Что интереснее, Вы:
1) Забыли квалификатор доступа public: - сейчас объект класса нельзя создать, все методы, включая конструкторы, недоступны извне.
2) Аргумент конструктора, наверное, const char* str? Иначе нельзя создать объект по константной строке.
3) При копировании C-строки настоятельно рекомендуется отводить n+1 символ (последний символ - под нуль-терминатор '\0', которым кончается любая C-строка). Прочитайте главу Вашего учебника про C-строки ещё раз.
В остальном вроде вполне сносно.
а в моей реализации конструктора, принимающего строку текста, строка заканчивается нулевым байтом?или для этого что-то нужно дополнительно прописать?
Последний раз редактировалось Stilet; 23.05.2013 в 07:07 .а в моей реализации конструктора, принимающего строку текста, строка заканчивается нулевым байтом?или для этого что-то нужно дополнительно прописать? |
Разумеется, нет - Вы же этого не сделали.
Посмотрите описание функции strcpy() / strncpy(). И описание функции strlen(), внимательно.
Далее, не забываем: данные - в private-секции, методы - в public-секции.
Далее, конструктор String::String(char) не устанавливает значение n. Не хорошо.
Далее, если массив имеет длину n+1, то последний элемент имеет индекс n, у Вас ошибка на единицу.
Статическое выделение памяти выполняется для статических и глобальных переменных. Память выделяется один раз (при запуске программы) и сохраняется на протяжении работы всей программы.
Автоматическое выделение памяти выполняется для параметров функции и локальных переменных. Память выделяется при входе в блок, в котором находятся эти переменные, и удаляется при выходе из него.
Динамическое выделение памяти является темой этого урока.
Динамическое выделение переменных
Как статическое, так и автоматическое распределение памяти имеют два общих свойства:
Размер переменной/массива должен быть известен во время компиляции.
Выделение и освобождение памяти происходит автоматически (когда переменная создается/уничтожается).
В большинстве случаев с этим всё ОК. Однако, когда дело доходит до работы с пользовательским вводом, то эти ограничения могут привести к проблемам.
Например, при использовании строки для хранения имени пользователя, мы не знаем наперед насколько длинным оно будет, пока пользователь его не введет. Или нам нужно создать игру с непостоянным количеством монстров (во время игры одни монстры умирают, другие появляются, пытаясь, таким образом, убить игрока).
Если нам нужно объявить размер всех переменных во время компиляции, то самое лучшее, что мы можем сделать — это попытаться угадать их максимальный размер, надеясь, что этого будет достаточно:
char name [ 30 ] ; // будем надеяться, что пользователь введет имя длиной менее 30 символов! Polygon rendering [ 40000 ] ; // этому 3D-рендерингу лучше состоять из менее чем 40000 полигонов!Это плохое решение, по крайней мере, по трем причинам:
Во-первых, теряется память, если переменные фактически не используются или используются, но не все. Например, если мы выделим 30 символов для каждого имени, но имена в среднем будут занимать по 15 символов, то потребление памяти получится в два раза больше, чем нам нужно на самом деле. Или рассмотрим массив rendering : если он использует только 20 000 полигонов, то память для других 20 000 полигонов фактически тратится впустую (т.е. не используется)!
В Visual Studio это можно проверить, запустив следующий фрагмент кода:
int array [ 1000000000 ] ; // выделяем 1 миллиард целочисленных значенийЛимит в 1МБ памяти может быть проблематичным для многих программ, особенно где используется графика.
Для динамического выделения памяти одной переменной используется оператор new:
new int ; // динамически выделяем целочисленную переменную и сразу же отбрасываем результат (так как нигде его не сохраняем)В примере, приведенном выше, мы запрашиваем выделение памяти для целочисленной переменной из операционной системы. Оператор new возвращает указатель, содержащий адрес выделенной памяти.
Для доступа к выделенной памяти создается указатель:
int * ptr = new int ; // динамически выделяем целочисленную переменную и присваиваем её адрес ptr, чтобы затем иметь доступ к нейЗатем мы можем разыменовать указатель для получения значения:
* ptr = 8 ; // присваиваем значение 8 только что выделенной памятиВот один из случаев, когда указатели полезны. Без указателя с адресом на только что выделенную память у нас не было бы способа получить доступ к ней.
Как работает динамическое выделение памяти?
На вашем компьютере имеется память (возможно, большая её часть), которая доступна для использования программами. При запуске программы ваша операционная система загружает эту программу в некоторую часть этой памяти. И эта память, используемая вашей программой, разделена на несколько частей, каждая из которых выполняет определенную задачу. Одна часть содержит ваш код, другая используется для выполнения обычных операций (отслеживание вызываемых функций, создание и уничтожение глобальных и локальных переменных и т.д.). Мы поговорим об этом чуть позже. Тем не менее, большая часть доступной памяти компьютера просто находится в ожидании запросов на выделение от программ.
Когда вы динамически выделяете память, то вы просите операционную систему зарезервировать часть этой памяти для использования вашей программой. Если ОС может выполнить этот запрос, то возвращается адрес этой памяти обратно в вашу программу. С этого момента и в дальнейшем ваша программа сможет использовать эту память, как только пожелает. Когда вы уже выполнили с этой памятью всё, что было необходимо, то её нужно вернуть обратно в операционную систему, для распределения между другими запросами.
В отличие от статического или автоматического выделения памяти, программа самостоятельно отвечает за запрос и обратный возврат динамически выделенной памяти.
Освобождение памяти
Когда вы динамически выделяете переменную, то вы также можете её инициализировать посредством прямой инициализации или uniform-инициализации (в С++11):
int * ptr1 = new int ( 7 ) ; // используем прямую инициализацию int * ptr2 = new int < 8 >; // используем uniform-инициализациюКогда уже всё, что требовалось, выполнено с динамически выделенной переменной — нужно явно указать для С++ освободить эту память. Для переменных это выполняется с помощью оператора delete:
// Предположим, что ptr ранее уже был выделен с помощью оператора new delete ptr ; // возвращаем память, на которую указывал ptr, обратно в операционную систему ptr = 0 ; // делаем ptr нулевым указателем (используйте nullptr вместо 0 в C++11)Оператор delete на самом деле ничего не удаляет. Он просто возвращает память, которая была выделена ранее, обратно в операционную систему. Затем операционная система может переназначить эту память другому приложению (или этому же снова).
Хотя может показаться, что мы удаляем переменную, но это не так! Переменная-указатель по-прежнему имеет ту же область видимости, что и раньше, и ей можно присвоить новое значение, как и любой другой переменной.
Обратите внимание, удаление указателя, не указывающего на динамически выделенную память, может привести к проблемам.
Висячие указатели
Язык C++ не предоставляет никаких гарантий относительно того, что произойдет с содержимым освобожденной памяти или со значением удаляемого указателя. В большинстве случаев, память, возвращаемая операционной системе, будет содержать те же значения, которые были у нее до освобождения, а указатель так и останется указывать на только что освобожденную (удаленную) память.
Указатель, указывающий на освобожденную память, называется висячим указателем. Разыменование или удаление висячего указателя приведет к неожиданным результатам. Рассмотрим следующую программу:
int * ptr = new int ; // динамически выделяем целочисленную переменную * ptr = 8 ; // помещаем значение в выделенную ячейку памяти delete ptr ; // возвращаем память обратно в операционную систему, ptr теперь является висячим указателем std :: cout << * ptr ; // разыменование висячего указателя приведет к неожиданным результатам delete ptr ; // попытка освободить память снова приведет к неожиданным результатам такжеВ программе, приведенной выше, значение 8 , которое ранее было присвоено динамической переменной, после освобождения может и далее находиться там, а может и нет. Также возможно, что освобожденная память уже могла быть выделена другому приложению (или для собственного использования операционной системы), и попытка доступа к ней приведет к тому, что операционная система автоматически прекратит выполнение вашей программы.
Процесс освобождения памяти может также привести и к созданию нескольких висячих указателей. Рассмотрим следующий пример:
int * ptr = new int ; // динамически выделяем целочисленную переменную int * otherPtr = ptr ; // otherPtr теперь указывает на ту же самую выделенную память, что и ptr delete ptr ; // возвращаем память обратно в операционную систему. ptr и otherPtr теперь висячие указатели // Однако, otherPtr по-прежнему является висячим указателем!Есть несколько рекомендаций, которые могут здесь помочь:
Во-первых, старайтесь избегать ситуаций, когда несколько указателей указывают на одну и ту же часть выделенной памяти. Если это невозможно, то выясните, какой указатель из всех «владеет» памятью (и отвечает за её удаление), а какие указатели просто получают доступ к ней.
Правило: Присваивайте удаленным указателям значение 0 (или nullptr в C++11), если они не выходят из области видимости сразу же после удаления.
Оператор new
При запросе памяти из операционной системы в редких случаях она может быть не выделена (т.е. её может и не быть в наличии).
По умолчанию, если оператор new не сработал, память не выделилась, то генерируется исключение bad_alloc . Если это исключение будет неправильно обработано (а именно так и будет, поскольку мы еще не рассматривали исключения и их обработку), то программа просто прекратит свое выполнение (произойдет сбой) с ошибкой необработанного исключения.
Во многих случаях процесс генерации исключения оператором new (как и сбой программы) нежелателен, поэтому есть альтернативная форма оператора new, которая возвращает нулевой указатель, если память не может быть выделена. Нужно просто добавить константу std::nothrow между ключевым словом new и типом данных:
int * value = new ( std :: nothrow ) int ; // указатель value станет нулевым, если динамическое выделение целочисленной переменной не выполнитсяВ примере, приведенном выше, если оператор new не возвратит указатель с динамически выделенной памятью, то возвратится нулевой указатель.
Разыменовывать его также не рекомендуется, так как это приведет к неожиданным результатам (скорее всего, к сбою в программе). Поэтому наилучшей практикой является проверка всех запросов на выделение памяти для обеспечения того, что эти запросы будут выполнены успешно и память выделится:
int * value = new ( std :: nothrow ) int ; // запрос на выделение динамической памяти для целочисленного значения if ( ! value ) // обрабатываем случай, когда new возвращает null (т.е. память не выделяется)Поскольку не выделение памяти оператором new происходит крайне редко, то обычно программисты забывают выполнять эту проверку!
Нулевые указатели и динамическое выделение памяти
Нулевые указатели (указатели со значением 0 или nullptr ) особенно полезны в процессе динамического выделения памяти. Их наличие как бы сообщаем нам: «Этому указателю не выделено никакой памяти». А это, в свою очередь, можно использовать для выполнения условного выделения памяти:
// Если для ptr до сих пор не выделено памяти, то выделяем еёУдаление нулевого указателя ни на что не влияет. Таким образом, в следующем нет необходимости:
Вместо этого вы можете просто написать:
Если ptr не является нулевым, то динамически выделенная переменная будет удалена. Если значением указателя является нуль, то ничего не произойдет.
Утечка памяти
Динамически выделенная память не имеет области видимости, т.е. она остается выделенной до тех пор, пока не будет явно освобождена или пока ваша программа не завершит свое выполнение (и операционная система очистит все буфера памяти самостоятельно). Однако указатели, используемые для хранения динамически выделенных адресов памяти, следуют правилам области видимости обычных переменных. Это несоответствие может вызвать интересное поведение, например:
Здесь мы динамически выделяем целочисленную переменную, но никогда не освобождаем память через использование оператора delete. Поскольку указатели следуют всем тем же правилам, что и обычные переменные, то, когда функция завершит свое выполнение, ptr выйдет из области видимости. Поскольку ptr — это единственная переменная, хранящая адрес динамически выделенной целочисленной переменной, то, когда ptr уничтожится, больше не останется указателей на динамически выделенную память. Это означает, что программа «потеряет» адрес динамически выделенной памяти. И в результате эту динамически выделенную целочисленную переменную нельзя будет удалить.
Это называется утечкой памяти. Утечка памяти происходит, когда ваша программа теряет адрес некоторой динамически выделенной части памяти (например, переменной или массива), прежде чем вернуть её обратно в операционную систему. Когда это происходит, то программа уже не может удалить эту динамически выделенную память, поскольку больше не знает, где выделенная память находится. Операционная система также не может использовать эту память, поскольку считается, что она по-прежнему используется вашей программой.
Хотя утечка памяти может возникнуть и из-за того, что указатель выходит из области видимости, возможны и другие способы, которые могут привести к утечкам памяти. Например, если указателю, хранящему адрес динамически выделенной памяти, присвоить другое значение:
Читайте также: