Базовый CS с нуля
Трассировка программы
Ты теперь знаешь, что if — это условный переход, а while — обратный переход. Но
читать о них по отдельности — совсем не то же самое, что наблюдать, как они работают
вместе в реальной программе, шаг за шагом, с меняющимся прямо перед тобой состоянием
переменных.
Именно это и делает этот урок. Ты прочитаешь короткую TypeScript-функцию, которая обходит небольшой массив и суммирует только положительные числа. Затем проследишь её кадр за кадром — следя за счётчиком команд и значением каждой переменной на каждой строке — пока функция не вернёт результат.
После этой трассировки ты будешь знать не только то, что код говорит; ты будешь знать, что CPU делает, по одной инструкции за раз.
После этого урока ты сможешь прочитать программу, объединяющую цикл и условие, предсказать каждый шаг выполнения, отслеживая счётчик команд и значения переменных, объяснить, как взаимодействуют условие цикла и условие if, и определить точный кадр, в котором цикл выходит.
Программа для трассировки — функция суммирования положительных чисел по фиксированному массиву. В ней три момента управления потоком:
- Тест while — вычислить
i < nums.lengthв начале каждой итерации. Счётчик команд либо проваливается в тело цикла (условие истинно), либо прыгает вперёд за цикл (условие ложно, выход). - Тест if — вычислить
nums[i] > 0внутри тела. Счётчик команд либо выполняетsum += nums[i](условие истинно, fall-through), либо пропускает его (условие ложно, прыжок вперёд). - Инкремент и обратный переход —
i++выполняется на каждой итерации (положительное или нет), затем безусловный обратный переход возвращается к тесту while.
Массив: [3, -1, 4]. Начальное состояние: sum = 0, i = 0. Ожидаемый результат:
3 + 4 = 7 (значение -1 пропускается внутренним if).
Каждый кадр в трассировке показывает:
- Строку кода, которая вот-вот выполнится.
- Текущие значения
i,sumиnums[i].
Настоятельно рекомендуется сначала самостоятельно пройти трассировку вручную, а потом смотреть кадры — это закрепляет ментальную модель движения счётчика команд по коду.
1
function sumPositives(nums: number[]): number {
2
let sum = 0; // аккумулятор начинается с нуля
3
let i = 0; // счётчик цикла начинается с нуля
4
5
while (i < nums.length) { // цикл с обратным переходом
6
if (nums[i] > 0) { // условие: пропустить отрицательные
7
sum += nums[i];
8
}
9
i++; // всегда инкремент, положительное или нет
10
}
11
12
return sum;
13
}
- L2 sum: аккумулятор — собирает текущую сумму
- L3 i: индекс в nums — продвигается на каждой итерации
- L5 тест while: CMP i, nums.length → условный переход выходит при i >= length
- L6 тест if: CMP nums[i], 0 → условный переход пропускает sum+= когда nums[i] <= 0
- L7 sum += nums[i]: добавляет текущий элемент только когда условие if истинно
- L9 i++: безусловный; выполняется даже когда if был пропущен
- L10 закрывающая скобка: безусловный обратный переход к тесту while на строке 5
Пройди sumPositives([3, -1, 4]) кадр за кадром. Каждая ячейка показывает текущее
значение одной переменной. Активная строка подсвечена в панели кода выше.
1
function sumPositives(nums: number[]): number {
2
let sum = 0;
3
let i = 0;
4
5
while (i < nums.length) {
6
if (nums[i] > 0) {
7
sum += nums[i];
8
}
9
i++;
10
}
11
12
return sum;
13
}
Граничные случаи
Что если массив пустой? Если nums = [], то nums.length = 0, и тест while при
самой первой проверке вычисляет i=0 < 0 → false. Тело цикла не выполняется ни разу.
Функция сразу возвращает sum = 0. Это корректный результат для пустых входных данных
и является естественным следствием проверки условия перед телом — тот же аппаратный
механизм, который делает тест while в начале.
После первой итерации sumPositives([3,-1,4]) переменная i была проинкрементирована с 0. Какое значение имеет i в начале второго теста while?
Во время итерации 2 (nums[1] = -1) условие if nums[1] > 0 ложно. Какое значение имеет sum после выполнения i++ в конце этой итерации?
Сколько раз выполняется строка 'sum += nums[i]' при вызове с [3,-1,4]?
При каком значении i цикл while выходит (т. е. когда условие while становится ложным)?
sumPositives([2, -5, -3, 6]) возвращает какое значение?
В sumPositives: что происходит когда nums[i] отрицательный или нулевой?
Трассировка программы шаг за шагом раскрывает конкретный механизм за высокоуровневым
синтаксисом. В sumPositives цикл while — это структура с тестом в начале и обратным
переходом: на каждой итерации условие i < nums.length вычисляется (сравнение обновляет
флаг Z или N), условный переход либо выходит из цикла, либо проваливается в тело, а
безусловный обратный переход в конце сбрасывает счётчик команд обратно к тесту.
Внутренний if — это второй CMP + условный переход: когда nums[i] > 0 ложно, тело
sum += nums[i] пропускается условным прямым переходом; когда истинно — fall-through.
Инкремент i++ безусловен — он стоит за пределами блока if и выполняется в любом случае.
Цикл выходит, когда i достигает nums.length: в этот момент условие while ложно,
условный переход в начале срабатывает (прямой переход за цикл), и счётчик команд
перемещается к return sum. Итоговое значение sum — сумма всех положительных
элементов, встреченных в ходе итерации.