Рекомендация: Посмотрите курс CS50 от Гарвардского Университета или Бесплатный курс по C# от BIMTeam на Stepik от компании ПИК, чтобы глубже понять основы программирования.
Истина и ложь (true/false)
В программах мы часто проверяем условия. Например: «если труба длиннее 10 м — сделать стык». Это условие может быть только истинным (true) или ложным (false).
Истина и ложь (0 и 1)
Компьютеру непонятны слова true/false, он всё хранит как числа. Поэтому true = 1, а false = 0.
Двоичная система (base-2)
Вся информация в компьютере хранится в виде комбинаций нулей и единиц. Это называется двоичная система счисления. Для нас это 0 и 1, а для процессора — есть ток (1) или нет тока (0).
В итоге: программист пишет true/false, а компьютер внутри работает только с 0 и 1.
Как работает двоичная запись числа
В компьютере каждое число хранится в виде нулей и единиц (битов). Каждая позиция в записи — это степень числа 2.
Пример: двоичное число 101
| |
Расчёт:
первая 1 = 2^2 = 4
0 = пропускаем
последняя 1 = 2^0 = 1
Итого: 4 + 1 = 5
📌 Каждый 0 или 1 — это бит (bit).
📌 8 битов = 1 байт (byte).
📌 Память компьютера адресуется по байтам.
Таблица ASCII: как байты превращаются в буквы
Компьютер хранит всё в виде чисел. Чтобы эти числа имели для нас смысл, придумали таблицу ASCII — она сопоставляет числам - буквы, цифры и знаки.
Например, число 48 в таблице ASCII соответствует символу ‘0’:
| |
ASCII Table

