Язык C для начинающих: первая программа, основы синтаксиса и 7 примеров кода

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

Семь примеров кода с выводом, частые ошибки новичков с реакцией GCC и Clang и задачи для практики.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 2998 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3652 экспертных мнения Подписаться на Телеграм-канал
Обложка: Язык C для начинающих: первая программа, основы синтаксиса и 7 примеров кода

Чтобы начать писать на языке C с нуля, хватит компилятора и текстового редактора. Сохраните программу в файл hello.c, соберите её командой gcc hello.c -o hello и запустите. Если ставить ничего не хочется, первые уроки можно пройти в онлайн-компиляторе прямо в браузере.

Дальше Си учат в одном и том же порядке: переменные и типы, ввод и вывод, условия и циклы, функции, массивы и строки, указатели. Ниже семь программ в этом порядке, под каждой её вывод. Какой компилятор поставить на свою систему, подробно разобрано в статье про компилятор C.

CheckroiCheckroiПодборка курсов по C (язык Си)15 курсов • 6 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Что такое язык C и где на нём пишут

Рой пишет первую программу на языке C за ноутбуком

C (по-русски его называют Си) придумал Деннис Ритчи из Bell Labs в начале 1970-х как язык для операционной системы Unix, которую тогда только начинали писать. По воспоминаниям самого Ритчи, язык складывался в 1969–1973 годах, а самый плодотворный период пришёлся на 1972-й.

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

Язык живёт и обновляется. Актуальный стандарт называется C23, его приняли ISO и IEC в 2024 году.

Где C встречается чаще всего:

Область Пример Что подтверждает
Операционные системы Ядро Linux Документация ядра: написано на C, обычно собирается GCC в режиме -std=gnu11
Базы данных SQLite Страница проекта: со дня создания 29 мая 2000 года SQLite пишут на C
Микроконтроллеры и встраиваемые системы Прошивки бытовой техники, датчиков, контроллеров Подробно в статье о программисте микроконтроллеров

Чем на C зарабатывают и как выглядит рабочий день, мы рассказали в разборе профессии разработчика на Си. Если тянет к железу, посмотрите на программирование Arduino: скетчи пишут на C++, но базовый синтаксис у него с C общий.

Что установить, чтобы писать на Си

Нужны две вещи: редактор, где вы пишете код, и компилятор, который превращает код в программу. Редактор подойдёт любой, кроме Word: он добавляет в файл форматирование, которое компилятор не поймёт.

Система Компилятор Как поставить
Windows MSVC или GCC MSVC приходит вместе с Visual Studio: в установщике выберите рабочую нагрузку «Разработка классических приложений на C++», язык C в неё тоже входит. GCC ставят через MSYS2
macOS Clang Команда xcode-select --install в Терминале
Ubuntu и Debian GCC Команда sudo apt install build-essential, пакет тянет за собой gcc, make и заголовочные файлы

В Windows компилятор Microsoft запускают из «Командной строки разработчика» командой cl hello.c, так показано в пошаговом руководстве Microsoft. Пошаговая установка GCC через MSYS2 с командами есть в нашей статье про компиляторы, ссылка в начале.

Без установки код на C запускают в браузере. В OnlineGDB можно ввести данные с клавиатуры, это пригодится для примеров со scanf. Compiler Explorer показывает, во что компилятор превращает каждую строку, и умеет переключаться между версиями GCC и Clang.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Первая программа на C

Создайте файл hello.c и вставьте в него шесть строк:

#include <stdio.h>

int main(void) {
    printf("Привет, мир!\n");
    return 0;
}

Соберите и запустите:

gcc -std=c17 -Wall -Wextra hello.c -o hello
./hello
Привет, мир!

Что здесь происходит, построчно:

  • #include <stdio.h> подключает стандартную библиотеку ввода-вывода, где живёт printf.
  • int main(void) объявляет главную функцию. С неё начинается любая программа на C.
  • printf печатает строку, а \n переводит курсор на новую строку.
  • return 0 сообщает системе, что программа завершилась без ошибок.

