Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторные_работы_1-7.doc
Скачиваний:
25
Добавлен:
16.11.2019
Размер:
2.11 Mб
Скачать

4Ссылки

Ссылка представляет собой синоним имени, указанного при инициализации ссылки. Ссылку можно рассматривать как указатель, который всегда разыменован. Формат объявления ссылки:

тип & имя;

где тип – это тип величины, на которую указывает ссылка, & – оператор ссылки, означающий, что следующее за ним имя является именем переменной ссылочного типа, например:

int kol;

int& pal = kol; // ссылка pal - альтернативное имя для kol

const char& CR = '\n'; // ссылка на константу

Необходимо помнить следующие правила:

переменная-ссылка должна явно инициализироваться при ее описании, кро­ме случаев, когда она является параметром функции, описана как extern или ссылается на поле данных класса;

после инициализации ссылке не может быть присвоена другая переменная;

тип ссылки должен совпадать с типом величины, на которую она ссылается;

не разрешается определять указатели на ссылки, создавать массивы ссылок и ссылки на ссылки.

Ссылки применяются чаще всего в качестве параметров функций и типов возвращаемых функциями значений. Ссылки позволяют использовать в функциях переменные, передаваемые по адресу, без операции разыменования, что улучшает читаемость программы

Ссылка, в отличие от указателя, не занимает дополнительного пространства в памяти и является просто другим именем величины. Операции над ссылкой приводят к изменению величины, на которую она ссылается, то есть с ней работают как с переменной, но обращение идет с использование адреса, а не копии переменной.

5Динамическое распределение памяти

До сих пор для данных, которые использовались, память выделялась при объявлении переменных. Такой способ выделения памяти называется статическим.

Однако иногда размер данных становится известным только во время выполнения программы. Например, если в процессе какого-либо измерения выполняется сохранение данных через определенные промежутки времени, объем этих данных зависит от времени, прошедшего с начала измерения. В таком случае рациональнее распределять память компьютера во время измерения. Процедура выделения памяти во время выполнения программы называется динамическим распределением (выделением) памяти.

В C++ существует два способа динамического выделения памяти. Один из них, унаследованный от С, использует стандартные библиотечные функции malloc и free. Другой – операторы new и delete, которые отсутствуют в С. Для обоих способов необходимо применение переменных типа указатель. Как правило, конкретные адреса, содержащиеся в этих переменных, не используются.

5.1Использование стандартных функций malloc и free

Динамическое выделение памяти с помощью библиотечной функции malloc состоит из следующих шагов.

1. Включение в программу файла заголовков malloc.h директивой #include <malloc.h>.

2. Объявление указателя нужного типа, например int *p;

3. Вызов функции malloc с указанием в качестве параметра требуемого количества памяти в байтах. Так как функция выдает результат своей работы в виде указателя на тип void, выполняется приведение типа (преобразуется тип результата к типу, указанному в объявлении). Присваивается полученное значение объявленному указателю. Пример:

p=(int *) malloc (число элементов массива*sizeof(int));

Вместо int может быть подставлен любой стандартный или введенный программистом тип.

4. Проверка факта выделения памяти. Если выделение памяти в нужном объеме невозможно, функция malloc возвращает в качестве своего результата нулевой указатель NULL, соответствующий значению ложь. Если выделение памяти выполнено, продолжаем выполнение программы, если нет, выходим из нее с соответствующей диагностикой о недостатке памяти. Пример:

if (!p) сообщение, выход; else продолжение;

5. Освобождение памяти после окончания работы с ней. Для этого вызываем функцию fгее и используем указатель в качестве аргумента:

free (p);

Значение указателя, полученное после выполнения шага 3, должно сохраняться до выполнения шага 5. В противном случае вся память, выделенная по этому адресу, будет потеряна при выходе из программы, что, в конечном счете, может привести к недостатку памяти и нарушению работы операционной системы.

Наиболее частой причиной «зависания» компьютера при работе с динамически выделяемой памятью является несоответствие инструкций malloc и free (в обеих инструкциях должен использоваться один и тоже указатель) или недостаточный объем свободной памяти.

В качестве примера рассмотрим ввод/вывод одномерного динамического массива произвольной длины, задаваемой с клавиатуры.

int i,n,*massiv; //объявление указателя

cout<<RUS("Введите размер массива\n");cin>>n;//ввод размера массива

massiv=(int*)malloc(n*sizeof(int)); //выделение динам.памяти

if(!massiv) //проверка факта выделения памяти

{cout<<RUS("\nНедостаточно памяти");

cout<<RUS("\nНажмите любую клавишу для завершения программы ...\n");

getch();

return 0;}

cout<<RUS("Введите массив\n");

for(i=0;i<n;i++)cin>>massiv[i]; //ввод массива

cout<<RUS("\nmassiv\n");

for(i=0;i<n;i++)cout<<' '<<massiv[i]; //вывод массива

free(massiv); //освобождение памяти

В этой программе указатель используется только для выделения динамической памяти. Далее в программе обращение к элементам массива осуществляется через имя массива, которое совпадает с именем указателя.

Для динамического выделения памяти можно также использовать функцию calloc( ). В отличии от malloc функция calloc кроме выделения области памяти под массив объектов еще производит инициализацию элементов массива нулевыми значениями.

В зависимости от используемой версии C++ для работы с большими фрагментами динамической памяти возможно применение функций farmalloc( ), farcalloc( ), farcoreleft( ) и farfree().