Типы, printf и scanf в C

В этом уроке мы возьмем первые типы данных в C и сразу привяжем их к живому действию: пользователь вводит числа, программа считает результат и печатает его в терминал. Так проще понять, зачем вообще нужны int, double, char, %d, %lf и почему scanf нельзя писать наугад

Главная мысль урока: в C тип переменной и формат в printf или scanf должны совпадать. Если вы храните число как int, печатайте его через %d. Если читаете double, используйте %lf в scanf. Компилятор иногда предупредит, но часть ошибок проявится только странным выводом или неверным вводом

Что получится в конце

Мы сделаем файл types_demo.c, который спрашивает возраст, рост и первую букву имени, а потом печатает аккуратную строку с результатом

#include <stdio.h>

int main(void)
{
    int age = 0;
    double height = 0.0;
    char initial = '?';

    printf("Age: ");
    scanf("%d", &age);

    printf("Height in meters: ");
    scanf("%lf", &height);

    printf("First initial: ");
    scanf(" %c", &initial);

    printf("Initial: %c\n", initial);
    printf("Age: %d\n", age);
    printf("Height: %.2f m\n", height);

    return 0;
}

Сборка:

gcc -Wall -Wextra -std=c17 types_demo.c -o types_demo
./types_demo

Ожидаемый сценарий:

Age: 32
Height in meters: 1.82
First initial: D
Initial: D
Age: 32
Height: 1.82 m

Почему типы в C ощущаются строже

В C переменная создается с типом заранее. Строка int age = 0; говорит компилятору: здесь будет целое число. Строка double height = 0.0; говорит: здесь будет число с дробной частью. Строка char initial = '?'; хранит один символ

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

Полезная учебная таблица:

ТипЧто хранитПример значенияФормат в printfФормат в scanf
intцелое число42%d%d
doubleдробное число3.14%f%lf
charодин символ'A'%c%c
char[]строку как массив символов"C"%s%s

Самая заметная странность для новичка: для double в printf используется %f, а в scanf нужен %lf. Это нормальное различие между выводом и вводом, его лучше просто запомнить на первом этапе

printf: печатаем значения через формат

printf получает строку формата и значения, которые нужно подставить:

printf("Age: %d\n", age);
printf("Height: %.2f m\n", height);

%d означает место для целого числа. %.2f означает дробное число с двумя знаками после запятой. \n переводит вывод на новую строку

Если написать:

printf("Age: %f\n", age);

код становится неверным по смыслу: формат просит дробное число, а переменная хранит int. На современных компиляторах с -Wall -Wextra вы часто увидите предупреждение. Эти предупреждения не стоит игнорировать: в C они часто ловят настоящие ошибки до запуска

scanf: почему нужен амперсанд

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

scanf("%d", &age);

Символ & читается как «адрес переменной». Пока не нужно глубоко уходить в указатели, но важно понять механику: scanf должен знать, куда положить число

Для char в примере есть пробел перед %c:

scanf(" %c", &initial);

Этот пробел просит scanf пропустить пробельные символы, включая перевод строки, который остался после предыдущего ввода. Без пробела scanf("%c", &initial); может мгновенно прочитать не букву, а оставшийся \n

Проверяем результат по шагам

Сначала соберите программу:

gcc -Wall -Wextra -std=c17 types_demo.c -o types_demo

Если компилятор молчит, это хороший знак. Запустите:

./types_demo

Введите обычные значения. Затем специально проверьте ошибочный сценарий: введите букву там, где программа ждет возраст. Вы увидите, что поведение становится неудобным. Это важный момент: scanf не делает удобную валидацию сам, ее придется писать отдельно

Минимальная проверка ввода выглядит так:

if (scanf("%d", &age) != 1) {
    printf("Age must be a number\n");
    return 1;
}

scanf возвращает количество успешно прочитанных значений. Если ожидали одно число, результат должен быть 1

Как изменить пример под себя

Добавьте переменную для веса:

