Перейти к основному содержимому

Типы данных языка Си

Переменные

Чтобы прочитать данные из памяти или записать даные в память необходимо знать адреса ячеек с которыми будут осуществляться действия. Так как различных данных у программ, включая промежуточные значения вычислений, огромное количество, то запомнить адреса ячеек практически не возможно. Поэтому для работы с данными используются переменные.

Переменная - это ячейка в памяти, которая имеет имя, адрес в памяти и значение. Значение может меняться в процессе выполнения программы путем записи нового значения вместо старого.

Имена переменных могут начинаться с латинской буквы или символа подчеркивания и могут содержать только латинские буквы, цифры или символ подчеркивания.

Типы данных

Язык программирования Си является строго типизированным. А это значит, что при объявлении переменной необходимо объявить ее тип, под который будет выделено нужное количество памяти и который будет неизменным все время работы программы. Типы данных различаются диапазонами возможных значений и требуют для хранения разное количество байт. Это следует учитывать при разработке приложений, особенно при написании программ для контроллеров, которые обладают ограниченными размерами памяти. В таблице ниже перечислены все типы языка Си.

Название типаРазмер памятиДиапазон значенийПсевдонимы
char1 байт1 символ
unsigned char1 байтот 0 до 255
signed char1 байтот -128 до 127
short2 байтаот 32768 до 32767short int, signed short, signed short int
unsigned short2 байтаот 0 до 65535unsigned short int
int2 или 4 байтаот 32768 до 32767 (при 2 байтах) или от 2 147 483 648 до 2 147 483 647 (при 4 байтах)signed int
unsigned int2 или 4 байтаот 0 до 65535 (для 2 байт) или от 0 до 4 294 967 295 (для 4 байт)unsigned
long4 или 8 байтот -2 147 483 648 до 2 147 483 647 (4 байта), либо -9223372036854775807 до +9 223 372 036 854 775 807 (8 байт)long int, signed long int, signed long
unsigned long4 или 8 байтот 0 до 4 294 967 295 (4 байта) или от 0 до 18 446 744 073 709 551 615 (8 байт)unsigned long int
long long8 байтот -9223372036854775807 до +9223372036854775807long long int, signed long long int, signed long long
unsigned long long8 байтот 0 до 18446744073709551615unsigned long, long int
float4 байтаот +/- 3.4E-38 до 3.4E+38
double8 байтот +/- 1.7E-308 до 1.7E+308.
long double10 байт (80 бит), 96 бит или 128 битот +/- 3.4E-4932 до 1.1E+4932
voidтип без значения

Примеры объявления переменных:

int main()
{
int a;
unsigned int a;
float f;
int su, prime = 7; five = 5;
char c, c2 = 'A', m=10;
}
Внимание !

Если не задано начальное значение переменной, то в ней хранится "мусор", оставшийся от предыдущего использования ячеек памяти.

Суффиксы

В языке Си любое десятичное число по умолчанию считается либо int/long либо int/long long int. Когда происходит присваивание числа переменной, тип которой отличается от этих типов происходит преобразование числа в тип указанный у переменной. Что бы избежать этого преобразования можно явно указать к какому типу принадлежит число. Для этого используются суффиксы.

ТипСуффикс
unsigned int, unsigned long int и unsigned long long intu или U
unsigned long int и unsigned long long intul или UL
long long intll или LL
unsigned long long intull или ULL

Пример объявления переменной с суффиксом:

unsigned number = 123456789u;

Спецификаторы классов памяти и квалификатор const

  • const Значение не будет меняться после инициализации. Пример: const unsigned int a = 123; При попытке изменить переменную произойдет ошибка компиляции.
  • static Место под переменную будет выделено в статической памяти, поэтому доступ к ней возможен во время всего времени работы программы. Инициализация выполняется до начала выполнения программы.
  • extern Глобальная переменная объявляется и инициализируется в другом файле. Доступ к переменной возможен во время всего выполнения программы.

Оператор присваивания и побочный эффект

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

prog (a,a=k*2);

Примеры побочных эффектов в выражениях:

int main(void)
{
int a, b, x=5, y, z;
a = 5; //положить целое число 5 в переменную a
x = x + 20; // x=25 побочный эффект
y = (x - 15) * (x + a); // y=300
z = y = a+1; // y=6 z=6 побочный эффект
}

Арифметические операции над целочисленными значениями

  • сложение "+"
  • вычитание "–"
  • умножение "*"
  • деление нацело "/"
  • остаток от деления нацело "%"
Важно !

При делении нацело результат всегда округляется в сторону нуля и выполняется равенство (a/b)*b + a%b = a, поэтому знак остатка совпадает со знаком делимого.

Явное приведение типов

Для явного приведения типов имя типа указывается в круглых скобках перед переменной или выражением:

int X;
int Y = 200;
char C = 255;
X = (unsigned char)C * 10 + Y;

Чтобы избежать неоднозначностей, рекомендуется явно указывать знаковость для типа char -1 или 255 иначе переменная С приводится к типу int.

Неявное приведение типов

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

  1. Если один из типов операндов – вещественный, то второй операнд тоже приводится к вещественному типу.
  2. Если есть операнд целого типа короче, чем int и все значения этого типа могут быть представлены как int, то он преобразуется к int; иначе - к unsigned int.
  3. Для операндов целых типов неявное приведение типов управляется целочисленным рангом приведения типа.

Примеры правила 1:

float f;
f = 3/2; //целочисленное деление f=1.0
f = 3./2; //вещественное деление f=1.5
int a = 7;
float x;
x = a / 4; // 1
x = 4 / a; // 0
x = (float)a / 4; // 1.75
x = 1.*a / 4; // 1.75

Примеры правила 2:

short  i, x=5,y=-2;
i = x + y;

переменные x и y сначала расширяются до типа int, выполняется сложение, а затем результат помещается в i

Примеры правила 3:

unsigned int u = 50;
int i = -500;
int answer = i / u; // answer = 85899335.

i будет приведен к беззнаковому типу и его значение будет равно 232-500 вместо -500, а результат деления будет приведен обратно к знаковому типу int

Унарные операции

Унарные операции также являются операциями с побочным эффектом.

  • Инкремент “++” - увеличение операнда на единицу
  • Декремент “--” - уменьшение операнда на единицу

Есть две формы унарных операций - постфиксная и префиксная. В первом случае сначала происходит присваивание значения а потом унарная операция, во втором случае сначала инкремент или декремент, а потом присваивание:

Постфиксная форма:

int a, b=7;
a = b++; // a=7 b=8

Префиксная форма:

int a, b=7;
a = ++b; // a=8 b=8

Точка следования

Точкой следования (sequence point), называется место в программе, в котором все побочные эффекты предыдущих вычислений закончены, а новые – не начаты. Точками следования в программе являются:

  • конец полного выражения
  • при выполнении операции x , y – между вычислением x и y;
  • при выполнении операции z ? x : y – между вычислением z и вычислением x либо y; (рассмотрим это позднее)
  • при вызове функции – перед выполнением ее тела и после вычисления ее аргументов;
  • при выполнении операций x && y и x || y – между вычислением x и вычислением y.

Пример точки следования:

int a, b, c;
a = (a + b) * (c + 3); // после вычисления всего выражения.
Антипример:
int a, b = 10, c;
a = b++ + ++b; // ТАК НЕЛЬЗЯ !!! Дважды модифицируется одна переменная !!!}
a = (c = 3) + (c = 3); // ТАК НЕЛЬЗЯ !!! Дважды модифицируется одна переменная !!!

Самостоятельная работа

Вопросы для самопроверки

Какие имена переменных верные?

  1. ABCdf
  2. h&m
  3. 4you
  4. Иван
  5. “GeekBrains”
  6. super173
  7. [goodname]
  8. _my_string
  9. a*b

Задачи

Целой переменной k присвоить значение, равное сумме цифр в записи целого положительного трехзначного числа x.

Решение
int main(void)
{
int n=123;
int sum;
sum = n%10; //sum = 3
sum += (n/10)%10; //sum = 5
sum += (n/100)%10; //sum = 6
}