Введение |
Массивы, строки и структуры |
Операторы |
Операции |
Пояснения к курсовой работе |
Препроцессор |
Работа с файлами |
Стандарты безопасного кодирования |
Указатели и динамическая память |
Функции и модули |
Ввод-вывод |
Переменная в С соответствует некоторой ячейке в памяти или регистру процессора и хранит обрабатываемые данные. Перед использованием переменная должна определена или объявлена, т.е. программист должен сообщить компилятору тип переменной и её имя, чтобы компилятор назначил адрес и размер памяти для хранения переменной с указанным именем. Кроме типа программист определяет вид используемой памяти, ограничения на изменение, область видимости и время жизни переменной.
Общий вид оператора определения:
спецификаторы
Пример:
int a, b;
Здесь определяются две переменные целого типа с именами a и b. При определении переменной можно указать начальное значение для неё после имени: "имя"="выражение". Пример:
int one=1, prime=1000000009;
Спецификатор const
указывает, что значение переменной после определения нельзя изменить:
const double pi=3.141592653589793;
Данные для программы могут размещаться в регистровой, статической, стековой и динамической памяти. Отличия между этими видами памяти состоит в способе адресации и времени жизни данных.
Виды памяти
Вид памяти | регистровая | статическая | стековая | динамическая |
---|---|---|---|---|
Ограничения | 4-32 значения | ограничена размером памяти компьютера | несколько мегабайт, можно изменить умолчание опциями при компиляции или компоновке | ограничена размером памяти компьютера |
Адресация | прямая: номер регистра определяется компилятором | абсолютная: адрес ячейки определяется на этапе компоновки и/или загрузки программы в память | относительная: адрес ячейки вычисляется добавлением значения регистра SP к смещению, определяемому на этапе компиляции | косвенная: память распределяется во время выполнения, адрес хранится в ячейках памяти других видов |
Время жизни | время нахождения данных в регистре определяется компилятором, при необходимости для данных используется стековая память | в течении всего времени выполнения программы | на время выполнения функции или блока операторов | определяется программно |
Определение | внутри функции с помощью спецификатора register |
вне функций или внутри функции с помощью спецификатора static |
внутри функции или блока | создание с помощью вызова функций malloc/calloc , уничтожение - free |
Регистры
В Си с помощью спецификатора register
можно указать, что некоторую часто используемую переменную следует разместить в регистре. Но данный описатель способа хранения можно считать устаревшим, так как, во-первых, оптимизирующие компиляторы эффективно используют регистры и могут размещать переменную в регистре только на время ее частого использования, а во-вторых, в современных процессорах реализовано многоуровневое кэширование, существенно уменьшающее время обращения к памяти.
Стек
Стек (stack - стопка) - это область памяти, в которую добавление и удаление данных происходит с одной стороны. При входе в некоторый блок программы данные добавляются в стек, при выходе из блока - удаляются. Данные, размещаемые в стеке, должны иметь фиксированный размер, так как смещение относительного адреса является константой и вычисляется во время компиляции.
Куча
Куча позволяет во время исполнения программы создавать и уничтожать данные произвольного размера в произвольном порядке. Для повторного использования освобожденной памяти поддерживается список свободных областей памяти, в котором при выделении памяти происходит поиск подходящей по размерам области, а если такой области не будет найдено, запрашивается новая область памяти у операционной системы. Количество действий для этого достаточно велико, поэтому выделение и освобождение памяти из кучи являются медленными операциями.
Переменную можно использовать в её области видимости - от точки определения до конца блока или файла. Блок операторов в {}
может содержать определение переменной с тем же именем, тогда новая переменная временно скрывает переменную, объявленную уровнем выше (см. пример).
Листинг 1 - Пример программы с использованием разных видов памяти
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);
}
Рисунок 1 - Размещение переменных в памяти при выполнении программы
В скобках на рисунке указан адрес или регистр для переменной. Переменные a
и b
будут доступны в других модулях, видимость переменной c
ограничена текущим модулем с помощью спецификатора static
. Все статические переменные (a, b, c, f
) существуют до начала выполнения программы, в том числе переменная f
, определенная внутри функции (рисунок 1а). Если для статической переменной не указано начальное значение (b
в примере), то она инициализируется нулем. Не инициализированные переменные в других видах памяти (d
в примере) имеют неопределенное начальное значение (рисунок 1б). В строках 7-9 определяются переменные a
и e
(рисунок 1в), которые временно скрывают одноименные переменные и удаляются из стека при выходе из блока (рисунок 1г). Переменная h
размещается на стеке и содержит адрес ячейки памяти в куче (рисунок 1д).