С: переменные

Переменные бывают локальные (в пределах функции) и глобальные. Глобальные определяются до функции main вне остальных функций. 

 Переменные можно просто объявлять и дополнительно инициализировать начальное значение. Размеры типов зависят от платформы и компилятора! Вывод размера: 

 sizeof(имя_типа); 

 Квалификаторы типов (модификаторы) 

 Они не создают новые типы, но изменяют их свойства. const    Значение нельзя изменить    const int x = 5; volatile    Значение может измениться внешне (прерывания, hardware)    volatile int status; restrict    Указатель — единственный способ доступа к данным (для оптимизации)    int *restrict ptr; signed    Тип со знаком (по умолчанию для char не определено)    signed char c; unsigned    Тип без знака (только положительные числа)    unsigned int u; 

 Псевдонимы типов (typedef) 

 Позволяет дать новое имя существующему типу.  

 typedef int my_int;           // my_int — это псевдоним для int

typedef unsigned long ulong;  // ulong — псевдоним для unsigned long

my_int x = 10;                // То же, что int x = 10;

ulong y = 100;                // То же, что unsigned long y = 100; 

 Часто используется для упрощения сложных типов:  

 typedef struct {

   char name[50];

   int age;

} Person;                    // Теперь можно писать Person p; вместо struct Person p; 

 Базовые типы: 

 

 

 

 void 

 Нет значений    Означает "отсутствие типа" 

 Нет размера 

 

 

 

 integer (int) 

 

 Целые числа, -2,147,483,648 … 2,147,483,647 

   

 Зависит от разрядности ОС! 

 

 4 

 

 int var;

int var=7; 

 

 

 

 unsigned int 

 Беззнаковое целое 0 … 4,294,967,295 

 4 

 

 

 

 short 

 Числа со знаком -32,768 … 32,767 

 2 

 

 

 

 unsigned short 

 Беззнаковое короткое целое 0 … 65,535 

 2 

 

 

 

 long 

 

 4 или 8    Зависит от платформы 

 

 

 

 unsigned long 

 

 

 

 

 

 long long 

 Очень длинное целое 

 8 байт 

 

 

 

 unsigned long long 

 

 8 

 

 

 

 float 

 Дробные с точностью до 7 знака 

 4 

 

 float var_float = 12.45; 

 

 

 

 double 

 Дробные с точностью 15 знаков 

 8 

 

 

 

 long double 

 

 10, 12 или 16   Зависит от платформы 

 

 

 

 bool 

 Логическое 

 

 

 bool vr = true; 

 

 

 

 char 

 

 Символ 

   

 Желательно указывать явно signed / unsigned 

 

 1 

 

 char n = 'g'; 

 

 

 

 unsigned char 

 Беззнаковый символ 0 … 255 

 1 

 

 

 

 

 Массивы 

 Хранят несколько элементов одного типа подряд в памяти. Из базовых.  

 int numbers[10]; // Массив из 10 целых чисел

char name[50]; // Массив из 50 символов

double matrix[3][3]; // Двумерный массив (матрица 3x3) 

 Указатели (pointer) 

 Хранят адрес в памяти, где находится значение. Для обращения по адресам необходимы: 

 

 Возможность находить адрес, по которому в памяти располагается та или иная переменная; 

 Место, где этот адрес можно было бы сохранить для дальнейшей работы;  

 Возможность обращаться к ячейке памяти по ее адресу.  

 

 Операция получения адреса переменной & (амперсанд). Хранятся адреса переменных тоже в переменных, в специальном типе,   переменные указатели.  Количество указательных типов, равно количеству типов данных.  Объявление  переменной-указателя  

 int *ptr, i; // Указатель на int и обычный int

char *str; // Указатель на char (строка)

void *generic; // Универсальный указатель (на любой тип) 

 Для изменения / получения данных из адреса оператор разыменовывания * но в операциях с переменной:  

 char i = 0, *p; 

p = &i;

*p = 2; 

i = i + 2; 

printf("%d %d", *p, i); 

 Но если попытаться напрямую изменить адрес, например p=p+2; то будет ошибка (такого адреса нет).  

 В ячейке памяти хранится адрес первой ячейки памяти. Тип переменной указывается для понимания, сколько байт нужно считывать. 

 

 Перечисления (enum) 

 Определяют набор именованных целочисленных констант.  

 enum Color {

 RED, // 0

 GREEN, // 1

 BLUE // 2

};

enum Color favorite = GREEN; 

 Структуры  

 Объединяют разные типы в один.  

 struct Person {

 char name[50];

 int age;

 float height;

};

struct Person person1; 

 Объединения (union) 

 Как структура, но все поля используют одну и ту же область памяти (экономят память). 

 union Data {

   int i;

   float f;

   char str[20];

};

union Data data;           // data.i, data.f, data.str занимают одну память 

 Преобразование типов. 

 Бывают явные (делает программист) и неявные (компилятор). Неявные делятся на: 

 

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

 При  вычислении выражения операнды каждой операции преобразуются к какому-то одному типу (если они различаются), при этом результат операции будет того же типа. Правило «меньший» тип к «большему», для минимизации потерю информации. Операции преобразования сначала выполняются от самого глубокого до внешнего, одного приоритета слева направо. 

 

 float c = 5/6; 

 5 и 6 - целочисленные, поэтому результат целочисленный. И равен 0. Только после этого он преобразуется в float, но уже поздно. В с будет 0. А если сделать один операнд с плавающей точкой - второй преобразуется во float и дробная часть не потеряется.  

 float c = 5.0/6; 

 Пример приоретизации операций:  

 2 / 4 * 3,14 

// результат 0, так как одноуровневые операции слева направо 

 Явное преобразование:  

 double result = (double)a / b;