Глиф Учебники

Урок 2. Переменные, типы, printf и scanf

Курс «C» · урок 2 из 10 · 4 минуты чтения

Переменная — это место в памяти, у которого есть имя и тип. Тип говорит, что в переменной хранится: целое число, дробное число или символ. В C тип указывается заранее и потом не меняется.

C
#include <stdio.h>

int main(void) {
    int age = 15;
    double height = 1.72;
    char grade = 'A';
    printf("Возраст: %d\n", age);
    printf("Рост: %f\n", height);
    printf("Оценка: %c\n", grade);
    age = age + 1;
    printf("Через год: %d\n", age);
    return 0;
}
Вывод
Возраст: 15
Рост: 1.720000
Оценка: A
Через год: 16

Запись int age = 15; объявляет переменную (тип int, имя age) и сразу кладёт в неё значение. Знак = в C означает не равенство, а присваивание: «положить в переменную слева значение справа». Поэтому age = age + 1 читается как «взять age, прибавить 1 и положить обратно».

age int · 4 байта height double · 8 байт grade char · 1 байт 15 1.72 'A' память — ряд байтов, клетка — 1 байт age = age + 1; age 15 16 в те же 4 байта записано 16, старое значение 15 стёрто
Каждая переменная занимает в памяти столько байт, сколько требует её тип: int — 4, double — 8, char — 1; после age = age + 1 в те же байты записывается 16, а прежнее 15 стирается.

Имена переменных

Основные типы

ТипЧто хранитРазмер на обычном компьютереprintfscanf
intцелые от −2 147 483 648 до 2 147 483 6474 байта%d%d
long longцелые примерно до ±9,2·10¹⁸8 байт%lld%lld
doubleдробные, 15–16 значащих цифр8 байт%f%lf
floatдробные, около 7 значащих цифр4 байта%f%f
charодин символ (точнее, маленькое целое число)1 байт%c%c

Стандарт C не называет точные размеры типов, он задаёт только наименьшие. Но на всех распространённых компьютерах размеры именно такие. Узнать размер можно оператором sizeof; его результат выводится форматом %zu.

Для дробных чисел берите double: у float мало точности, он нужен там, где важна память. Дробная часть отделяется точкой: 3.14, а не 3,14 — и в программе, и при вводе.

Если число не помещается в int (например, произведение двух чисел около миллиона), берите long long. Что бывает при переполнении — в справке Переполнение int.

Переменная внутри функции без начального значения содержит случайный мусор, а не ноль. Чтение такой переменной — ошибка: программа может выдавать разные ответы при каждом запуске. Ключ -Wall предупреждает об этом сообщением is used uninitialized.

Арифметика

C
#include <stdio.h>

int main(void) {
    int a = 17, b = 5;
    printf("%d + %d = %d\n", a, b, a + b);
    printf("%d - %d = %d\n", a, b, a - b);
    printf("%d * %d = %d\n", a, b, a * b);
    printf("%d / %d = %d\n", a, b, a / b);
    printf("%d %% %d = %d\n", a, b, a % b);
    printf("17.0 / 5 = %f\n", 17.0 / 5);
    printf("(double)a / b = %.2f\n", (double)a / b);
    return 0;
}
Вывод
17 + 5 = 22
17 - 5 = 12
17 * 5 = 85
17 / 5 = 3
17 % 5 = 2
17.0 / 5 = 3.400000
(double)a / b = 3.40

Главное здесь — деление целых: 17 / 5 даёт 3, дробная часть отбрасывается. Остаток от деления даёт оператор %: 17 % 5 равно 2. Чтобы получить 3.4, хотя бы одно число должно быть дробным: 17.0 / 5 или (double)a / b. Запись (double)a называется приведением типа: значение a превращается в double. Подробнее — в справке Почему 5 / 2 равно 2.

int a = 17, b = 5; 17 = 3 · 5 + 2 17 / 5 = 3 три полные группы по 5 17 % 5 = 2 остаток 17.0 / 5 = 3.4 (double)a / b = 3.4 дробное число — дробный ответ
Из 17 выходят три полные группы по 5 — это 17 / 5 = 3, и ещё 2 остаются — это 17 % 5 = 2; дробный ответ 3.4 получается, только если одно из чисел дробное: 17.0 / 5 или (double)a / b.

Чтобы вывести сам знак процента, в printf пишут %%.

Сокращённые записи: x += 5 — то же, что x = x + 5 (так же -=, *=, /=, %=); x++ увеличивает x на 1, x-- уменьшает на 1.

Дробное число, записанное в переменную типа int, теряет дробную часть без округления: после int n = 3.99; в n будет 3.

Вывод: printf

Первый аргумент printf — строка формата. Обычный текст выводится как есть, а на место каждого спецификатора (%d, %f…) подставляется следующий аргумент по порядку. Число и типы аргументов должны совпадать со спецификаторами — иначе выводится мусор, а -Wall предупреждает. Подробнее — в справке warning: format specifies type.

C
#include <stdio.h>

int main(void) {
    double price = 12.5;
    int count = 3;
    char currency = 'P';
    printf("%d шт. по %.2f = %.2f\n", count, price, count * price);
    printf("[%5d]\n", count);
    printf("[%-5d]\n", count);
    printf("[%8.3f]\n", price);
    printf("Символ %c, его код %d\n", currency, currency);
    printf("int занимает %zu байта\n", sizeof(int));
    return 0;
}
Вывод
3 шт. по 12.50 = 37.50
[    3]
[3    ]
[  12.500]
Символ P, его код 80
int занимает 4 байта
printf("%d шт. по %.2f = %.2f\n", count, price, count * price); 1 2 3 1 2 3 строка формата аргументы по порядку вывод 3 шт. по 12.50 = 37.50 1 2 3 %d — целое число %.2f — дробное, 2 знака после точки
Спецификаторы строки формата получают аргументы по порядку: первый %d — count, второй — price, третий — count * price, и на их местах в выводе стоят 3, 12.50 и 37.50.

Ввод: scanf

scanf читает данные с клавиатуры по такой же строке формата:

C
#include <stdio.h>

int main(void) {
    int a, b;
    double r;
    scanf("%d %d", &a, &b);
    scanf("%lf", &r);
    printf("Сумма: %d\n", a + b);
    printf("Среднее: %.1f\n", (a + b) / 2.0);
    printf("Площадь круга: %.3f\n", 3.14159265358979 * r * r);
    return 0;
}
Ввод
7 4
2.5
Вывод
Сумма: 11
Среднее: 5.5
Площадь круга: 19.635

Что важно знать про scanf:

В олимпиадных задачах и автоматических проверках не выводите подсказки вроде «Введите число:» — ответ сверяется с образцом до символа, и лишний текст делает его неверным. В учебных программах для себя подсказки, наоборот, удобны.

Константы

Значение, которое не должно меняться, объявляют с const: const double PI = 3.14159265358979;. Попытка присвоить такой переменной новое значение — ошибка сборки. Ещё один старый способ — #define PI 3.14159265358979 в начале файла: перед сборкой каждое PI в тексте заменяется числом.

Коротко

Проверьте себя

1. Что выведет printf("%d\n", 7 / 2);?
2. Какой формат нужен, чтобы прочитать double через scanf?
3. Почему в scanf("%d", &n) перед n стоит &?
4. Что выведет программа?
C
#include <stdio.h>

int main(void) {
    int x = 10;
    x += 5;
    x = x % 4;
    printf("%d\n", x);
    return 0;
}