Флаги в команде сборки стоит запомнить сразу. -std=c17 фиксирует версию языка, а -Wall -Wextra включают предупреждения. Без флага -std компиляторы выбирают версию сами: Clang работает в режиме gnu17, а GCC начиная с 15-й версии перешёл на gnu23. Код из этой статьи собирается в обоих режимах.

В Windows GCC создаст файл hello.exe, в командной строке его запускают командой hello.exe.

Что происходит при сборке программы

Четыре этапа сборки программы на C в виде карточек на столе

Команда gcc hello.c -o hello выглядит как один шаг, но внутри их четыре. В документации GCC они названы так: препроцессор, компиляция, ассемблирование и компоновка. Каждый этап можно остановить флагом и посмотреть на промежуточный файл:

Этап Команда Что получится
Препроцессор gcc -E hello.c -o hello.i Текст программы, в который вставлено содержимое stdio.h. В Ubuntu 24.04 файл из шести строк вырос до 819
Компиляция gcc -S hello.c -o hello.s Код на языке ассемблера
Ассемблирование gcc -c hello.s -o hello.o Объектный файл с машинным кодом
Компоновка gcc hello.o -o hello Готовая программа, к которой подключена стандартная библиотека

Зачем это новичку: сообщение об ошибке подсказывает, на каком этапе сломалось. No such file or directory про заголовочный файл приходит от препроцессора, синтаксическая ошибка от компилятора, а undefined reference to от компоновщика, когда функция объявлена, но её тело нигде не найдено. Разбор таких сообщений с примерами есть в статье о компиляторах C, в разделе о частых ошибках.

Переменные и типы данных

В C у каждой переменной есть тип, и задают его до первого использования. Тип определяет, сколько памяти займёт значение и какие операции с ним можно делать.

Тип Что хранит Пример Формат в printf
int Целое число int apples = 7; %d
double Дробное число double price = 89.90; %f, %.2f
char Один символ char grade = 'A'; %c
char[] Строка char name[] = "Си"; %s

Размер типов стандарт не фиксирует жёстко. Для int он гарантирует не меньше 16 бит, а sizeof(char) всегда равен 1. Как числа раскладываются на биты, удобно посмотреть в разборе систем счисления: примеры там на Python, но двоичная запись одна для всех языков. На обычном ноутбуке int занимает 4 байта, это видно в выводе программы:

#include <stdio.h>

int main(void) {
    int apples = 7;
    int people = 2;
    double price = 89.90;
    char grade = 'A';

    printf("Каждому по %d, остаток %d\n", apples / people, apples % people);
    printf("Точное деление: %.1f\n", (double)apples / people);
    printf("Цена: %.2f, оценка: %c\n", price, grade);
    printf("int занимает %zu байта, double — %zu\n", sizeof(int), sizeof(double));
    return 0;
}
Каждому по 3, остаток 1
Точное деление: 3.5
Цена: 89.90, оценка: A
int занимает 4 байта, double — 8

Деление двух целых даёт целое. По стандарту начиная с C99 дробная часть отбрасывается в сторону нуля, поэтому 7 / 2 равно 3. Чтобы получить 3.5, одно из чисел приводят к double, как во второй строке примера. Остаток от деления считает оператор %.

Ввод и вывод: printf и scanf

Печатает данные printf, читает с клавиатуры scanf. Формат у них общий: %d для целого, %lf для double при чтении, %s для строки.

#include <stdio.h>

int main(void) {
    int year;

    printf("Год рождения: ");
    if (scanf("%d", &year) != 1) {
        printf("Нужно целое число\n");
        return 1;
    }
    printf("В 2030 году вам исполнится %d\n", 2030 - year);
    return 0;
}
Год рождения: 1995
В 2030 году вам исполнится 35

