<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://mit.spbau.ru/sewiki/index.php?action=history&amp;feed=atom&amp;title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8</id>
		<title>Динамическое распределение памяти - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://mit.spbau.ru/sewiki/index.php?action=history&amp;feed=atom&amp;title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8"/>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8&amp;action=history"/>
		<updated>2026-04-03T19:39:24Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8&amp;diff=145&amp;oldid=prev</id>
		<title>Alexey.Gurevich: Новая страница: «== Виды памяти ==  Память, которую использует программа делится на три вида:  1. Статическая п…»</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8&amp;diff=145&amp;oldid=prev"/>
				<updated>2011-03-27T19:29:14Z</updated>
		
		<summary type="html">&lt;p&gt;Новая страница: «== Виды памяти ==  Память, которую использует программа делится на три вида:  1. Статическая п…»&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== Виды памяти ==&lt;br /&gt;
&lt;br /&gt;
Память, которую использует программа делится на три вида:&lt;br /&gt;
&lt;br /&gt;
1. Статическая память (static memory)&lt;br /&gt;
* хранит глобальные переменные и константы;&lt;br /&gt;
* размер определяется при компиляции.&lt;br /&gt;
2. Стек (stack)&lt;br /&gt;
* хранит локальные переменные, аргументы функций и промежуточные значения вычислений;&lt;br /&gt;
* размер определяется при запуске программы (обычно выделяется 4 Мб).&lt;br /&gt;
3. Куча (heap)&lt;br /&gt;
* динамически распределяемая память;&lt;br /&gt;
* ОС выделяет память по частям (по мере необходимости).&lt;br /&gt;
&lt;br /&gt;
Динамически распределяемую память следует использовать в случае если мы заранее (на момент написания программы) не знаем сколько памяти нам понадобится (например, размер массива зависит от того, что введет пользователь во время работы программы) и при работе с большими объемами данных (например, массив из 1 000 000 элементов типа &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; не поместится на стеке).&lt;br /&gt;
&lt;br /&gt;
== Работа с динамической памятью в С ==&lt;br /&gt;
&lt;br /&gt;
Для работы с динамической памятью в языке С используются следующие функции: &amp;lt;code&amp;gt;malloc, calloc, free, realloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
Рассмотрим их подробнее.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void * malloc(size_t size);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В качестве входного параметра функция принимает размер памяти, которую требуется выделить. Возвращаемым значением является указатель на выделенный в куче участок памяти.&lt;br /&gt;
Для выделения памяти под 1 000 000 элементов типа &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; необходимо выполнить следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * p = malloc(1000000 * sizeof(int));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В языке С++ потребуется небольшая модификация данной кода (из-за того, что в С++ нет неявного приведения указателей):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * p = (int *) malloc(1000000 * sizeof(int));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если ОС не смогла выделить память (например, памяти не хватило), то &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt; возвращает 0.&lt;br /&gt;
&lt;br /&gt;
После окончания работы с выделенной динамически памятью нужно освободить ее. Для этой цели используется функция &amp;lt;code&amp;gt;free&amp;lt;/code&amp;gt;, которая возвращает память под управление ОС.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void free(void * ptr);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В качестве входного параметра в &amp;lt;code&amp;gt;free&amp;lt;/code&amp;gt; нужно передать указатель, значение которого получено из функции &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt;. Вызов &amp;lt;code&amp;gt;free&amp;lt;/code&amp;gt; на указателях полученных не из &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt; (например, &amp;lt;code&amp;gt;free(p+10)&amp;lt;/code&amp;gt;) приведет к неопределенному поведению. Это связанно с тем, что при выделении памяти при помощи &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt; в ячейки перед той, на которую указывает возвращаемый функцией указатель операционная система записывает служебную информацию (см. рис.). При вызове &amp;lt;code&amp;gt;free(p+10)&amp;lt;/code&amp;gt; информация находящаяся перед ячейкой &amp;lt;code&amp;gt;(p+10)&amp;lt;/code&amp;gt; будет трактоваться как служебная.&lt;br /&gt;
&lt;br /&gt;
[[Файл:pointer_in_heap.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void * calloc(size_t nmemb, size_t size);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Функция работает аналогично &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt;, но отличается синтаксисом (вместо размера выделяемой памяти нужно задать количество элементов и размер одного элемента) и тем, что выделенная память будет обнулена. Например, после выполнения&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * q = (int *) calloc(1000000, sizeof(int))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; будет указывать на начало массива из миллиона элементов типа &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; проинициализированных нулями.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void * realloc(void * ptr, size_t size);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Функция изменяет размер выделенной памяти (на которую указывает &amp;lt;code&amp;gt;ptr&amp;lt;/code&amp;gt;, полученный из вызова &amp;lt;code&amp;gt;malloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;calloc&amp;lt;/code&amp;gt; или &amp;lt;code&amp;gt;realloc&amp;lt;/code&amp;gt;). Если размер указанный в параметре &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; больше, чем тот, который был выделен под указатель &amp;lt;code&amp;gt;ptr&amp;lt;/code&amp;gt;, то проверяется, есть ли возможность выделить недостающие ячейки памяти подряд с уже выделенными. Если места недостаточно, то выделяется новый участок памяти размером &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; и данные по указателю &amp;lt;code&amp;gt;ptr&amp;lt;/code&amp;gt; копируются в начало нового участка.&lt;br /&gt;
&lt;br /&gt;
=== Какие бывают ошибки ===&lt;br /&gt;
1. Потеря памяти&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * p = (int *) malloc(100);&lt;br /&gt;
p = (int *) malloc(200); // потерян указатель на первые 100 &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;'ов, которые теперь нельзя отдать обратно ОС&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
2. Повторное освобождение выделенной памяти&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
free(p);&lt;br /&gt;
… &lt;br /&gt;
free(p); // неопределенное поведение&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Правильно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
free(p);&lt;br /&gt;
p = 0;&lt;br /&gt;
…&lt;br /&gt;
free(p); // отработает без ошибок &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Работа с динамической памятью в С++ ==&lt;br /&gt;
&lt;br /&gt;
В С++ есть свой механизм выделения и освобождения памяти — это функции &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пример использования &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * p = new int[1000000]; // выделение памяти под 1000000 int`ов&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Т.е. при использовании функции &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; не нужно приводить указатель и не нужно использовать &amp;lt;code&amp;gt;sizeof()&amp;lt;/code&amp;gt;.&lt;br /&gt;
Освобождение выделенной при помощи &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; памяти осуществляется посредством следующего вызова:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
delete [] p;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если требуется выделить память под один элемент, то можно использовать&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * q = new int;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
или&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int * q = new int(10); // выделенный int проинциализируется значением 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
в этом случае удаление будет выглядеть следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
delete q;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
'''Замечание:'''  &lt;br /&gt;
&lt;br /&gt;
Выделять динамически небольшие кусочки памяти (например, под один элемент простого типа данных) не целесообразно по двум причинам:&lt;br /&gt;
# При динамическом выделении памяти в ней помимо значения указанного типа будет храниться служебная информация ОС и С/С++. Таким образом потребуется гораздо больше памяти, чем при хранении необходимых данных на стеке.&lt;br /&gt;
# Если в памяти хранить большое количество маленьких кусочков, то она будет сильно фрагментирована и большой массив данных может не поместиться.&lt;br /&gt;
&lt;br /&gt;
=== Многомерные массивы ===&lt;br /&gt;
&amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; позволяет выделять только одномерные массивы, поэтому для работы с многомерными массивами необходимо воспринимать их как массив указателей на другие массивы.&lt;br /&gt;
Для примера рассмотрим задачу выделения динамической памяти под массив чисел размера &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; на &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''1ый способ''' &lt;br /&gt;
 &lt;br /&gt;
На первом шаге выделяется указатель на массив указателей, а на втором шаге, в цикле каждому указателю из массива выделяется массив чисел в памяти:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int ** a = new int*[n];&lt;br /&gt;
for (int i = 0; i != n; ++i)&lt;br /&gt;
  a[i] = new int[m];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Однако, этот способ плох тем, что в нём требуется n+1 выделение памяти, а это достаточно дорогая по времени операция.  &lt;br /&gt;
&lt;br /&gt;
'''2ой способ'''  &lt;br /&gt;
&lt;br /&gt;
На первом шаге выделение массива указателей и массива чисел размером n на m. На втором шаге каждому указателю из массива ставится в соответствие строка в массиве чисел.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int ** a = new int*[n];&lt;br /&gt;
a[0] = new int[n*m];&lt;br /&gt;
for (int i = 1; i != n; ++i)&lt;br /&gt;
  a[i] = a[0] + i*m;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В данном случае требуется всего 2 выделения памяти.&lt;br /&gt;
Для освобождения памяти потребуется выполнить:  &lt;br /&gt;
&lt;br /&gt;
'''1ый способ:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
for (int i = 0; i != n; ++i)&lt;br /&gt;
  delete [] a[i];&lt;br /&gt;
delete [] a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
'''2ой способ:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
delete [] a[0];&lt;br /&gt;
delete [] a;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Таким образом, второй способ опять же требует гораздо меньше вызовов функции &amp;lt;code&amp;gt;delete []&amp;lt;/code&amp;gt;, чем первый.&lt;/div&gt;</summary>
		<author><name>Alexey.Gurevich</name></author>	</entry>

	</feed>