Суть Читай диаграммы памяти и небольшие сниппеты, считай адресную арифметику, трассируй dereference и решай stack vs heap.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min
Вопросы про память — на деле вопросы про диаграммы. Прочитай каждую раскладку или сниппет, трассируй, что машина делает ячейка за ячейкой, и выбери ответ, совпадающий с моделью — address vs value, byte-смещения, dereference и где живут данные.
Цель
Отработай движения, которые будешь повторять всегда: прочитать диаграмму памяти, посчитать byte-address по смещению, пройти по pointer на один шаг и рассудить, лежит value на stack или на heap.
Сниппет 1 — диаграмма памяти
addr: 0 1 2 3 4 5value: 25 30 3 0 99 12
Викторина
Completed
Ячейка по address 2 хранит value 3, и программа трактует address 2 как pointer. Сделай dereference: какое value вернётся?
Heads-up Value 3 в ячейке-pointer — это address, а не итоговые данные. Dereference дальше читает address 3, где лежит 0. Ответ — 0.
Heads-up Dereference стартует с ячейки-pointer (address 2), а не с address 0. Читаем address 2 и получаем 3, затем address 3 и получаем 0.
Heads-up Dereference следует по сохранённому address, а не ищет максимум. Address 2 хранит 3, а address 3 хранит 0, поэтому результат — 0.
Сниппет 2 — адресная арифметика
Массив 32-битных целых начинается с address 200.Каждый элемент шириной 4 byte (32 бита).Элементы лежат вплотную без зазоров.
Викторина
Completed
По какому byte-address начинается элемент с индексом 3 (четвёртый элемент)?
Heads-up Каждый элемент шириной 4 byte, поэтому продвигаешься на index * 4, а не на index * 1. Смещение = 3 * 4 = 12, итого 200 + 12 = 212.
Heads-up Индекс 3 — четвёртый элемент (индексы с 0), и его смещение = 3 * 4 = 12. Это даёт 212, а не 216. 4 * 4 был бы индекс 4.
Heads-up На base лежит только индекс 0. Индекс 3 — на три элемента дальше: 200 + 3 * 4 = 212.
Сниппет 3 — размещение stack vs heap
int* make_counter() { int local = 0; // строка A int* shared = malloc(sizeof(int)); // строка B *shared = 0; return shared; // возвращает heap-pointer}
Викторина
Completed
После возврата make_counter что из local (строка A) и int от malloc (строка B) безопасно существует и почему?
Heads-up Быть целым к времени жизни отношения не имеет; важно размещение. local лежит в stack-фрейме и умирает с ним. Только heap-аллокация от malloc переживает вызов.
Heads-up Порядок объявления не задаёт время жизни. local — в stack-фрейме и исчезает после возврата; переживает heap-аллокация (строка B).
Heads-up Возврат освобождает stack-фрейм, но heap-память от malloc независима от вызова и живёт, пока не освобождена явно. Аллокация строки B выживает.
Сниппет 4 — трассировка записей
Старт: addr 10 -> 7, addr 11 -> 0Op 1: записать value 4 по address 11Op 2: записать value 9 по address 10Op 3: записать value 0 по address 10
Викторина
Completed
После всех трёх записей какие value лежат по address 10 и 11?
Heads-up Запись перезаписывает, а не складывает и не наслаивает value. Op 3 заменяет 9 на 0, поэтому address 10 заканчивается на 0, а не на 9.
Heads-up Запись затрагивает только свой целевой address. Op 3 ставит address 10 в 0, но оставляет address 11 равным 4 — value, записанному Op 1.
Heads-up Записи деструктивны и постоянны до следующей записи в ту ячейку. Исходных нет: address 10 заканчивается на 0, а address 11 — на 4.
Итог
Каждая задача здесь решается буквальным чтением диаграммы: value может быть address, поэтому dereference — это второе чтение по тому address; byte-address элемента массива — это base + index * elementSize; выживание value после возврата функции зависит от того, лежал он в stack-фрейме (исчез) или на heap (сохранился); а запись перезаписывает ровно одну ячейку, побеждает последняя запись, и ни один другой address не трогается. Трассируй ячейка за ячейкой — и ответ предопределён.