- •1 Переменные
- •1.1 Базовые типы данных
- •1.1.1 Целочисленные типы
- •1.1.2 Способы записи целых чисел
- •1.1.3 Логический тип
- •1.1.4 Вещественные типы
- •1.1.5 Специальный тип void
- •1.2 Оператор sizeof
- •1.3 Константы
- •1.4 Определение и описание переменных
- •1.5 Классы памяти переменных
- •2 Функции
- •2.1 Объявления и определения функций
- •2.2 Функция main
- •3.1 Разыменование указателя и получение адреса
- •3.1.1 Операции разыменования указателя и получение адреса переменной
- •3.1.2 Инициализация и присваивание указателей
- •3.1.3 Указатели и область действия (время существования) переменных
- •4 Массивы
- •4.1 Основные сведения
- •4.2 Указатель на первый элемент массива
- •4.3 Работа с указателями как с массивами
- •4.4 Арифметика указателей
- •4.5 Разноразмерные массивы
- •5 Структуры
- •6 Логические операции
- •7 Условия
- •8 Операторы сравнения
- •9 Сдвиги
- •10 Циклы
- •10.1 Цикл с предусловием
- •10.2 Цикл с постусловием
- •10.3 Цикл со счётчиком
- •11 Оптимизация и её запрет, ключевое слово volatile
- •12.1.2 Директива #include
- •12.2 Условная компиляция
Листинг 1. Пример определения переменных различных типов.
unsigned int a = 5; // Целочисленная (беззнаковая) переменная
short b = -16384; // Короткое целое, эквивалентно short int b = -16384;
//Не проинициализированная переменная (начальное значение не указано) //(значение в общем случае может быть любым)
unsigned char byteValue;
float temperature = 36.6; //Вещественная переменная (одинарной точности)
const unsigned channel = 4; // Целочисленная беззнаковая константа
1.2Оператор sizeof
Как можно заметить, разные типы данных в общем случае занимают разный размер в памяти. Для автоматического определения этого размера «с помощью» компилятора в языке Си определён оператор sizeof, который применяется как к типам, так и к самим переменным этих типов и позволяет узнать размер, который они занимают в памяти (в байтах). Пример его использования приведён в листингах 2 и 8.
Листинг 2. Пример использования оператора sizeof.
// Переменная, |
проинициализированная |
числом, равным объёму памяти, |
|
который занимает переменная типа int |
|
|
|
const unsigned |
char integerSize = sizeof (int); |
// = 4 |
// Переменная, проинициализированная числом, равным объёму памяти, который занимает переменная integerSize
const unsigned int sizeOfByte = sizeof (integerSize); // = 1
1.3Константы
Вязыке Си зарезервировано ключевое слово const, позволяющее создать «переменную», значение которой невозможно изменить после её инициализации (т. е. константу). Инициализация (т. е. присвоение начального значения) константы должна производиться одновременно с созданием переменной, т. к. позже сделать это будет невозможно, а её значение может оказаться случайным. Так, в листинге 1 описана константа channel, равная 4. В
5
остальном, константы ведут себя так же, как переменные: могут использоваться в различных выражениях, передаваться в качестве аргументов функций.
Использование констант позволяет сделать исходный текст понятнее, защищает программиста от собственных ошибок (невозможно случайно изменить переменную, которая объявлена константой), а также помогает компилятору оптимизировать программный код. Кроме того, константы обычно размещаются в ПЗУ, что позволяет не держать их в ОЗУ.
1.4Определение и описание переменных
Одним из требований языка Си является наличие определения или описания переменной до её первого использования в исходном файле.
Определение переменной – это указание имени и типа переменной с
выделением памяти для её хранения.
Описание (объявление) переменной – указание имени и типа переменной, определённой где-то в другом месте. Описание переменной не выделяет память, а лишь сообщает компилятору о том, что где-то определена переменная с конкретным типом и именем.
Описания переменных обычно используются в случаях, когда необходимо сослаться на внешнюю переменную (см. п. 1.5), определённую ниже по тексту в текущем файле, либо вообще в другом исходном файле. Такие описания делаются с использованием ключевого слова extern.
1.5Классы памяти переменных
Взависимости от того, где (в каком месте программы: в функции, или вне неё) и как (с использованием каких ключевых слов) определена (или описана) переменная, она относится к одному из возможных классов памяти.
Классы памяти в Си – это понятие, определяющее как долго хранится переменная в памяти и откуда к ней можно обратиться (см. табл. 4).
В листинге 3 показан пример использования переменных, относящихся к различным классам памяти.
6
Таблица 4. Классы памяти переменных
Класс |
памяти |
Ключевое |
Место |
Описание |
переменной |
слово |
определения |
|
|
|
|
|
|
|
Автоматический |
<нет> |
внутри |
Локальные переменные. Видны только в этой |
|
|
|
|
функции |
функции. Уничтожаются при выходе из функции |
|
|
|
|
(т. е. не сохраняют значения между вызовами |
|
|
|
|
функции). |
Статический |
static |
внутри |
Локальные переменные. Видны только в этой |
|
|
|
|
функции |
функции. При выходе из функции не |
|
|
|
|
уничтожаются. Сохраняют свои значения между |
|
|
|
|
вызовами функции. |
|
|
static |
вне функций |
Глобальные переменные. Создаются до входа в |
|
|
|
|
функцию main (см. п. 2.2). Существуют всё |
|
|
|
|
время выполнения программы. Видны только в |
|
|
|
|
том файле, в котором определены. |
Внешний |
|
<нет> |
вне функций |
Глобальные переменные. Создаются до входа в |
|
|
|
|
функцию main (см. п. 2.2). Существуют всё |
|
|
|
|
время выполнения программы. Доступны в |
|
|
|
|
файле, в котором определены, ниже определения. |
|
|
|
|
Если необходимо сослаться на внешнюю |
|
|
|
|
переменную, определённую ниже по тексту в |
|
|
|
|
текущем файле, либо в другом файле, то |
|
|
|
|
необходимо сделать описание этой переменной с |
|
|
|
|
использованием ключевого слова extern. |
Листинг 3. Пример работы с переменными, относящимися к различным классам памяти
//Объявление глобальной переменной value (определение идёт ниже).
//Внешний класс памяти.
extern short value;
// Определение функции (подпрограммы) void func (void)
{
//Объявление целочисленной переменной с
//одновременной инициализацией нулём. Автоматический класс памяти. int i = 0;
//Переменная статического класса памяти. Начальное значение = 3. static short staticValue = 3;
//Инкремент. Каждый новый вызов функции func()
//Будет приводить к увеличению значения переменной. ++staticValue;
//Здесь значения staticValue при каждом вызове func() будут равны:
7
//4, 5, 6, ... и т.д.
//Присваивание глобальной переменной нового значения value = 5;
//Присваивание нового значения локальной переменной i = value;
//Инкремент
++i;
// Здесь i всегда будет равно 6
}
//Определение глобальной переменной value. Внешний класс памяти. short value = 10;
//Выполнение программы начинается с функции main
int main (void)
{
// <-- |
Здесь |
значение value пока равно 10 |
|||
func(); |
// вызов функции (подпрограммы) |
||||
// <-- |
Здесь |
value уже равно 5 |
|||
func(); |
// |
вызов функции |
(подпрограммы) |
||
func(); |
// |
вызов функции |
(подпрограммы) |
//<-- Отсюда невозможно напрямую обратиться
//к переменной staticValue, определённой внутри функции
//func(), тем не менее эта переменная существует и её
//значение в данной точке выполнения равно 6
}
8