Модель памяти в языке Си

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску

Модель памяти в языке Си — система хранения объектов в языке Си[1].

Способ хранения объекта в языке Си определяет его время жизни — часть времени выполнения программы, во время которого объект существует или для него зарезервировано место. Объект имеет постоянный адрес и сохраняет своё последнее значение. Запрещается обращаться к объекту, который перестал существовать, при этом, если при работе с объектом использовался указатель, его значение остаётся неопределённым.

Существует три способа хранения объектов[1]: автоматический, статический и динамический.

Свойство Автоматический Статический Динамический
Объявление Объект без связывания и без static Имеет внутреннее или внешнее связывание или объявлен с квалификатором static Выделен с помощью malloc
Время существования Блок, в котором объявлен объект Всё время выполнения программы От вызова malloc до вызова free
Инициализация Отсутствует в случае отсутствия явной инициализации Происходит один раз до запуска программы Частично в случае calloc
Размер Фиксированный, неизменяемый Фиксированный, неизменяемый Любой, изменяемый
Типичное размещение Стек или регистры процессора Отдельный сегмент памяти Куча

Статический объект можно инициализировать явно, либо использовать умалчиваемую инициализацию.

При использовании функции calloc все объекты имеют нулевое значение кроме чисел с плавающей запятой и указателей[2].

Выражения, не являющиеся lvalue, связанные с обращением к массиву, являющегося членом структуры (struct) или объединения (union) имеют время существования, ограниченное оценкой такого выражения[1].

Си-строки, которыми инициализируются указатели char*, имеют статический тип хранения и не должны изменяться[3].

Динамическая память[править | править код]

Ни один объект не может находиться в динамической памяти без явного указания программиста. Для работы с динамической памятью существуют функции malloc, calloc, realloc и free. Поскольку функции, выделяющие память, принимают размер в переменной типа size_t, максимальный объём выделяемой памяти ограничен SIZE_T_MAX[1].

Функции malloc и calloc выделяют память, которая после использования должна быть освобождена с помощью вызова free. После освобождения значение указателя остаётся неопределённым. Функция realloc возвращает указатель на изменённый блок памяти, если запрос не может быть удовлетворён, размер блока памяти не изменяется[1].

#include <stdlib.h>

void foo (void **ptr, size_t size)
{
   *ptr = realloc (*ptr, size+128); /* утечка памяти, если realloc вернёт NULL */
   if (!*ptr)
   {
     ...
   }
}

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

Пример[править | править код]

#include <stdlib.h>
#include <string.h>

static int x; /* 0 по умолчанию, существует всё время выполнения */
static int y=45; /* 45, существует всё время выполнения */

int cnt(void)
{
    static int i=0;/*статический тип, инициализируется нулём только при запуске 
        программы, а не каждый вызов функции */
    int j=-1;/*автоматический тип, инициализируется каждый раз 
                при вызове функции -1*/    
    i++;/* увеличивается на 1 в статической области памяти каждый запуск функции*/
    j++;/* увеличивается на 1 локальная переменная */
    return (i+j);/*при первом вызове с запуска программы функция вернёт 1, 
        при втором вызове 2, ... */
}

int main (void)
{
	char arr[50] = "This is object of automatic storage duration";
	/* имеет автоматический тип,существует до выхода из main,
	начальные 45 элементов массива инициализированы элементами 
	строки с закрывающим нулём, остальные не определены */
    char *line = "Simple line"; /*автоматический тип, существует до выхода 
    из main, line инициализирован указателем на константу */
    
	int y; /* значение не определено, существует до выхода из main*/
	int z=10; /* значение определено, существует до выхода из main*/
	char *ptr; /* значение указателя не определено */
	ptr = malloc (50); /* значение по указателю не определено, 
	                объект по указателю существует до вызова free */
	strcpy (ptr, arr);
	free (ptr);
	return 0;
}

Примечания[править | править код]

  1. 1 2 3 4 5 ISO/IEC 9899:1999. 6.2.4. Дата обращения: 5 августа 2011. Архивировано 15 августа 2011 года.
  2. ISO/IEC 9899:1999 7.20.3. Дата обращения: 5 августа 2011. Архивировано 15 августа 2011 года.
  3. C Faq. Дата обращения: 8 августа 2011. Архивировано 11 августа 2011 года.