Указатели и структуры (из мира C)
Указатель(pointer) — это шестнадцатеричный адрес в памяти компьютера.- В
Cпрограммист сам управляет памятью: выделяет/освобождает и следит за корректностью. - В
C#этим занимается сборщик мусора (GC - Garbage Collector): большинство рутины скрыто. Указателииструктуры(pointers&structs) позволяют «сшивать» байты в цепочки — например, делать списки, где элементы лежат рядом или связаны ссылками.- В
C#мы обычно работаем склассами/структурамииссылками, а памятью управляетCLR— Common Language Runtime (Общеязыковая исполняющая среда).
Что такое ссылка?
- Ссылка (reference) — это не сами данные, а «указатель» на то место в памяти, где эти данные лежат.
- Можно представить как адрес квартиры: у тебя в руках не квартира, а бумажка с адресом, по которой ты находишь квартиру.
Пример на C#:
| |
📊 Разбор на примере двусвязного списка
У нас есть три узла (структуры/объекты):
Узел 1 (первый)
Object: данные (например, 10)Null: нет предыдущего — это начало спискаPointer to next: ссылка на Узел 2
Узел 2 (середина)
Object: данные (например, 20)Pointer to previous: ссылка на Узел 1Pointer to next: ссылка на Узел 3
Узел 3 (последний)
Object: данные (например, 30)Pointer to previous: ссылка на Узел 2Null: нет следующего — это конец
🔁 Зачем так делать?
Двусвязный список позволяет:
- двигаться вперёд и назад по элементам;
- легко вставлять/удалять элементы в середине (без «сдвига» массива).
В итоге: указатели — это как «стрелочки» между элементами. В C программист рисует и двигает их сам, а в C# за это отвечает CLR.
📊 Пример: двусвязный список (ASCII-схема)
| |
Чуть подробнее с указателями:
| |
Так видно, что каждый узел хранит данные + две ссылки: на предыдущий и на следующий элемент.
Код: сначала C, затем C#
Закрепим:
- В
Cпрограммист работает напрямую с указателями и вручную управляет памятью (malloc,free). - В
C#мы используем ссылки и классы, а памятью управляет CLR и сборщик мусора (GC).
По сути, структура данных одна и та же, но уровень «ручного труда» разный:
в C — всё в руках программиста, в C# — большая часть рутины скрыта.
C
| |
C#
| |
🧠 Вставка и удаление в связном списке
В связном списке важны две базовые операции: вставка нового элемента и удаление существующего.
Они работают не с самим массивом, а только со «стрелочками» (ссылками/указателями), которые соединяют узлы между собой.
➕ Вставка
Хотим добавить новый узел (со значением 15) между
firstиsecond.
До:
| |
После вставки нового узла (значение 15):
| |
Что делаем:
- Создаём новый узел.
- Настраиваем «стрелку» (
next) уfirstнаnewNode. - Настраиваем «стрелку» (
prev) уsecondнаnewNode. - Указываем у
newNodeегоprev = firstиnext = second.
👉 По сути, мы просто перенастроили ссылки, добавив новый элемент в цепочку.
➖ Удаление
Теперь удалим узел second из середины списка.
Например, удалим second:
До:
| |
После:
| |
Что делаем:
- Перенастраиваем
first.next = third. - Перенастраиваем
third.prev = first. - В C обязательно освобождаем память для
secondвручную (free).
В C# про это заботится сборщик мусора (GC).
👉 Мы ничего не «двигаем» и не копируем, как в массиве. Просто меняем ссылки — и список работает по-новому.
✅ Цель
Вставим узел со значением
15междуfirst(10) иsecond(20), а затем удалим его.
🧱 Код на C
🔧 Вставка
| |
❌ Удаление
| |
🧱 Код на C#
🔧 Вставка
| |
❌ Удаление
| |
✅ Итоги
| Операция | C | C# |
|---|---|---|
| Вставка | malloc + 4 указателя | new + 4 ссылки |
| Удаление | 2 указателя + free() удаляемого | 2 ссылки, сборщик мусора очистит сам |
Домашнее задание
Соберите маленькое консольное приложение, чтобы закрепить биты/байты, ASCII и списки:
- Бинарное → Десятичное → ASCII
- Напишите
BinaryToDecimal(string bits)— преобразует бинарную строку (например,"110000") вint. - Напишите
AsciiFromBinary(string bits)— возвращает соответствующий символchar. - По входной строке
"01001000 01101001"выведите"Hi".
- Двусвязный список (C#)
- Реализуйте минимальный
DoublyLinkedList<T>с внутренним узломNode(поляPrev,Next,Value). - Поддержите
AddLast,InsertAfter(node, value)иRemove(node). - Продемонстрируйте: соберите
10 <-> 20 <-> 30, вставьте15между 10 и 20, выведите вперёд/назад, затем удалите15и снова выведите.
- Коротко объясните (2–3 предложения)
- Когда массивы удобнее списков и наоборот.
- Что в C требует ручного управления памятью, а в C# делает CLR/GC.
Решение
Показать/Скрыть Код
Project Solution
| |
Program.cs
| |
Примечания
- Массивы удобны для случайного доступа по индексу и компактной памяти; списки — для частых вставок/удалений в середине без «сдвига» элементов.
- В C нужно вручную
malloc/freeи управлять указателями; в C# память и ссылки обслуживает CLR/GC.
Домашнее задание — разбор и объяснение
Ниже объяснение, зачем нужна каждая часть кода.
1) Работа с битами и ASCII
Методы
BinaryToDecimal(string bits)
Переводит двоичную строку в десятичное число через сдвиг:
| |
Это закрепляет принцип: каждая новая цифра в base-2 = умножение на 2 и добавление текущего бита.
AsciiFromBinary(string bits)Превращает число в символ: (char)BinaryToDecimal(bits).
Здесь мы видим связь с таблицей ASCII — байт = буква или знак.
DecodeBinaryMessage("0100100001101001") → “Hi”Разбивает строку на байты, переводит каждый и собирает в текст.
Показывает, что двоичные наборы напрямую соответствуют символам.
Зачем это нужно?
Закрепить фундаментальную идею: компьютер хранит буквы как числа, а числа — как комбинации битов.
2) Двусвязный список (DoublyLinkedList<T>)
Структура
Внутренний класс
Nodeхранит:Value — данные,
Prev — ссылка на предыдущий узел,
Next — ссылка на следующий узел.
Поля head и tail — быстрый доступ к началу и концу списка.
Методы
AddLastДобавляет новый узел в конец. Если список пустой — и head, и tail указывают на новый элемент.
InsertAfter(existing, value)Вставляет узел после указанного: перенастраивает ссылки у трёх элементов (existing, newNode, next).
Remove(node)Удаляет узел: корректирует ссылки у соседей, обновляет head/tail, обнуляет ссылки удаляемого (помогает GC).
В C пришлось бы ещё вызывать free, но в C# этим займётся сборщик мусора.
Forward()/Backward()Перебор элементов в обе стороны: вперёд по Next, назад по Prev.
Это ключевое преимущество двусвязного списка.
Зачем это нужно?
Закрепить понятие «ссылки/указатели» на практике. В C# мы работаем с ссылками, а
CLRиGCберут на себя управление памятью.
3) Массивы vs списки и C vs C#
МассивыУдобны для быстрого случайного доступа O(1) и компактного хранения. Но вставки/удаления в середине требуют сдвига элементов.
СпискиУдобны для частых вставок и удалений. Но доступ по индексу медленнее (O(n)).
CvsC#В
C: ручное управление памятью (malloc/free), явные указатели.В
C#: ссылки, памятью управляютCLRиGC.
Вывод
Логика и прогрессия от простого к сложному — удачная.
Каждая часть кода «подсвечивает» теоретические объяснения.
Задание даёт целостную картину: от битов до структур данных и модели памяти.
