Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Возможные причины утечки памяти

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

Выход такого указателя из области своего действия

При неаккуратном использовании динамической памяти возможно появление «мусора», (или «утечки» памяти), т.е. такой памяти, которая считается выделенной программе, но ее адрес по каким-то причинам утерян, и доступ к ней невозможен.

Примеры неправильной работы с памятью

int *pi1=new int, *pi2=new int;

*pi1=0;

pi2=pi1;

// хотели написать *pi2 = *pi1 L

// получили утечку памяти

(*pi2)++;

// тем самым изменилось и *pi1, но

// этого не видим

delete pi1; // пока нормально

delete pi2; // использование зависшего указателя крах!!!

Другая возможность появления мусора связана с тем, что указатели

подчиняются общим ограничениям на область действия и время жизни.

int my_func()

{

int *pi = new int;

} // delete pi написать забыли… L

при каждом вызове этой функции память под одну переменную типа int будет отправляться в мусор.

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

int *p;

p++;

значение p увеличивается не на единицу, а на sizeof(int) (арифметические операции над абстрактными указателями недопустимы). Разность между двумя указателями – это разность их значений, деленная на размер типа в байтах. Суммирование двух указателей не допускается.

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

Пример неправильной работы с памятью (часть 2)

int *pv = new int;

pv++;

*pv=1;

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

При записи выражений с указателями следует обращать внимание на приоритет операций и при необходимости расставлять скобки. Так, выражение (*p)++ увеличивает значение, расположенное по адресу, хранящемуся в p. С другой стороны, выражение *(p++) изменяет значение указателя. Тем не менее, оба выражения возвращают старые данные, хранящиеся по старому адресу. Поэтому, записывая оператор *p++, задумайтесь – поймет ли компилятор то, что вы хотели сказать!

(*p++ выполняетсяв C++ как *(p++))

Динамическое выделение памяти под одномерный массив
Динамическое выделение памяти под массив из N элементов типа int:
1) с помощью функции malloc (предполагается, что значение N известно):
int *pi = (int *) malloc(N*sizeof(int));
2) с помощью операции new:
int *pi = new int[N];
Освобождение памяти, занятой этим массивом, выполняется соответственно операторами
free(pi);
delete [] pi;

Обратите внимание на необходимость указания скобок в операции delete.
Доступ к i-му элементу:
pi[i] или *(pi+i)


int a[]={1,2,3,4,5,6,7};
int x;
int *pa;
pa = &a[0]; //pa=a;
x = *pa;
cout<< x; //1;
int i=4;
cout<< *(pa+4); //5;
cout<< *(pa+i); //5;

Таким образом, если pa указывает на a[0], то *(pa+1) есть содержимое a[1], a+i -адрес a[i], *(pa+i) - содержимое a[i].

Смысл слов "добавить 1 к указателю", как и смысл любой арифметики с указателями, состоит в том, чтобы pa+1 указывал на следующий объект, a pa+i - на i -й после pa.

pa = &a[0];
pa = a;

ра и a имеют одно и то же значение.
Пусть a – массив и ра указатель:
int a[]={1,2,3,4,5,6,7};
int x;
int *pa=a;

Для обращения к i тому элементу
a[i] и *(a+i).
pa[i] и *(pa+i).

Элемент массива можно изображать как в виде указателя со смещением, так и в виде имени массива с индексом.
Между именем массива и указателем, выступающим в роли имени массива, существует одно различие.
Указатель - это переменная, поэтому можно написать pa=a или pa++.
Имя массива не является переменной, и записи вроде a=pa или a++ не допускаются.

int a[]={1,2,3,4,5,6};
int b[]={1,2,3,4,5,6};
int n, m;
n=&a[5]-&a[3]; //n=2
m=&a[3]-&a[5]; //m=-2
int *p;
p=(a+2); //p=&a[2];


Динамическое выделение памяти под двумерный массив

Двумерный статический массив описывается, например,
int a[10][10];
Двумерные динамические массивы реализуются через указатели на указатели. Описание
int a[10][10];
соответствует описанию
int (*a)[10];
int **a;

Для динамического массива типа int указатель a содержит адрес одномерного массива указателей типа int *, хранящих адреса строк массива (т.е. элементов массива с одинаковым значением первой размерности).

Динамическое выделение памяти под двумерный массив размерности MxN (M строк, N столбцов)

1. Использование функции malloc:
int **mas;
mas = (int **) malloc(M * sizeof(int *));
for (int i=0; i<M; i++)
mas[i] = (int *) malloc(N * sizeof(int));

Для корректного освобождения памяти необходимо записать следующий фрагмент:
for (i=0; i<M; i++)
free(mas[i]);
free(mas);

2 . Использование операций new и delete:
int **mas; // 1
mas = new int *[M]; // 2
for (int i=0; i<M; i++) // 3
mas[i] = new int [N]; // 4

1 – объявляется переменная типа <указатель на указатель на int>
2 – выделяется память под массив указателей на строки массива (M строк)
3 – организуется цикл для выделения памяти под каждую строку
4 – каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного под строку из N целых чисел

For (int i=0; i<M; i++)
delete [] mas[i];
delete [] mas;

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

<== предыдущая лекция | следующая лекция ==>
Использование неинициализированных указателей | В головной программе матрица должна быть описана с фиксированной размерностью с 10 столбцами
Поделиться с друзьями:


Дата добавления: 2014-01-07; Просмотров: 541; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.009 сек.