C
Весь язык C на одной странице: типы, указатели, массивы, структуры, malloc, препроцессор и файлы — экспресс-тур в комментариях кода.
C — компактный компилируемый язык, на котором написаны ядра ОС, драйверы и интерпретаторы. Весь язык — на одной странице, прямо в комментариях кода. Компилируй: gcc file.c -o file и запускай ./file.
1. Структура программы
// Это однострочный комментарий
/* А это многострочный
комментарий */
#include <stdio.h> // подключаем стандартный ввод-вывод (printf и т.д.)
// int main — точка входа. Возвращает код завершения (0 = успех)
int main(void) {
printf("Привет, мир!\n"); // \n — перевод строки
return 0; // 0 сообщает ОС: всё прошло успешно
}
// Вывод программы:
// Привет, мир!
2. Переменные и типы
В C переменную надо объявить с типом. Размеры зависят от платформы (даны типичные).
#include <stdio.h>
#include <stdbool.h> // для типа bool (C99)
int main(void) {
int i = 42; // целое, обычно 4 байта
short s = 10; // короткое целое, обычно 2 байта
long l = 1000000L; // длинное целое
float f = 3.14f; // вещественное одинарной точности (суффикс f)
double d = 2.71828; // вещественное двойной точности
char c = 'A'; // символ (1 байт), хранит код 65
_Bool b = 1; // логический тип C99 (или bool из stdbool.h)
unsigned int u = 4000000000U; // только неотрицательные
// Спецификаторы printf:
printf("%d\n", i); // %d — int -> 42
printf("%ld\n", l); // %ld — long -> 1000000
printf("%f\n", f); // %f — float/double -> 3.140000
printf("%.2f\n", d); // %.2f — 2 знака -> 2.72
printf("%c\n", c); // %c — символ -> A
printf("%d\n", c); // как число -> 65
printf("%u\n", u); // %u — unsigned -> 4000000000
printf("%x\n", 255); // %x — hex -> ff
// Константа: значение нельзя менять
const double PI = 3.14159;
printf("%f\n", PI); // -> 3.141590
return 0;
}
3. Ввод-вывод
#include <stdio.h>
int main(void) {
int age;
float height;
printf("Введите возраст: ");
scanf("%d", &age); // & — передаём адрес переменной!
printf("Введите рост: ");
scanf("%f", &height); // для float в scanf нужен %f
// Вывод нескольких значений в одной строке:
printf("Вам %d лет, рост %.1f\n", age, height);
char name[50];
scanf("%49s", name); // строка без пробелов; имя массива = адрес, & не нужен
printf("Привет, %s!\n", name);
return 0;
}
// Пример сессии (ввод: 25, 1.80, Аня):
// Вам 25 лет, рост 1.8
// Привет, Аня!
4. Операторы и условия
#include <stdio.h>
int main(void) {
int a = 10, b = 3;
printf("%d\n", a + b); // 13
printf("%d\n", a - b); // 7
printf("%d\n", a * b); // 30
printf("%d\n", a / b); // 3 (целочисленное деление!)
printf("%d\n", a %% b); // 1 (остаток); в коде пишется один %
// Сравнения: ==, !=, <, >, <=, >=
// Логика: && (и), || (или), ! (не)
if (a > b && b > 0) {
printf("a больше b и b положительно\n");
} else if (a == b) {
printf("равны\n");
} else {
printf("иначе\n");
}
// Тернарный оператор: условие ? если_да : если_нет
int max = (a > b) ? a : b;
printf("max = %d\n", max); // max = 10
// switch — выбор по значению
int day = 3;
switch (day) {
case 1: printf("Пн\n"); break; // break обязателен!
case 3: printf("Ср\n"); break; // -> Ср
default: printf("другой\n");
}
return 0;
}
5. Циклы
#include <stdio.h>
int main(void) {
// for: инициализация; условие; шаг
for (int i = 0; i < 3; i++) {
printf("i=%d ", i); // i=0 i=1 i=2
}
printf("\n");
// while: проверка перед телом
int n = 3;
while (n > 0) {
printf("%d ", n); // 3 2 1
n--;
}
printf("\n");
// do-while: тело выполнится хотя бы раз
int k = 0;
do {
printf("раз "); // раз
} while (k > 0);
printf("\n");
// break — выйти из цикла, continue — к следующей итерации
for (int i = 0; i < 10; i++) {
if (i == 2) continue; // пропустить 2
if (i == 5) break; // остановиться на 5
printf("%d ", i); // 0 1 3 4
}
printf("\n");
return 0;
}
6. Массивы и строки
Строка в C — это массив char, завершённый нулевым байтом '\0'.
#include <stdio.h>
#include <string.h> // strlen, strcpy, strcmp, strcat
int main(void) {
int nums[5] = {10, 20, 30, 40, 50}; // массив из 5 int
printf("%d\n", nums[0]); // 10 (индексация с нуля)
nums[1] = 99;
printf("%d\n", nums[1]); // 99
int sizeN = sizeof(nums) / sizeof(nums[0]); // длина = 5
printf("длина: %d\n", sizeN);
// Строки
char s1[20] = "Привет"; // массив char с '\0' в конце
char s2[20];
printf("%zu\n", strlen("abc")); // strlen — длина -> 3
strcpy(s2, s1); // копирование s1 в s2
strcat(s2, "!"); // конкатенация -> "Привет!"
printf("%s\n", s2); // Привет!
// strcmp: 0 если строки равны
if (strcmp("abc", "abc") == 0)
printf("строки равны\n");
return 0;
}
7. Указатели
Указатель хранит адрес переменной. & — взять адрес, * — разыменовать (получить значение по адресу).
#include <stdio.h>
int main(void) {
int x = 42;
int *p = &x; // p указывает на x (хранит адрес x)
printf("%d\n", x); // 42 (значение)
printf("%p\n", (void*)&x); // адрес x, напр. 0x7ffe...
printf("%d\n", *p); // 42 (* — значение по адресу)
*p = 100; // меняем x через указатель
printf("%d\n", x); // 100
// Арифметика указателей: шаг = размер типа
int arr[3] = {7, 8, 9};
int *q = arr; // имя массива = адрес первого элемента
printf("%d\n", *q); // 7
printf("%d\n", *(q+1)); // 8 (q+1 -> следующий int)
printf("%d\n", q[2]); // 9 (q[2] == *(q+2))
int *nothing = NULL; // NULL — "никуда не указывает"
if (nothing == NULL) printf("пустой указатель\n");
return 0;
}
8. Функции
Прототип объявляет функцию заранее; передача по умолчанию — по значению (копия). Чтобы изменить аргумент, передают указатель.
#include <stdio.h>
// Прототипы (объявления до main)
int sum(int a, int b);
void increment(int *n);
int main(void) {
printf("%d\n", sum(2, 3)); // 5
int x = 10;
increment(&x); // передаём адрес
printf("%d\n", x); // 11 (значение изменилось)
int y = 10;
// передача по значению ничего бы не изменила:
// increment_value(y) -> y осталось бы 10
(void)y;
return 0;
}
// Определения функций
int sum(int a, int b) { // a, b — копии аргументов
return a + b;
}
void increment(int *n) { // n — адрес; *n — само значение
(*n)++; // меняем переменную вызвавшего
}
9. Структуры
#include <stdio.h>
#include <string.h>
// struct объединяет поля разных типов
struct Point {
int x;
int y;
};
// typedef задаёт короткое имя типа
typedef struct {
char name[30];
int age;
} Person;
int main(void) {
struct Point p = {3, 4};
printf("%d, %d\n", p.x, p.y); // 3, 4 (доступ через .)
p.x = 10;
Person alice;
strcpy(alice.name, "Алиса");
alice.age = 30;
printf("%s, %d\n", alice.name, alice.age); // Алиса, 30
// Через указатель используют стрелку ->
Person *ptr = &alice;
printf("%d\n", ptr->age); // 30 (то же, что (*ptr).age)
return 0;
}
10. Динамическая память
Память в куче выделяется вручную и так же вручную освобождается через free — иначе утечка.
#include <stdio.h>
#include <stdlib.h> // malloc, calloc, realloc, free
int main(void) {
// malloc — выделить N байт (неинициализированных)
int *arr = malloc(3 * sizeof(int));
if (arr == NULL) return 1; // проверка: память могла не выделиться
arr[0] = 1; arr[1] = 2; arr[2] = 3;
printf("%d\n", arr[1]); // 2
// calloc — выделить и обнулить
int *zeros = calloc(3, sizeof(int));
printf("%d\n", zeros[0]); // 0
// realloc — изменить размер блока
arr = realloc(arr, 5 * sizeof(int));
arr[3] = 4; arr[4] = 5;
printf("%d\n", arr[4]); // 5
free(arr); // обязательно освобождаем!
free(zeros);
arr = NULL; // хорошая привычка после free
return 0;
}
11. Препроцессор
#include <stdio.h>
#define PI 3.14159 // макрос-константа (текстовая замена)
#define SQUARE(x) ((x) * (x)) // макрос-функция (скобки важны!)
#define DEBUG 1
int main(void) {
printf("%f\n", PI); // 3.141590
printf("%d\n", SQUARE(5)); // 25
printf("%d\n", SQUARE(2 + 3)); // 25 (благодаря скобкам в макросе)
// Условная компиляция
#ifdef DEBUG
printf("режим отладки\n"); // попадёт в код, т.к. DEBUG определён
#endif
#if DEBUG == 1
printf("DEBUG == 1\n");
#else
printf("релиз\n");
#endif
return 0;
}
// Вывод:
// 3.141590
// 25
// 25
// режим отладки
// DEBUG == 1
12. Файлы
#include <stdio.h>
int main(void) {
// Запись: "w" — создать/перезаписать
FILE *f = fopen("data.txt", "w");
if (f == NULL) return 1; // файл мог не открыться
fprintf(f, "%d %s\n", 42, "hello"); // пишем как printf, но в файл
fclose(f); // обязательно закрываем
// Чтение: "r"
FILE *r = fopen("data.txt", "r");
if (r == NULL) return 1;
int n;
char word[50];
fscanf(r, "%d %s", &n, word); // читаем как scanf, но из файла
printf("%d %s\n", n, word); // 42 hello
fclose(r);
// Режимы: "r" чтение, "w" запись, "a" дозапись в конец,
// "rb"/"wb" — бинарный режим
return 0;
}
Итог: ты прошёл весь базовый C — от printf до указателей, ручного управления памятью и работы с файлами. Дальше — заголовочные файлы (.h), битовые операции, union и стандартная библиотека. Компилируй с флагами -Wall -Wextra, чтобы ловить ошибки раньше.