Control flow · 07
More loops
Taking values one by one, going backwards, reading up to an end marker, and the run-at-least-once do-while.
This lesson adds four shapes to the for and while from the Loops lesson.
The example below reads positive whole numbers until a 0 appears and collects them, takes the values one by one to add them up, prints them from the back, and finally counts how many digits the total has.
nums = []x = int(input())while x != 0: # 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums.append(x) x = int(input()) total = 0for v in nums: # 번호 없이 값을 하나씩 total += vprint(total) for i in range(len(nums) - 1, -1, -1): # 마지막 번호부터 0번까지 print(nums[i]) digits = 0while True: # do-while이 없어서: 먼저 한 번 하고 끝에서 확인해요 digits += 1 total //= 10 if total == 0: breakprint(digits)const lines = require("fs").readFileSync(0, "utf8").split("\n");let at = 0;const nums = [];let x = Number(lines[at++]);while (x !== 0) { // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums.push(x); x = Number(lines[at++]);} let total = 0;for (const v of nums) { // 번호 없이 값을 하나씩 total += v;}console.log(total); for (let i = nums.length - 1; i >= 0; i--) { // 마지막 번호부터 0번까지 console.log(nums[i]);} let digits = 0;do { // 먼저 한 번 하고 끝에서 확인해요 digits++; total = Math.trunc(total / 10);} while (total !== 0);console.log(digits);import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");let at = 0;const nums: number[] = [];let x: number = Number(lines[at++]);while (x !== 0) { // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums.push(x); x = Number(lines[at++]);} let total: number = 0;for (const v of nums) { // 번호 없이 값을 하나씩 total += v;}console.log(total); for (let i = nums.length - 1; i >= 0; i--) { // 마지막 번호부터 0번까지 console.log(nums[i]);} let digits: number = 0;do { // 먼저 한 번 하고 끝에서 확인해요 digits++; total = Math.trunc(total / 10);} while (total !== 0);console.log(digits);import java.util.ArrayList;import java.util.List;import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); List<Integer> nums = new ArrayList<>(); int x = sc.nextInt(); while (x != 0) { // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums.add(x); x = sc.nextInt(); } int total = 0; for (int v : nums) { // 번호 없이 값을 하나씩 total += v; } System.out.println(total); for (int i = nums.size() - 1; i >= 0; i--) { // 마지막 번호부터 0번까지 System.out.println(nums.get(i)); } int digits = 0; do { // 먼저 한 번 하고 끝에서 확인해요 digits++; total /= 10; } while (total != 0); System.out.println(digits); }}using System;using System.Collections.Generic; class Program{ static void Main() { List<int> nums = new List<int>(); int x = int.Parse(Console.ReadLine()); while (x != 0) // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 { nums.Add(x); x = int.Parse(Console.ReadLine()); } int total = 0; foreach (int v in nums) // 번호 없이 값을 하나씩 { total += v; } Console.WriteLine(total); for (int i = nums.Count - 1; i >= 0; i--) // 마지막 번호부터 0번까지 { Console.WriteLine(nums[i]); } int digits = 0; do // 먼저 한 번 하고 끝에서 확인해요 { digits++; total /= 10; } while (total != 0); Console.WriteLine(digits); }}#include <iostream>#include <vector> int main() { std::vector<int> nums; int x; std::cin >> x; while (x != 0) { // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums.push_back(x); std::cin >> x; } int total = 0; for (int v : nums) { // 번호 없이 값을 하나씩 total += v; } std::cout << total << '\n'; for (int i = (int)nums.size() - 1; i >= 0; i--) { // 마지막 번호부터 0번까지 std::cout << nums[i] << '\n'; } int digits = 0; do { // 먼저 한 번 하고 끝에서 확인해요 digits++; total /= 10; } while (total != 0); std::cout << digits << '\n';}#include <stdio.h> int main(void) { int nums[1000], n = 0, x; scanf("%d", &x); while (x != 0) { // 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요 nums[n++] = x; scanf("%d", &x); } int total = 0; for (int i = 0; i < n; i++) { // 값을 하나씩 꺼내는 꼴이 없어서 번호로 돌아요 total += nums[i]; } printf("%d\n", total); for (int i = n - 1; i >= 0; i--) { // 마지막 번호부터 0번까지 printf("%d\n", nums[i]); } int digits = 0; do { // 먼저 한 번 하고 끝에서 확인해요 digits++; total /= 10; } while (total != 0); printf("%d\n", digits); return 0;}nums = [];x = Console.ReadLine().ToNumber();// 0이 끝 표시예요. 0 뒤의 줄은 읽지 않아요while (x != 0){ nums.Add(x); x = Console.ReadLine().ToNumber();} total = 0;// 번호 없이 값을 하나씩foreach (v in nums){ total += v;}Console.WriteLine(total); // 마지막 번호부터 0번까지for (i = nums.Count - 1; i >= 0; i--){ Console.WriteLine(nums[i]);} digits = 0;// do-while이 없어서: 먼저 한 번 하고 끝에서 확인해요while (true){ digits++; total = Mathf.Quot(total, 10); if (total == 0) { break; }}Console.WriteLine(digits);12 7 30 0 99
49 30 7 12 2
Key points
- A for-each loop hands you each value directly, with no index.
There is no index to get wrong, so it is the safest choice when you look at everything from first to last.
Use an index when you need the position or want to go backwards. - Counting down flips the start, the condition and the step.
Start at the last index,count - 1, keep going whilei >= 0, and step withi--. - A sentinel loop is for input that does not tell you how many values there are but ends with an agreed value, such as "0 means stop".
Read one value first, process while it is not the marker, and read the next value at the end of each lap.
The marker itself is not processed. - With no marker at all, read until the input ends, the form you met in the Reading input lesson.
It has the same shape as the sentinel loop; only the condition changes to "did the read succeed?". - A do-while runs its body once first and checks the condition at the end, so it always runs at least once.
Counting digits is that kind of job: 0 has one digit, butwhile (total != 0)never runs for 0 and answers zero digits. - Python and Craykon have no do-while.
Do the work first inside an endless loop, then check the condition at the end and leave: it behaves the same.
How each language writes it
| Python | for v in nums:; backwards with for v in reversed(nums): or by index with range(len(nums) - 1, -1, -1).Sentinel: while x != 0:; until the input ends: for line in sys.stdin:.There is no do-while, so use if cond: break inside while True: |
|---|---|
| JavaScript | for (const v of nums); backwards with for (let i = nums.length - 1; i >= 0; i--).nums.reverse() reverses the original list itself.do { } while (cond); ends with a ;.Read all the input at once, split it into a list of lines and take them by index. Until the input ends: split with .trim().split("\n") and walk the whole list with for (const line of lines) |
| TypeScript | Same as JavaScript |
| Java | for (int v : nums); backwards with for (int i = nums.size() - 1; i >= 0; i--) (nums.length for an array).do { } while (cond);.Until the input ends: while (sc.hasNextInt()) |
| C# | foreach (int v in nums); backwards with for (int i = nums.Count - 1; i >= 0; i--).do { } while (cond);.Until the input ends: while ((line = Console.ReadLine()) != null) |
| C++ | for (int v : nums); backwards with for (int i = (int)nums.size() - 1; i >= 0; i--) — size() is unsigned, so convert it to int.do { } while (cond);.Until the input ends: while (std::cin >> x) |
| C | There is no for-each form, so for (int i = 0; i < n; i++); backwards with for (int i = n - 1; i >= 0; i--).do { } while (cond);.Until the input ends: while (scanf("%d", &x) == 1) |
| Craykon | foreach (v in nums); backwards with for (i = nums.Count - 1; i >= 0; i--).Sentinel: while (x != 0); until the input ends: loop until ReadLine() gives null (while (line != null)).There is no do-while, so while (true) { … if (cond) { break; } } |
Common mistakes
Counting down with an unsigned indexC · C++
std::vector<int> nums = {12, 7, 30};
for (size_t i = nums.size() - 1; i >= 0; i--) {
std::cout << nums[i] << '\n';
}→ It prints 30, 7, 12 and does not stop. Subtracting 1 from an unsigned i at 0 gives 18446744073709551615, not -1, so i >= 0 is always true. After that it reads outside the list, which is undefined behaviour: nothing says what will happen. On the judge it printed a stream of junk values and then died with Segmentation fault
Loop with a signed integer: int i = (int)nums.size() - 1.
To stay unsigned, write for (size_t i = nums.size(); i-- > 0; ).
Using a variable made inside the do-while body in its conditionJava · C# · C · C++ · JavaScript · TypeScript
int total = 0;
do {
int x = sc.nextInt();
total += x;
} while (x != 0);→ A compile error (Java: cannot find symbol). An x created inside { } disappears at the closing brace, so the condition after it cannot see it. TypeScript rejects it at compile time too (Cannot find name 'x'), and JavaScript stops at run time with ReferenceError: x is not defined
Create the variable before the do: int x; and then do { x = sc.nextInt(); … } while (x != 0);.
Expecting the list to change when you change the for-each variablePython · JavaScript · TypeScript · Java · C# · C++ · Craykon
nums = [1, 2, 3]
for v in nums:
v = v * 2
print(nums)→ [1, 2, 3] — unchanged. v is only a variable holding the value that was taken out, so changing v does not change the slot in the list. JavaScript (for (let v of nums)), Java, C++ (for (int v : nums)) and Craykon leave the list unchanged in the same way. C# refuses the assignment to a foreach variable with a compile error (CS1656)
To change the slots, loop by index and write nums[i] = nums[i] * 2.
In C++, taking the value as for (int& v : nums) changes the original.
Removing values from a list while walking it is covered in the Editing lists lesson.
Choosing is simple.
Looking at everything from first to last: for-each.
Need the position or going backwards: an index.
Don't know how many laps:
while.Must happen at least once: do-while.
When reading up to a marker, keep the order "read → check → process → read again".
If processing comes before the check, the marker gets added in too.