Две детали, в которых новички ошибаются чаще всего:

  1. Знак & перед переменной. Функция scanf должна записать число в year, поэтому получает её адрес, а не значение. Откуда берётся адрес, станет ясно в разделе про указатели.
  2. Проверка результата. scanf возвращает число успешно заполненных переменных: на «abc» вместо числа это будет 0, а если ввод закончился раньше, чем удалось заполнить первую, вернётся EOF. Введёте «abc» вместо года, и программа из примера ответит «Нужно целое число», а не посчитает возраст от мусора в памяти.
Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Условия и циклы

Ветвление в C пишут через if и else, повторение через for и while. Сравнение записывают двумя знаками ==, один знак = означает присваивание. Эту пару легко перепутать, особенно после Паскаля или Python.

#include <stdio.h>

int main(void) {
    int n = 10;
    int sum = 0;

    for (int i = 1; i <= n; i++) {
        if (i % 2 == 0) {
            sum += i;
        }
    }
    printf("Сумма чётных от 1 до %d: %d\n", n, sum);

    int x = 1000;
    int steps = 0;
    while (x > 1) {
        x = x / 2;
        steps++;
    }
    printf("1000 делили пополам %d раз\n", steps);
    return 0;
}
Сумма чётных от 1 до 10: 30
1000 делили пополам 9 раз

Цикл for берут, когда число повторений известно заранее. while подходит, когда цикл крутится, пока выполняется условие: здесь мы не знаем наперёд, сколько раз 1000 поделится пополам до единицы.

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

Функции

Функция в C объявляет тип результата, имя и параметры. Если функция описана ниже main, перед main ставят её прототип, иначе компилятор не будет знать о ней в момент вызова.

#include <stdio.h>

int is_prime(int n);

int main(void) {
    for (int i = 2; i <= 30; i++) {
        if (is_prime(i)) {
            printf("%d ", i);
        }
    }
    printf("\n");
    return 0;
}

int is_prime(int n) {
    if (n < 2) {
        return 0;
    }
    for (int d = 2; d * d <= n; d++) {
        if (n % d == 0) {
            return 0;
        }
    }
    return 1;
}
2 3 5 7 11 13 17 19 23 29

Отдельного логического типа в старых стандартах не было, поэтому функция возвращает 1 для «да» и 0 для «нет». Любое ненулевое число if считает истиной. Делители проверяем только до квадратного корня из числа: если у n есть делитель больше корня, парный к нему окажется меньше корня и найдётся раньше.

Массивы и строки

Массив хранит несколько значений одного типа подряд. Нумерация начинается с нуля, так что у массива из семи элементов последний индекс 6. Размер задают при объявлении, и сам массив не растёт: в C нет аналога метода push из JavaScript, для этого вручную выделяют новую память.

Строка в C устроена как массив символов, в конце которого стоит невидимый нулевой символ \0. Из-за него sizeof у строки «hello» на единицу больше, чем её длина по strlen:

#include <stdio.h>
#include <string.h>

int main(void) {
    double temps[7] = {12.5, 14.0, 9.5, 11.0, 15.5, 13.0, 10.5};
    double total = 0;

    for (int i = 0; i < 7; i++) {
        total += temps[i];
    }
    printf("Средняя за неделю: %.1f\n", total / 7);

    char word[] = "hello";
    printf("Длина: %zu, символов в массиве: %zu\n", strlen(word), sizeof(word));
    for (int i = (int)strlen(word) - 1; i >= 0; i--) {
        printf("%c", word[i]);
    }
    printf("\n");
    return 0;
}
Средняя за неделю: 12.3
Длина: 5, символов в массиве: 6
olleh

Границы массива C не проверяет. Обращение к temps[7] скомпилируется и, скорее всего, запустится, просто прочитает чужую память. Как ловить такие ошибки, показано ниже.

Указатели: первое знакомство

Указатель хранит адрес другой переменной. Оператор & берёт адрес, оператор * достаёт значение по адресу. Без указателей функция не может изменить переменные того, кто её вызвал: в C аргументы передаются копиями.