double weight = 0.0;

Спросите значение:

printf("Weight in kg: ");
scanf("%lf", &weight);

И напечатайте:

printf("Weight: %.1f kg\n", weight);

Так вы закрепите сразу три вещи: объявление переменной, чтение через scanf, вывод через printf. В C лучше учиться небольшими изменениями. Если переписывать весь пример сразу, трудно понять, какая строка сломала программу

Мини-практика: среднее значение без магии

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

#include <stdio.h>

int main(void)
{
    int first = 0;
    int second = 0;

    printf("First number: ");
    if (scanf("%d", &first) != 1) {
        printf("First number is invalid\n");
        return 1;
    }

    printf("Second number: ");
    if (scanf("%d", &second) != 1) {
        printf("Second number is invalid\n");
        return 1;
    }

    double average = (first + second) / 2.0;
    printf("Average: %.2f\n", average);

    return 0;
}

Ключевая деталь здесь — 2.0, а не 2. Если написать (first + second) / 2, деление будет целочисленным, потому что оба операнда целые. Например, сумма 5 разделится на 2 как целое число и даст 2, а не 2.5. Когда один из операндов становится double, результат тоже считается как дробное число

Проверьте программу на парах 2 и 4, 1 и 2, 10 и 11. Хороший учебный пример должен показывать не только красивый случай, но и границу, где ошибка становится заметной

Почему scanf не должен быть единственной защитой

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

На первом этапе достаточно запомнить практическое правило: каждый вызов scanf нужно проверять. Если вы ждете одно значение, результат должен быть 1. Если вы читаете два значения одной строкой, результат должен быть 2

if (scanf("%d %d", &first, &second) != 2) {
    printf("Two numbers expected\n");
    return 1;
}

Такой код не делает ввод идеальным, но уже отделяет нормальный сценарий от сломанного. Для новичка это сильная привычка: не продолжать вычисления, если входные данные не прочитаны

Как читать предупреждения компилятора

Если формат не совпадает с типом, компилятор часто пишет предупреждение про format. Не пролистывайте его. В сообщении обычно есть две части: какой спецификатор указан и какой тип реально передан

Например, если для double в scanf написать %f, компилятор может подсказать, что ожидается float , а передан double . Сначала это выглядит как шум, но в C такие предупреждения экономят часы отладки. Пока вы учитесь, команда с -Wall -Wextra должна быть стандартной, а не «когда-нибудь потом»

Частые ошибки и порядок проверки

Нет & в scanf Если написать scanf("%d", age);, функция получит не адрес, а значение. Это ошибка, которая может привести к падению программы. Для обычных числовых переменных в scanf почти всегда нужен &

Неверный формат для double Для чтения double нужен %lf, а не %f. В printf для double обычно пишут %f. Именно эта разница часто путает в первых задачах

%c читает перевод строки Добавьте пробел перед %c: scanf(" %c", &initial);. Это не украшение, а способ пропустить остаточный перевод строки

Строки через %s опасны без ограничения Если позже будете читать строку в массив char name[32];, не пишите просто scanf("%s", name);. Лучше ограничить длину: scanf("%31s", name);

Что может быть еще интересно по этой теме

Почему C не преобразует все автоматически? C многое преобразует, но не обязан спасать неверный формат в printf и scanf. Эти функции получают переменное количество аргументов, поэтому проверка зависит от компилятора и предупреждений

Можно ли пока не использовать scanf? Да. Для первых задач можно задавать значения прямо в коде. Но ввод полезен: он быстро показывает, что тип переменной связан не только с вычислениями, но и с форматом данных

Почему строка в C не отдельный тип? В базовом C строка обычно представлена как массив char, который заканчивается нулевым символом \0. Это подробно разберем в уроке про массивы и строки

Когда переходить к указателям? После типов, ввода, условий и массивов. Символ & в scanf уже подготовил почву, но полноценные указатели лучше разбирать отдельным уроком

Что почитать дальше по C

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x