awesome-everything EN
↑ Обратно к восхождению

Базовый CS с нуля

Функции и стек вызовов: чтение кода и трассировка

Суть Прочитайте четыре маленьких сниппета на TypeScript, проследите стек кадр за кадром, посчитайте глубину рекурсии и предскажите, что реально делают передача параметров и возврат.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Чтение стека вызовов по коду — навык, к которому ведёт весь юнит. Для каждого сниппета прогоните его в голове: кладите кадр на каждый вызов, снимайте один на каждый возврат и следите, куда текут значения.

Цель

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

Сниппет 1 — вложенные вызовы и глубина стека

function inner(): void {
  let c = 3;          // единственная локальная переменная inner
}

function outer(): void {
  let b = 2;          // единственная локальная переменная outer
  inner();            // кладёт кадр inner
}

function main(): void {
  let a = 1;          // единственная локальная переменная main
  outer();            // кладёт кадр outer
}

main();
Викторина

В момент, когда inner выполняет let c = 3, сколько кадров на стеке и какой из них хранит a = 1?

Сниппет 2 — передача параметров (по значению)

function bump(x: number): void {
  x = x + 100;        // переприсваивает собственную копию x в bump
}

function main(): void {
  let v = 1;
  bump(v);            // аргумент 1 копируется в x функции bump
  // чему равно v здесь?
}
Викторина

После возврата bump(v) чему равно v в main и почему?

Сниппет 3 — глубина рекурсии

function sumTo(n: number): number {
  if (n === 0) return 0;        // базовый случай
  return n + sumTo(n - 1);      // рекурсивный случай
}

sumTo(4);
Викторина

Для sumTo(4) каково максимальное число кадров, активных одновременно, и какое значение возвращается?

Сниппет 4 — отсутствующий базовый случай

function blow(n: number): number {
  return n + blow(n + 1);   // нет базового случая: n только растёт
}

blow(0);
Викторина

Что происходит при запуске blow(0) и в чём первопричина?

Итог

Каждый сниппет читается прогоном стека в голове: вложенные вызовы держат кадры всех вызывающих функций активными ниже текущего; скопированный аргумент означает, что переприсвоение параметра никогда не трогает переменную вызывающей стороны; рекурсивный вызов кладёт новый кадр на уровень, поэтому пиковая глубина — это число вложенных активных вызовов (включая базовый случай); а рекурсия без достижимого базового случая растит стек без ограничений, пока он не переполнится. Трассируйте укладку-при-вызове и снятие-при-возврате — и ответы выпадают сами.

Продолжить восхождение ↑Функции и стек вызовов: постройте трассировщик стека
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.