Переменная в С соответствует некоторой ячейке в памяти или регистру процессора и хранит обрабатываемые данные.
Перед использованием переменная должна определена или объявлена, т.е. программист должен сообщить компилятору тип переменной и её имя, чтобы компилятор назначил адрес и размер памяти для хранения переменной с указанным именем. Кроме типа программист определяет вид используемой памяти, область видимости и время жизни переменной.
Здесь определяются две переменные целого типа с именами `a` и `b`. При определении переменной можно указать начальное значение для неё после имени: `"имя"="выражение"`. Пример:
``int one=1, prime=1000000009;``
Данные для программы могут размещаться в регистровой, статической, стековой и динамической памяти. Отличия между этими видами памяти состоит в способе адресации и времени жизни данных.
**Виды памяти**
||.draw|| Вид памяти|регистровая|статическая|стековая|динамическая
----------|-----------|-----------|--------|------------
Ограничения|4-32 значения|ограничена размером памяти компьютера|несколько мегабайт, можно изменить умолчание опциями при компиляции или компоновке|ограничена размером памяти компьютера
Адресация|прямая: номер регистра определяется компилятором|абсолютная: адрес ячейки определяется на этапе компоновки и/или загрузки программы в память|относительная: адрес ячейки вычисляется добавлением значения регистра SP к смещению, определяемому на этапе компиляции|косвенная: память распределяется во время выполнения, адрес хранится в ячейках памяти других видов
Время жизни|время нахождения данных в регистре определяется компилятором, при необходимости для данных используется стековая память|в течении всего времени выполнения программы|на время выполнения функции или блока операторов|определяется программно
Определение|внутри функции с помощью спецификатора ``register``|вне функций или внутри функции с помощью спецификатора ``static``|внутри функции или блока|создание с помощью вызова функций ``malloc/calloc``, уничтожение - ``free``
**Регистры**
В Си с помощью спецификатора ``register`` можно указать, что некоторую часто используемую переменную следует разместить в регистре. Но данный описатель способа хранения можно считать устаревшим, так как, во-первых, оптимизирующие компиляторы эффективно используют регистры и могут размещать переменную в регистре только на время ее частого использования, а во-вторых, в современных процессорах реализовано многоуровневое кэширование, существенно уменьшающее время обращения к памяти.
**Стек**
Стек (stack - стопка) - это область памяти, в которую добавление и удаление данных происходит с одной стороны. При входе в некоторый блок программы данные добавляются в стек, при выходе из блока - удаляются. Данные, размещаемые в стеке, должны иметь фиксированный размер, так как смещение относительного адреса является константой и вычисляется во время компиляции.
**Куча**
Куча позволяет во время исполнения программы создавать и уничтожать данные произвольного размера в произвольном порядке. Для повторного использования освобожденной памяти поддерживается список свободных областей памяти, в котором при выделении памяти происходит поиск подходящей по размерам области, а если такой области не будет найдено, запрашивается новая область памяти у операционной системы. Количество действий для этого достаточно велико, поэтому выделение и освобождение памяти из кучи являются медленными операциями.
Переменную можно использовать в её *области видимости* - от точки определения до конца блока или файла. Блок операторов в ``{}`` может содержать определение переменной с тем же именем, тогда новая переменная временно *скрывает* переменную, объявленную уровнем выше (см. пример).
*Листинг 1* - Пример программы с использованием разных видов памяти
```c #
int a=1, b;
static int c=2;
int main()
{ int d, e=3;
static int f=4;
register int g=5;
{
int a=6, e=7;
}
int *h=malloc(sizeof(int));
*h=6;
free(h);
}
```
![Размещение переменных в памяти](43188.png)
*Рисунок 1* - Размещение переменных в памяти при выполнении программы
В скобках на рисунке указан адрес или регистр для переменной. Переменные ``a`` и ``b`` будут доступны в других модулях, видимость переменной ``c`` ограничена текущим модулем с помощью спецификатора ``static``. Все статические переменные (``a, b, c, f``) существуют до начала выполнения программы, в том числе переменная ``f``, определенная внутри функции (рисунок 1а). Если для статической переменной не указано начальное значение (``b`` в примере), то она инициализируется нулем. Не инициализированные переменные в других видах памяти (``d`` в примере) имеют неопределенное начальное значение (рисунок 1б). В строках 7-9 определяются переменные ``a`` и ``e`` (рисунок 1в), которые временно скрывают одноименные переменные и удаляются из стека при выходе из блока (рисунок 1г). Переменная ``h`` размещается на стеке и содержит адрес ячейки памяти в куче (рисунок 1д).