Проблемы, возникающие при использовании динамически распределяемой памяти


1). Недоступные блоки — блоки памяти, указатели на которые потеряны.
2). Висящие ссылки — указатели на освобожденные блоки памяти.
3). Повторное освобождение динамической памяти.
Недоступные блоки возникают после выделения памяти при присваивании указателю какого — либо другого значения или при уничтожении локального указателя после выхода из области видимости.
Пример 1:
int *a1, *a2;
a1 = new int[1000]; //выделили память
… //что-то делаем
a1 = a2; //ошибка — присвоение а1 другого
//значения — память недоступна
Пример 2:
void func(void)
{
int * a1;
a1 = new int[1000];

} //ошибка — при выходе из функции автоматически
//уничтожен a1,а память тем не менее осталась
//занята и недоступна.
Необходимо следить за указателями на выделенную память:
int * c;
void func1(void) {
int * a1;
a1 = new int[1000];
c = a1; //если данные по адресу a1 необходимы вне
//func1
… //иначе освободить перед выходом из функции
}
void func2(void)
{

delete c;
}
Висящие ссылки возникают при освобождении памяти, на которую указывает более чем 1 указатель:
int *a = new int[1000];
int *a1 = a;

delete a;
d = *(a1+50);
//опасно — a1 уже нельзя использовать для обращения к
//массиву!

Если нет освобождения памяти, программист в зависимости от конкретной ситуации может посчитать это ошибкой, а может и нет (хотя это в любом случае уменьшает доступные ресурсы памяти), повторное освобождение безусловно ошибочно и скорее всего приведет к зависанию системы. Как правило, подобные ошибки не проявляются немедленно после появления, что затрудняет процесс отладки.

1?5?8? Указатель на void
Такому указателю можно присвоить значение указателя на любой базовый тип.
void *v_ptr;
int *int_ptr = new int;
v_ptr = int_ptr;

//Программа 4.

#include <stdio.h>
#include <conio.h>
void swap (void *&item1, void *&item2)
{
void *temp = item1;
item1 = item2;
item2 = temp;
}
void main(void)
{
int *i = new int,
*j = new int;
*i = 5;
*j = 20;
clrscr();
swap((void *&)i,(void *&)j);
printf(» *i = %d, *j = %d \n», *i,*j);
float *x = new float,
*z = new float;
*x = 5.0;
*z = 20.0;
swap((void *&)x,(void *&)z);
printf(» *x = %f, *z = %f \n», *x,*z);
}
1?6? Перегрузка функций
Имена функций могут быть перегружены в пределах одной области видимости. Компилятор отличает одну функцию от другой по сигнатуре. Сигнатура задается числом, порядком следования и типами ее параметров.

//Программа 5.
#include <stdio.h>
#include <string.h>
int noName (int first)
{
return first*first;
}
int noName (unsigned first)
{
return first*first;
}
char noName (char first)
{
return first*first;
}
int noName (int first,char *second)
{
return first*strlen(second);
}

float noName (float r)
{
return r*r;
}
double noName (double r)
{
return r*r;
}
void main(void)
{
printf(«%d\n», noName(4));
printf(«%d\n», noName((unsigned)4));
printf(«%c\n», noName(‘c’));
printf(«%d\n», noName(4,»cлово»));
printf(«%0.2f\n», noName((float)1.2));
printf(«%0.2lf\n», noName((double)1.2));
}

1?7? Значение формальных параметров по умолчанию
Формальный параметр может иметь значение по умолчанию. Все параметры, стоящие справа от него тоже должны иметь значения по умолчанию. Эти значения передаются в функцию, если при вызове данные параметры не указаны.
//Программа 6.
#include <stdio.h>
void noName1 (float x, int y, char z=’b’)
{
printf(«x = %0.1f y = %d, z = %d \n», x,y, (int)z);
}
void noName2 (float x, int y=16, char z=’a’)
{
printf(«x = %0.1f y = %d, z = %d \n», x,y, (int)z);
}
void noName3 (float x=1.3, int y=4, char z=’c’)
{
printf(«x = %0.1f y = %d, z = %d \n», x,y, (int)z);
}
void main(void)
{
noName1(1.0,2);
noName2(100.0);
noName3();
}

Загрузка...