Язык C крошечный: типы, операторы, управляющие конструкции, функции, указатели. Он не умеет ни печатать, ни читать файл, ни сравнить строку, ни выделить память. Всё это — стандартная библиотека: набор заголовков, который поставляет каждая соответствующая стандарту реализация.
Эта страница — карта. Каждый раздел говорит, для чего нужен заголовок, показывает один короткий рабочий пример и указывает на более подробную страницу там, где она есть.
stdio.h — ввод и вывод
Заголовок, который вы подключаете первым почти в каждой программе. В нём живут printf и scanf, тип FILE и функции работы с файлами, а также более безопасные построчные функции ввода.
Самое необходимое: printf, fprintf, sprintf, snprintf для вывода; scanf, fscanf, sscanf, fgets, getchar для ввода; fopen, fclose, fread, fwrite, fseek для файлов. Подробнее — в printf, scanf и работе с файлами.
Одно правило стоит унести с собой: никогда не используйте gets(). Он никак не может узнать размер вашего буфера и был удалён из стандарта в C11. Замена — fgets(buf, sizeof buf, stdin).
stdlib.h — утилиты общего назначения
Сборная солянка: память, преобразования, случайные числа, управление процессом, сортировка.
Главное: malloc, calloc, realloc, free (см. динамическую память); atoi, atof, strtol, strtod для преобразований — предпочитайте семейство strto*, которое умеет сообщать об ошибке там, где atoi молча возвращает 0; rand и srand (см. случайные числа); exit, abort, getenv, system; а также qsort/bsearch.
string.h — строки и блоки памяти
Строки в C — это массивы char, заканчивающиеся '\0', и каждая операция над ними есть вызов функции.
Две привычки не дают этому заголовку превратиться в источник переполнений буфера: всегда знайте размер приёмника и помните, что strcmp возвращает 0 при равенстве — if (strcmp(a, b)) истинно, когда строки различаются. Функции для строк подробно разбирают более безопасные приёмы со strncpy/snprintf.
math.h — математика
sqrt, pow, fabs, floor, ceil, round, fmod, семейства тригонометрических и логарифмических функций, INFINITY и NAN.
Это единственный заголовок, которому может понадобиться флаг компоновщика: в Linux добавьте -lm в конец команды компиляции, иначе компоновщик сообщит "undefined reference to sqrt". Полный обзор — в математических функциях.
time.h — часы и даты
Два смещения в struct tm ловят всех: tm_year отсчитывается от 1900 года, а tm_mon нумеруется с нуля. time(NULL) к тому же обычно служит зерном для srand.
ctype.h — классификация символов
Маленький и куда более полезный, чем кажется. Каждая функция принимает символ и отвечает на вопрос «да или нет» либо меняет регистр.
Полный набор: isalpha, isdigit, isalnum, isspace, isupper, islower, ispunct, isxdigit, isprint, плюс toupper и tolower.
Обратите внимание на приведение (unsigned char). Эти функции определены для значений, представимых как unsigned char, плюс EOF; обычный char на большинстве систем знаковый, поэтому байт больше 127 приходит отрицательным числом и вызов становится неопределённым поведением. Приведение ничего не стоит и снимает целый класс проблем.
И предпочитайте их самодельным проверкам. c >= '0' && c <= '9' случайно работает, но isdigit(c) говорит о том, что вы имеете в виду, и остаётся корректным везде.
limits.h и float.h — границы типов
Насколько большим может быть int на этой машине? Эти заголовки отвечают на вопрос, и именно поэтому переносимый код спрашивает, а не предполагает.
INT_MAX — это способ проверить переполнение до того, как оно произойдёт, и это важно, потому что знаковое переполнение — неопределённое поведение, а не обёртывание, которое можно проверить постфактум.
stdbool.h и stdint.h — типы получше
До C99 в C не было логического типа. <stdbool.h> его даёт:
bool, true и false — это макросы для _Bool, 1 и 0, но они делают намерение очевидным. (В C23 они стали ключевыми словами, и заголовок больше не нужен.)
<stdint.h> даёт типы с гарантированной разрядностью — незаменимые для форматов файлов, сетевых протоколов и всего встраиваемого, где «int, наверное, 32-битный» недостаточно хорошо:
Макросы вида PRId32 из <inttypes.h> разворачиваются в правильный спецификатор printf для каждого типа фиксированной ширины на текущей платформе — это и есть переносимый способ их печатать, ведь %d подходит для int32_t на одних системах и не подходит на других.
assert.h — проверка ваших предположений
assert(expr) не делает ничего, когда выражение истинно, и аварийно завершает программу с сообщением, когда оно ложно.
Компиляция с -DNDEBUG убирает все проверки, так что в релизной сборке они ничего не стоят. В этом же и предупреждение: никогда не помещайте побочный эффект внутрь assert. assert(read_next() > 0) в релизной сборке вообще перестаёт читать, и получившийся баг проявляется только в продакшене.
Проверки предназначены для ваших ошибок — для условий, которые должны быть невозможны, если код корректен. Плохой ввод пользователя — не повод для assert; это if и сообщение об ошибке.
Остальное, кратко
<stddef.h>—size_t,ptrdiff_t,NULL,offsetof<stdarg.h>— функции с переменным числом аргументов, механика, стоящая заprintf<errno.h>—errnoплюсperrorиstrerror, чтобы сообщить, почему вызов не удался<signal.h>— обработка сигналов, например Ctrl-C<setjmp.h>— нелокальные переходы; редко бывают правильным ответом<locale.h>,<wchar.h>,<wctype.h>— локали и широкие символы<stdnoreturn.h>,<stdalign.h>,<threads.h>,<stdatomic.h>— дополнения C11
Две привычки делают библиотеку приятной в использовании. Читайте man-страницу, а не угадывайте сигнатуру — man 3 strtol на macOS и Linux авторитетен и быстр. И проверяйте возвращаемые значения: malloc, fopen и strtol все сообщают о неудаче, а программа, которая их игнорирует, ломается гораздо позже и гораздо менее понятным образом.
Часто задаваемые вопросы
Что такое стандартная библиотека C?
Это набор функций, типов и макросов, которые предоставляет каждая соответствующая стандарту реализация C, сгруппированных примерно в 30 заголовков. Он покрывает ввод и вывод (<stdio.h>), память и преобразования (<stdlib.h>), строки (<string.h>), математику (<math.h>), время, классификацию символов и пределы числовых типов. В самом языке C нет ни встроенного ввода-вывода, ни работы со строками — всё это отсюда.
В чём разница между stdio.h и stdlib.h?
<stdio.h> — это ввод и вывод: printf, scanf, fopen, fgets, FILE. <stdlib.h> — это утилиты общего назначения: malloc и free, atoi и strtol, rand и srand, exit, qsort, bsearch. Типичная программа подключает оба.
Для чего нужен ctype.h?
Он классифицирует и преобразует отдельные символы: isdigit, isalpha, isalnum, isspace, isupper, islower, ispunct, плюс toupper и tolower. Использовать их вместо самописных сравнений вроде c >= '0' && c <= '9' понятнее и корректно для любой локали и любой кодировки.
Нужно ли что-то линковать, чтобы использовать стандартную библиотеку C?
Нет, с одним исключением — математическими функциями. Стандартная библиотека C линкуется автоматически, но в Linux реализации из <math.h> лежат в отдельной библиотеке, так что sqrt и компании требуют -lm в конце команды компиляции. Всему остальному нужен только правильный #include.