{ }codelper

Learn › Craykon

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 = 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);
stdin
12
7
30
0
99
stdout
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 while i >= 0, and step with i--.
  • 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, but while (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

Pythonfor 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:
JavaScriptfor (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)
TypeScriptSame as JavaScript
Javafor (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)
CThere 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)
Craykonforeach (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

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.

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);.

How languages differ
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.

Practice