#include <stdio.h>

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int main(void) {
    int x = 3;
    int y = 8;
    int *p = &x;

    printf("x = %d, через указатель: %d\n", x, *p);
    swap(&x, &y);
    printf("После обмена: x = %d, y = %d\n", x, y);
    return 0;
}
x = 3, через указатель: 3
После обмена: x = 8, y = 3

В C++ ту же задачу решают ещё и ссылками, но указатели там остаются, поэтому эта тема пригодится, если вы потом пойдёте в C++.

Теперь понятно, зачем scanf нужен &year: функция получает адрес и пишет число прямо в вашу переменную. После основ идут динамическая память через malloc и free и структуры, и на этом этапе указатели встречаются уже в каждой программе.

Частые ошибки новичков

Ниже семь типичных ошибок первых программ. Компиляторы реагируют на них по-разному, поэтому для каждой указано, что говорят GCC 13 и Clang 17 с флагами -std=c17 -Wall -Wextra.

Присваивание вместо сравнения

Строка if (score = 10) записывает 10 в переменную, и условие всегда истинно. Оба компилятора предупреждают. GCC пишет:

warning: suggest parentheses around assignment used as truth value [-Wparentheses]

Решение: в сравнении ставить ==.

Забытый & в scanf

Вызов scanf("%d", age) передаёт значение вместо адреса, и программа пишет число неизвестно куда. Оба компилятора ловят это предупреждением -Wformat: ждали int *, получили int.

Точка с запятой после if

В записи if (n > 5); условие ничего не охраняет: точка с запятой закончила оператор, а блок в фигурных скобках выполнится всегда. Clang предупреждает if statement has empty body, GCC советует поставить фигурные скобки.

Переменная без начального значения

В int sum; лежит то, что было в памяти до вас, и sum += i прибавляет к мусору. Clang ловит это при обычной сборке. GCC 13 в нашем примере промолчал без оптимизации и выдал предупреждение только с флагом -O2.

Решение: инициализируйте переменные сразу, int sum = 0;.

Выход за границы массива

Цикл for (int i = 0; i <= 5; i++) по массиву из пяти элементов читает шестой, которого нет. Clang 17 на этом коде молчит, GCC 13 предупреждает только с -O2. Такие ошибки ловит AddressSanitizer: соберите программу с флагом -fsanitize=address, и при запуске она остановится с отчётом.

ERROR: AddressSanitizer: stack-buffer-overflow
READ of size 4 ...
    #0 ... in main err_bounds.c:6

Целочисленное деление

Строка double half = 1 / 2; даёт 0, потому что делятся два целых. Ни один из двух компиляторов здесь не предупредил: с точки зрения языка код правильный. Пишите 1.0 / 2 или приводите тип явно.

Неверный формат в printf

Если вывести double через %d, на экране появится случайное число. Оба компилятора предупреждают через -Wformat, поэтому флаг -Wall лучше не выключать никогда.

Все семь случаев объединяет одно: код собирается, а работает неправильно. Поэтому предупреждения компилятора стоит читать так же внимательно, как ошибки.

Задачи для практики

Рой радуется, что программа собралась и выдала правильный ответ

Четыре задачи на темы статьи. Каждая решается программой до 30 строк.

  1. Таблица температур. Выведите пересчёт из градусов Цельсия в Фаренгейты от 0 до 100 с шагом 10. Формула: F = C × 9 / 5 + 32. Проверьте себя: 100 °C дают 212 °F. Если вышло 132, вы записали 9 / 5 * c: целые 9 / 5 дают 1, и формула ломается.
  2. Сумма цифр. Прочитайте целое число через scanf и посчитайте сумму его цифр циклом while: остаток % 10 даёт последнюю цифру, деление / 10 её отрезает. Для 2026 ответ 10.
  3. Максимум в массиве. Заполните массив из десяти чисел и найдите наибольшее и его индекс. Не забудьте, что индексы идут от 0 до 9.
  4. Разворот строки на месте. Напишите функцию void reverse(char *s), которая меняет символы местами с двух концов, пока индексы не встретятся. Длину возьмите через strlen.

