Задачи на языке C с решениями и разбором

Задачи на языке C с решениями и разбором Полезное

Задачи на C — это короткие учебные программы на языке C, которые тренируют базовые конструкции: ввод и вывод, условные операторы, циклы, функции и работу с массивами. Ниже — подборка задач с готовыми решениями и разбором: от сравнения двух чисел до проверки простоты и работы с массивом.

Каждое решение — полная программа, которую можно скопировать, скомпилировать и запустить. Чтобы вывод был предсказуемым и его можно было сверить, входные данные заданы прямо в коде переменными. В конце статьи разберем типичную ошибку новичка, из-за которой программа компилируется, но работает не так, как ожидалось.

Как устроена программа на C

Минимальная программа на C состоит из функции main — точки входа. Для вывода используют printf, для чтения с клавиатуры — scanf, оба объявлены в заголовке <stdio.h>.

Скомпилировать и запустить файл task.c можно так (компилятор GCC или Clang):

cc task.c -o task
./task

В примерах ниже данные зашиты в переменные. Чтобы читать их с клавиатуры, замените присваивание на scanf:

int a, b;
scanf("%d %d", &a, &b);  // читаем два целых числа, разделенных пробелом

Обратите внимание на & перед именем переменной: scanf нужен адрес, куда записать значение. Пропуск & — частая причина падения программы.

Задача 1. Сравнение двух чисел

Условие: даны два целых числа, надо вывести, равны ли они, а если нет — какое больше. Решаем через if / else if / else.

#include <stdio.h>

int main(void) {
    int a = 7, b = 3;
    if (a == b)
        printf("Числа равны: %d\n", a);
    else if (a > b)
        printf("%d больше %d\n", a, b);
    else
        printf("%d меньше %d\n", a, b);
    return 0;
}

Для a = 7, b = 3 в консоли появится:

7 больше 3

Двойное == — это сравнение, одиночное = — присваивание. Их легко перепутать, к этому вернемся в конце.

Задача 2. Проверка попадания в диапазон

Условие: число введено пользователем. Если оно больше 5 и одновременно меньше 10, вывести одно сообщение, иначе — другое. Два условия объединяет логическое И — оператор &&.

#include <stdio.h>

int main(void) {
    int n = 8;
    if (n > 5 && n < 10)
        printf("Число %d входит в диапазон (5; 10)\n", n);
    else
        printf("Число %d вне диапазона (5; 10)\n", n);
    return 0;
}

Для n = 8 результат:

Число 8 входит в диапазон (5; 10)

Границы 5 и 10 в диапазон не входят: условие строгое (> и <). Если нужны включительные границы, взяли бы >= и <=.

Задача 3. Проценты по вкладу

Условие: по сумме вклада начисляем процент. Меньше 100 — ставка 5 %, от 100 до 200 включительно — 7 %, больше 200 — 10 %. Вывести итоговую сумму. Здесь пригодится тип double для дробного результата и цепочка if / else if.

#include <stdio.h>

int main(void) {
    double deposit = 150.0;
    double rate;
    if (deposit < 100)
        rate = 0.05;
    else if (deposit <= 200)
        rate = 0.07;
    else
        rate = 0.10;
    double total = deposit + deposit * rate;
    printf("Итоговая сумма: %.2f\n", total);
    return 0;
}

Для вклада 150 попадаем во вторую ветку (ставка 7 %), итог 150 + 150 * 0.07:

Итоговая сумма: 160.50

Формат %.2f округляет вывод до двух знаков после запятой. Само значение double при этом хранит полную дробную часть.

Задача 4. Сумма цифр числа

Условие: найти сумму цифр целого числа. Классический прием — отделять последнюю цифру остатком от деления на 10 (% 10) и укорачивать число делением на 10 (/ 10) в цикле while, пока число не станет нулем.

#include <stdio.h>

int main(void) {
    int n = 12345;
    int sum = 0;
    int x = n;
    while (x > 0) {
        sum += x % 10;  // последняя цифра
        x /= 10;        // отбрасываем ее
    }
    printf("Сумма цифр числа %d: %d\n", n, sum);
    return 0;
}

Для 12345 получаем 1 + 2 + 3 + 4 + 5:

Сумма цифр числа 12345: 15

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

Задача 5. Факториал через функцию

Условие: посчитать факториал числа и вынести расчет в отдельную функцию. Функция в C объявляется как тип имя(параметры); здесь возвращаем long long, чтобы вместить большие значения.

#include <stdio.h>

