
- •Алгоритм
- •3. Этапы решения задач на эвм.
- •4. Структу́рное программи́рование
- •6. Типизированные указатели.
- •7.Ссылочный тип.
- •8.Перечислимый тип.
- •10.Процедуры ввода-вывода. Потоковый ввод-вывод.
- •13.Условный оператор. Оператор выбора.
- •14.Операторы безусловного перехода.
- •16.Циклические программы. Вложенные циклы.
- •17.Глобальные и локальные переменные.
- •18.Функции. Механизм передачи параметров.
- •19.Вложенные функции. Рекурсия.
- •20.Область видимости и время жизни переменной.
- •21.Фактические и формальные параметры.
- •22.Перегрузка функций.
- •23.Шаблоны функций.
- •24.Понятие модуля. Преимущества модульного программирования. Структура модуля.
- •25.Пример модуля. Способ использования модуля.
- •27.Символьный тип данных. Строковые массивы. Способы обработки.
- •28.Основные операции над строками. Функции для работы со строками.
- •29.Структуры. Работа со структурами. Примеры.
- •30.Массивы структур. Особенности обработки. Примеры.
- •31.Файлы. Виды файлов. Файловая переменная. Общая схема работы с файлами.
- •33.Текстовые файлы. Функции обработки для текстовых файлов.
- •34.Бинарные файлы. Функции для работы с бинарными файлами.
- •35.Статическая и динамическая память.
- •37.Алгоритмы и методы сортировки: оценка эффективности алгоритма.
- •38.Сортировка выбором.
- •43.Алгоритмы и методы поиска в отсортированном массиве данных.
35.Статическая и динамическая память.
Динамическое выделение памяти необходимо для эффективного использования памяти компьютера. Например, мы написали какую-то программку, которая обрабатывает массив. При написании данной программы необходимо было объявить массив, то есть задать ему фиксированный размер (к примеру, от 0 до 100 элементов). Тогда данная программа будет не универсальной, ведь может обрабатывать массив размером не более 100 элементов. А если нам понадобятся всего 20 элементов, но в памяти выделится место под 100 элементов, ведь объявление массива было статическим, а такое использование памяти крайне не эффективно.
В С++ операции new и delete предназначены для динамического распределения памяти компьютера. Операция new выделяет память из области свободной памяти, а операция delete высвобождает выделенную память. Выделяемая память, после её использования должна высвобождаться, поэтому операции new и delete используются парами. Даже если не высвобождать память явно, то она освободится ресурсами ОС по завершению работы программы. Рекомендую все-таки не забывать про операцию delete.
// пример использования операции new
int *ptrvalue = new int;
//где ptrvalue – указатель на выделенный участок памяти типа int
//new – операция выделения свободной памяти под создаваемый объект.
Операция new создает объект заданного типа, выделяет ему память и возвращает указатель правильного типа на данный участок памяти. Если память невозможно выделить, например, в случае отсутствия свободных участков, то возвращается нулевой указатель, то есть указатель вернет значение 0. Выделение памяти возможно под любой тип данных: int, float,double, char и т. д.
// пример использования операции delete:
delete ptrvalue;
// где ptrvalue – указатель на выделенный участок памяти типа int
// delete – операция высвобождения памяти
Разработаем программу, в которой будет создаваться динамическая переменная.
// new_delete.cpp: определяет точку входа для консольного приложения.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int *ptrvalue = new int; // динамическое выделение памяти под объект типа int
*ptrvalue = 9; // инициализация объекта через указатель
//int *ptrvalue = new int (9); инициализация может выполнятся сразу при объявлении динамического объекта
cout << "ptrvalue = " << *ptrvalue << endl;
delete ptrvalue; // высвобождение памяти
system("pause");
return 0;
}
В строке 10 показан способ объявления и инициализации девяткой динамического объекта, все, что нужно так это указать значение в круглых скобочках после типа данных.
Создание динамических массивов
Как было сказано раньше, массивы также могут быть динамическими. Чаще всего операции new и delete применяются, для создания динамических массивов, а не для создания динамических переменных. Рассмотрим фрагмент кода, создания одномерного динамического массива.
// объявление одномерного динамического массива на 10 элементов:
float *ptrarray = new float [10];
// где ptrarray – указатель на выделенный участок памяти под массив вещественных чисел типа float
// в квадратных скобочках указываем размер массива
После того как динамический массив стал ненужным, нужно освободить участок памяти, который под него выделялся.1
2 // высвобождение памяти отводимой под одномерный динамический массив:
delete [] ptrarray;
После оператора delete ставятся квадратные скобочки, которые говорят о том, что высвобождается участок памяти, отводимый под одномерный массив. Разработаем программу, в которой создадим одномерный динамический массив, заполненный случайными числами.
// new_delete_array.cpp: определяет точку входа для консольного приложения.
#include "stdafx.h"
#include <iostream>
// в заголовочном файле <ctime> содержится прототип функции time()
#include <ctime>
// в заголовочном файле <iomanip> содержится прототип функции setprecision()
#include <iomanip>
using namespace std;
int main(int argc, char* argv[])
{
srand(time(0)); // генерация случайных чисел
float *ptrarray = new float [10]; // создание динамического массива вещественных чисел на десять элементов
for (int count = 0; count < 10; count++)
ptrarray[count] = (rand() % 10 + 1) / float((rand() % 10 + 1)); //заполнение массива случайными числами с масштабированием от 1 до 10
cout << "array = ";
for (int count = 0; count < 10; count++)
cout << setprecision(2) << ptrarray[count] << " ";
delete [] ptrarray; // высвобождение памяти
cout << endl;
system("pause");
return 0;
}
Созданный одномерный динамический массив заполняется случайными вещественными числами, полученными c помощью функций генерации случайных чисел, причём числа генерируются в интервале от 1 до 10, интервал задается так - rand() % 10 + 1. Чтобы получить случайные вещественные числа, выполняется операция деления, с использованием явного приведения к вещественному типу знаменателя - float((rand() % 10 + 1)). Чтобы показать только два знака после запятой используем функцию setprecision(2), прототип данной функции находится в заголовочном файле <iomanip>. Функция time(0) засевает генератор случайных чисел временным значением, таким образом, получается, воспроизводить случайность возникновения чисел.
По завершению работы с массивом, он удаляется, таким образом, высвобождается память, отводимая под его хранение.
Как создавать и работать с одномерными динамическими массивами мы научились. Теперь рассмотрим фрагмент кода, в котором показано, как объявляется двумерный динамический массив.
// объявление двумерного динамического массива на 10 элементов:
float **ptrarray = new float* [2]; // две строки в массиве
for (int count = 0; count < 2; count++)
ptrarray[count] = new float [5]; // и пять столбцов
// где ptrarray – массив указателей на выделенный участок памяти под массив вещественных чисел типа float
Сначала объявляется указатель второго порядка float **ptrarray, который ссылается на массив указателей float* [2], где размер массива равен двум. После чего в цикле for каждой строке массива объявленного в строке 2 выделяется память под пять элементов. В результате получается двумерный динамический массив ptrarray[2][5]. Рассмотрим пример высвобождения памяти отводимой под двумерный динамический массив.
// высвобождение памяти отводимой под двумерный динамический массив:
for (int count = 0; count < 2; count++)
delete [] ptrarray[count];
// где 2 – количество строк в массиве
Объявление и удаление двумерного динамического массива выполняется с помощью цикла, так как показано выше, необходимо понять и запомнить то, как это делается. Разработаем программу, в которой создадим двумерный динамический массив.
// new_delete_array2.cpp: определяет точку входа для консольного приложения.
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
int main(int argc, char* argv[])
{
srand(time(0)); // генерация случайных чисел
// динамическое создание двумерного массива вещественных чисел на десять элементов
float **ptrarray = new float* [2]; // две строки в массиве
for (int count = 0; count < 2; count++)
ptrarray[count] = new float [5]; // и пять столбцов
// заполнение массива
for (int count_row = 0; count_row < 2; count_row++)
for (int count_column = 0; count_column < 5; count_column++)
ptrarray[count_row][count_column] = (rand() % 10 + 1) / float((rand() % 10 + 1)); //заполнение массива случайными числами с масштабированием от 1 до 10
// вывод массива
for (int count_row = 0; count_row < 2; count_row++)
{
for (int count_column = 0; count_column < 5; count_column++)
cout << setw(4) <<setprecision(2) << ptrarray[count_row][count_column] << " ";
cout << endl;
}
// удаление двумерного динамического массива
for (int count = 0; count < 2; count++)
delete []ptrarray[count];
system("pause");
return 0;
}
При выводе массива была использована функция setw(), если вы не забыли, то она отводит место заданного размера под выводимые данные. В нашем случае, под каждый элемент массива по четыре позиции, это позволяет выровнять, по столбцам, числа разной длинны.
Автоматическое хранилище
Обычные переменные, объявленные внутри функции, используют автоматическое хранилище и называются автоматическими переменными. Этот термин означает, что они создаются автоматически при вызове содержащей их функции и уничтожаются при ее завершении. Например, массив temp в листинге 4.22 существует только во время работы функции getname (). Когда управление программой возвращается main (), то память, используемая temp, освобождается автоматически. Если бы getname () возвращала указатель на temp, то указатель name в main () остался бы установленным на адрес памяти, которая скоро будет использована повторно. Вот почему внутри getname () необходимо вызывать new.
На самом деле автоматические значения являются локальными по отношению к блоку, в котором они объявлены. Блок — это раздел кода, ограниченный фигурными скобками. До сих пор все наши блоки были целыми функциями. Но как будет показано в следующей главе, можно иметь блоки и внутри функций. Если вы объявите переменную внутри одного из таких блоков, она будет существовать только в то время, когда программа выполняет операторы, содержащиеся внутри этого блока.
Статическое хранилище
Статическое хранилище — это хранилище, которое существует в течение всего времени выполнения программы. Есть два способа сделать переменные статическими. Один заключается в объявлении их вне функций. Другой предполагает использование при объявлении переменной ключевого слова static:
static double fee = 56.50;
Согласно правилам языка С стандарта K&R, вы можете инициализировать только статические массивы и структуры, в то время как С++ Release 2.0 (и более поздние), а также ANSI С позволяют также инициализировать автоматические массивы и структуры. Однако, как вы, возможно, обнаружите, в некоторых реализациях С++ до сих пор не реализована инициализация таких массивов и структур.
В главе 9 статическое хранилище обсуждается более подробно. Главный момент, который вы должны запомнить сейчас относительно автоматическое и статического хранения — то, что эти методы строго определяют время жизни переменных. Переменные могут либо существовать на протяжении всего выполнения программы (статические переменные) либо только в период выполнения функции или блока (автоматические переменные).
Динамическое хранилище
Операции new и delete предлагают более гибкий подход, нежели использование автоматических и статических переменных. Они управляют пулом памяти, который в С++ называется свободным хранилищем. Этот пул отделен от области памяти, используемой статическими и автоматическими переменными. Как показано в листинге 4.22, операции new и delete позволяют выделять память в одной функции и освобождать в другой. Таким образом, время жизни данных при этом не привязывается жестко к времени жизни программы или функции. Совместное применение new и delete
предоставляет вам возможность более тонко управлять использованием памяти, чем в случае обычных переменных.