Как учить C дальше

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

  • Книга Кернигана и Ритчи «Язык программирования C». Создатель языка написал её вместе с Брайаном Керниганом. Книга тонкая и плотная, упражнения в ней хорошие, но новичку без опыта программирования она даётся тяжело.
  • Справочник cppreference по стандартной библиотеке C. Там описано, что возвращает каждая функция и в какой версии стандарта она появилась.
  • Курс CS50 Гарвардского университета. После вводной недели на Scratch программа курса переходит на C, а неделя 4 называется Memory и разбирает работу с памятью. Материалы бесплатные, на английском.
  • Задачи на каждую тему. Пишите по пять-десять маленьких программ на тему, прежде чем идти дальше. Как выстроить самостоятельную учёбу, мы разбирали в статье о том, как учить языки программирования самостоятельно.

Первым языком C выбирать можно, но готовьтесь, что ошибки с памятью съедят часть мотивации. Если цель просто научиться программировать, начинать с Python проще, сравнение подходов есть в материале о программировании с нуля. Если вас интересуют встраиваемые системы, драйверы или устройство компьютера изнутри, C ведёт туда напрямую. Путь до первой работы на Си расписан в плане как стать программистом на Си.

C и C++ часто учат парой. C++ вырос из C и добавил классы, шаблоны и большую стандартную библиотеку. Синтаксис основ у них общий, поэтому база из этой статьи пригодится и там.

Где освоить язык Си системно

Основы из статьи можно пройти самостоятельно. Дальше начинаются указатели, память и сборка проектов, и тут удобнее учиться по программе с проверкой заданий. Ниже курсы по языку C из нашего каталога, а если хотите сразу двигаться к C++, посмотрите курсы по C++.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Инженер-программист
Перейти на сайт курса
GeekBrainsGeekBrains159 408 ₽4428 ₽/мес.12 месяцевОбзор курса
Специалист по информационной безопасности: расширенный курс
Перейти на сайт курса
НетологияНетология117 343 ₽4018 ₽/мес.13 месяцевОбзор курса
Внедрение и работа в DevSecOps
Перейти на сайт курса
OTUSOTUS88 000 ₽8800 ₽/мес.5 месяцевОбзор курса
Блокчейн
Перейти на сайт курса
GeekBrainsGeekBrains168 768 ₽4153 ₽/мес.4 месяцаОбзор курса
Инженер-программист C++
Перейти на сайт курса
GeekBrainsGeekBrains7970 ₽221 ₽/мес.1 месяцОбзор курса

Больше программ — в полном каталоге курсов по C (язык Си)

Часто задаваемые вопросы

С чего начать изучать язык C с нуля?

Поставьте компилятор GCC, Clang или MSVC либо откройте онлайн-компилятор и соберите программу «Привет, мир». Дальше идите по темам: переменные и типы, ввод и вывод, условия и циклы, функции, массивы и строки, указатели. На каждую тему пишите несколько маленьких программ.

Можно ли учить C первым языком программирования?

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

Чем язык C отличается от C++?

C++ вырос из C и добавил классы, шаблоны и большую стандартную библиотеку. Синтаксис основ у них общий, поэтому знание C помогает в C++. Разницу в работе мы разбирали в статье о разработчике на Си.

Где писать код на C без установки компилятора?

В браузере: в OnlineGDB можно запускать программы и вводить данные с клавиатуры, а Compiler Explorer показывает результат компиляции разными версиями GCC и Clang. Для первых уроков этого хватает.

Какой стандарт языка C сейчас актуален?

Актуальный стандарт называется C23, его приняли ISO и IEC в 2024 году. GCC начиная с 15-й версии по умолчанию работает в режиме gnu23, Clang в режиме gnu17. Нужную версию задают флагом -std, например -std=c17.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

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

Напишите, что думаете. Нам важно ваше мнение!