long long factorial(int n) {
    long long result = 1;
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

int main(void) {
    int n = 5;
    printf("%d! = %lld\n", n, factorial(n));
    return 0;
}

Факториал 5 — это 1 * 2 * 3 * 4 * 5:

5! = 120

Тип long long вмещает факториал примерно до 20!. Дальше значение переполнится — это ограничение целочисленного типа, а не ошибка кода.

Задача 6. Проверка на простое число

Условие: определить, простое ли число. Число простое, если делится без остатка только на 1 и на себя. Достаточно проверять делители до квадратного корня из числа — так меньше итераций.

#include <stdio.h>

int is_prime(int n) {
    if (n < 2) return 0;
    for (int d = 2; (long)d * d <= n; d++)
        if (n % d == 0) return 0;  // нашли делитель - не простое
    return 1;
}

int main(void) {
    int n = 29;
    if (is_prime(n))
        printf("Число %d простое\n", n);
    else
        printf("Число %d составное\n", n);
    return 0;
}

29 делителей, кроме 1 и 29, не имеет:

Число 29 простое

Функция возвращает 1 (истина) или 0 (ложь): в условиях C истиной считается любое ненулевое число, а ложью — ноль (тип _Bool и макросы bool/true/false из <stdbool.h> появились в C99, но проверка if работает с любым числом).

Задача 7. Максимум и разворот массива

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

#include <stdio.h>

int main(void) {
    int a[] = {3, 7, 2, 9, 4};
    int len = sizeof(a) / sizeof(a[0]);  // число элементов
    int max = a[0];
    for (int i = 1; i < len; i++)
        if (a[i] > max) max = a[i];
    printf("Максимум: %d\n", max);
    printf("В обратном порядке:");
    for (int i = len - 1; i >= 0; i--)
        printf(" %d", a[i]);
    printf("\n");
    return 0;
}

Результат для массива {3, 7, 2, 9, 4}:

Максимум: 9
В обратном порядке: 4 9 2 7 3

Выражение sizeof(a) / sizeof(a[0]) считает длину массива только там, где виден его размер. Если передать массив в функцию, он превратится в указатель, и длину придется передавать отдельным параметром.

Типичная ошибка новичка: = вместо ==

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

Неверный код:

#include <stdio.h>

int main(void) {
    int n = 5;
    if (n = 0)  // ошибка: присваиваем 0, а не сравниваем
        printf("n равно нулю\n");
    else
        printf("n не равно нулю, n = %d\n", n);
    return 0;
}

Фактический вывод:

n не равно нулю, n = 0

Разбор: n = 0 присваивает переменной ноль, и все выражение в скобках равно 0, то есть ложно. Программа уходит в ветку else, а n при этом уже испорчена — вместо 5 в ней ноль. Clang и GCC обычно предупреждают об этом (флаг -Wparentheses), но не считают ошибкой, так что программа все равно собирается.

Исправление — двойное ==:

#include <stdio.h>

int main(void) {
    int n = 5;
    if (n == 0)  // сравнение
        printf("n равно нулю\n");
    else
        printf("n не равно нулю, n = %d\n", n);
    return 0;
}

Теперь n не меняется, сравнение честное:

n не равно нулю, n = 5

Прием защиты: ставьте константу слева — if (0 == n). Тогда случайное if (0 = n) не скомпилируется, потому что константе нельзя присвоить значение.

Выводы

  • Задачи на C отрабатывают базовые конструкции: ввод-вывод через printf и scanf, условия if / else, циклы while и for, функции и массивы.
  • Двойное == сравнивает, одиночное = присваивает; их путаница компилируется, но ломает логику — помогает привычка писать константу слева.
  • Для дробных расчетов берут тип double и формат %.2f, для больших целых — long long; у каждого типа есть предел, за которым значение переполняется.
  • Массивы в C индексируются с нуля, а их длину при переборе нужно знать заранее: внутри функции размер массива через sizeof уже не получить.
  • Разбор простых чисел до квадратного корня и отделение цифр остатком от деления — типовые приемы, которые переносятся на многие другие задачи.

Где применять на практике

Освойте тему на практике

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

Освойте тему на практике

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

Смежные темы: Оператор case в Си, Создание первого приложения на C++.

FAQ

Чем отличается C от C++? C — процедурный язык без классов и объектов; C++ надстроен над тем же синтаксисом и добавляет ООП, шаблоны и стандартную библиотеку контейнеров. Базовые конструкции из этих задач одинаковы в обоих.

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

Что делать, если программа компилируется, но выдает не тот результат? Проверьте условия на = вместо ==, наличие & в scanf, границы циклов и типы: целочисленное деление отбрасывает дробь, а переполнение целого типа дает неверное число без ошибки.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)