Типы данных, переменные, printf и scanf

⏱ 25 мин · 🧩 заданий: 6

Переменные

Переменная — именованная область памяти определённого типа. Тип определяет размер области и то, как интерпретировать её биты.

int counter = 0;        /* объявление с инициализацией */
double sum;             /* без инициализации: внутри функции значение — мусор! */
char letter = 'A';      /* символ — это маленькое целое число (код 65) */

Неинициализированные переменные

Локальная переменная без начального значения содержит то, что лежало в памяти до неё. Глобальные и static переменные, наоборот, всегда обнуляются.

Целые типы

Тип Типичный размер (x86-64 Linux) Диапазон
char 1 байт −128…127 (или 0…255)
short 2 байта −32 768…32 767
int 4 байта ≈ −2,1·10⁹…2,1·10⁹
long 8 байт (на 32-битных — 4) ≈ ±9,2·10¹⁸
long long 8 байт ≈ ±9,2·10¹⁸

Модификатор unsigned делает тип беззнаковым: unsigned int хранит 0…4 294 967 295.

Стандарт C гарантирует только минимальные размеры, поэтому точный размер узнают оператором sizeof:

printf("%zu %zu %zu\n", sizeof(int), sizeof(long), sizeof(double));  /* 4 8 8 */

Если нужен точный размер — типы из <stdint.h>: int32_t, uint64_t, uint8_t.

Вещественные типы

Тип Размер Точность
float 4 байта ~7 значащих цифр
double 8 байт ~15–16 цифр
double x = 0.1 + 0.2;
printf("%.17f\n", x);   /* 0.30000000000000004 — двоичная дробь неточна */

Переполнение и деление

unsigned int u = 0;
u = u - 1;              /* 4294967295: беззнаковые «заворачиваются» по модулю 2^32 */

int a = 7 / 2;          /* 3: целочисленное деление */
int r = 7 % 2;          /* 1: остаток */
double d = 7.0 / 2;     /* 3.5 */
double e = (double)7 / 2;  /* 3.5: явное приведение типа */

Знаковое переполнение

INT_MAX + 1 — неопределённое поведение (undefined behavior): компилятор вправе считать, что этого не бывает, и оптимизировать код неожиданным образом.

Системные типы

В системном программировании вы постоянно будете встречать типы-«псевдонимы»:

Тип Где используется На Linux обычно
size_t размеры (sizeof, malloc, strlen) unsigned long
ssize_t результат read/write (может быть −1) long
pid_t идентификатор процесса (fork, getpid) int
off_t смещение в файле long
uid_t идентификатор пользователя unsigned int

Их фактический размер зависит от системы, поэтому при печати безопаснее явно привести: printf("%d", (int)pid) или printf("%ld", (long)pid).

printf: форматированный вывод

printf("%d: %d\n", ppid, pid);       /* строка из экзаменационной задачи */
printf("%5d|%-5d|\n", 42, 42);        /* "   42|42   |" — ширина и выравнивание */
printf("%.2f\n", 3.14159);            /* "3.14" */
printf("%x %o\n", 255, 8);            /* "ff 10" — шестнадцатеричный и восьмеричный */
printf("%s %c\n", "текст", 'A');
printf("%p\n", (void *)&counter);     /* адрес в памяти */
printf("100%%\n");                    /* знак процента */
Спецификатор Тип
%d, %i int
%u unsigned int
%ld, %lu long, unsigned long
%zu size_t
%f, %e, %g double (и float)
%c символ
%s строка (char *)
%p указатель
%x целое в hex

scanf: форматированный ввод

int n;
double x;
if (scanf("%d %lf", &n, &x) != 2) {     /* вернёт число успешно прочитанных значений */
    fprintf(stderr, "Ошибка ввода\n");
    return 1;
}

Обратите внимание на &: scanf должна записать значение в переменную, поэтому ей передаётся адрес переменной. Об адресах — в уроке про указатели. И ещё отличие: для double в scanf нужен %lf, а в printf хватает %f.

Стандартные потоки

У каждого процесса при запуске открыты три потока:

Поток Дескриптор Назначение
stdin 0 ввод
stdout 1 вывод (буферизуется)
stderr 2 ошибки (не буферизуется)

printf(...) — то же, что fprintf(stdout, ...).

Итог

  • Тип задаёт размер и смысл битов; размер узнаём через sizeof; double — 8 байт.
  • Беззнаковые типы заворачиваются по модулю, знаковое переполнение — неопределённое поведение.
  • Деление целых — целочисленное.
  • Системные типы size_t, pid_t, ssize_t печатаем с правильным форматом или приводим явно.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Один вариант ответа

Чему равно sizeof(double) на x86 и x86-64?

Задание 2 Ввод ответа

Сколько байт занимает массив double a[70]? Введите число.

Задание 3 Ввод ответа

Что напечатает фрагмент?

unsigned char c = 255;
c = c + 1;
printf("%d\n", c);
Задание 4 Ввод ответа

Что напечатает printf("%d\n", 7 / 2);?

Задание 5 Написать код

Напечатайте идентификатор процесса и его родителя одной строкой в формате pid=123 ppid=45. Значения уже лежат в переменных pid_t pid и pid_t ppid. Приведите их к int и используйте формат %d.

Задание 6 Заполнить таблицу

Сопоставьте спецификаторы printf и типы: отметьте «+», если спецификатор подходит для типа.

%d%u%ld%f%zu%p
int
unsigned int
long
double
size_t
void *
Отметьте ячейку — «+», пустая — «−».

Войдите, чтобы отмечать пройденные уроки.