Going further · 22
Common mistakes and error messages
How to read error messages, and the mistakes every language shares: off-by-one, = vs ==, integer division, null, out-of-range indexes.
Some mistakes show up in every language.
Learn them together with how to read error messages.
The example below checks that an index is in range and that the divisor isn't 0 before using them.
def get(a, i): if 0 <= i < len(a): # a[-1]도 막아요(Python에서는 마지막 값) return a[i] return None def safe_div(x, y): if y == 0: return None return x // y n = int(input())a = list(map(int, input().split()))input()for i in map(int, input().split()): v = get(a, i) if v is None: # if not v: 로 쓰면 0도 걸려요 print(f"a[{i}]: out of range") else: print(f"a[{i}] = {v}")x, y = map(int, input().split())q = safe_div(x, y)print(f"{x} / {y}: cannot divide" if q is None else f"{x} / {y} = {q}")print(f"average {sum(a) / n:.1f}")const tok = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let p = 0;const n = tok[p++];const a = tok.slice(p, (p += n));const q = tok[p++];const idx = tok.slice(p, (p += q));const [x, y] = tok.slice(p, p + 2); // a[7]은 오류 없이 undefined라서 직접 검사해요const get = (arr, i) => (i >= 0 && i < arr.length ? arr[i] : null);const safeDiv = (u, v) => (v === 0 ? null : Math.trunc(u / v)); // u / 0은 Infinity for (const i of idx) { const v = get(a, i); console.log(v === null ? `a[${i}]: out of range` : `a[${i}] = ${v}`);}const d = safeDiv(x, y);console.log(d === null ? `${x} / ${y}: cannot divide` : `${x} / ${y} = ${d}`);let sum = 0;for (let i = 0; i < n; i++) sum += a[i]; // <= n 이면 undefined를 더해 NaNconsole.log(`average ${(sum / n).toFixed(1)}`);import { readFileSync } from "node:fs";const tok: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let p = 0;const n = tok[p++];const a = tok.slice(p, (p += n));const q = tok[p++];const idx = tok.slice(p, (p += q));const [x, y] = tok.slice(p, p + 2); // a[7]은 오류 없이 undefined라서 직접 검사해요const get = (arr: number[], i: number): number | null => (i >= 0 && i < arr.length ? arr[i] : null);const safeDiv = (u: number, v: number): number | null => (v === 0 ? null : Math.trunc(u / v)); for (const i of idx) { const v = get(a, i); console.log(v === null ? `a[${i}]: out of range` : `a[${i}] = ${v}`);}const d = safeDiv(x, y);console.log(d === null ? `${x} / ${y}: cannot divide` : `${x} / ${y} = ${d}`);let sum = 0;for (let i = 0; i < n; i++) sum += a[i]; // <= n 이면 undefined를 더해 NaNconsole.log(`average ${(sum / n).toFixed(1)}`);import java.util.Scanner; public class Main { // int에는 null을 못 담아서 Integer로 돌려줘요 static Integer get(int[] a, int i) { if (i >= 0 && i < a.length) return a[i]; // 안 막으면 ArrayIndexOutOfBoundsException return null; } static Integer safeDiv(int x, int y) { if (y == 0) return null; // 안 막으면 ArithmeticException return x / y; } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] a = new int[n]; int sum = 0; for (int i = 0; i < n; i++) { // i <= n 이면 한 칸 넘어가요 a[i] = in.nextInt(); sum += a[i]; } int q = in.nextInt(); for (int t = 0; t < q; t++) { int i = in.nextInt(); Integer v = get(a, i); System.out.println(v == null ? "a[" + i + "]: out of range" : "a[" + i + "] = " + v); } int x = in.nextInt(), y = in.nextInt(); Integer d = safeDiv(x, y); System.out.println(x + " / " + y + (d == null ? ": cannot divide" : " = " + d)); System.out.println(String.format("average %.1f", (double) sum / n)); // sum / n은 2 }}using System;using System.Linq; class Program{ // int?는 '수 또는 null'이에요 static int? Get(int[] a, int i) => i >= 0 && i < a.Length ? a[i] : null; // 안 막으면 IndexOutOfRangeException static int? SafeDiv(int x, int y) => y == 0 ? null : x / y; // 안 막으면 DivideByZeroException static void Main() { int n = int.Parse(Console.ReadLine()); int[] a = Console.ReadLine().Split(' ').Select(int.Parse).ToArray(); Console.ReadLine(); foreach (int i in Console.ReadLine().Split(' ').Select(int.Parse)) { int? v = Get(a, i); Console.WriteLine(v is null ? $"a[{i}]: out of range" : $"a[{i}] = {v}"); } int[] xy = Console.ReadLine().Split(' ').Select(int.Parse).ToArray(); int? d = SafeDiv(xy[0], xy[1]); Console.WriteLine($"{xy[0]} / {xy[1]}" + (d is null ? ": cannot divide" : $" = {d}")); Console.WriteLine($"average {((double)a.Sum() / n).ToString("F1")}"); // a.Sum() / n은 2 }}#include <cstdio>#include <iostream>#include <optional>#include <vector> // optional<int>는 '수 또는 없음'이에요std::optional<int> get(const std::vector<int>& a, int i) { if (i < 0 || i >= (int)a.size()) return std::nullopt; // a[i]는 검사 안 함, a.at(i)는 예외 return a[i];} std::optional<int> safeDiv(int x, int y) { if (y == 0) return std::nullopt; // 0으로 나누면 정의되지 않은 동작 return x / y;} int main() { int n, q, x, y; std::cin >> n; std::vector<int> a(n); long long sum = 0; // = 0 을 빼면 쓰레기 값에서 시작해요 for (int& v : a) std::cin >> v, sum += v; std::cin >> q; for (int t = 0; t < q; t++) { int i; std::cin >> i; if (auto v = get(a, i)) std::cout << "a[" << i << "] = " << *v << '\n'; else std::cout << "a[" << i << "]: out of range\n"; } std::cin >> x >> y; if (auto d = safeDiv(x, y)) std::cout << x << " / " << y << " = " << *d << '\n'; else std::cout << x << " / " << y << ": cannot divide\n"; std::printf("average %.1f\n", (double)sum / n); // sum / n은 2}#include <stdbool.h>#include <stdio.h> /* C에는 null 정수가 없어서 성공 여부(bool)와 값(*out)을 따로 돌려줘요 */bool get(const int *a, int n, int i, int *out) { if (i < 0 || i >= n) return false; /* 안 막으면 정의되지 않은 동작 */ *out = a[i]; return true;} int main(void) { int n, q, x, y, v; int a[100]; int sum = 0; /* = 0 을 빼면 쓰레기 값에서 시작해요 */ scanf("%d", &n); if (n < 1 || n > 100) return 1; /* 배열 크기를 넘지 않게 */ for (int i = 0; i < n; i++) { /* i <= n 이면 한 칸 넘어가요 */ scanf("%d", &a[i]); sum += a[i]; } scanf("%d", &q); for (int t = 0; t < q; t++) { int i; scanf("%d", &i); if (get(a, n, i, &v)) printf("a[%d] = %d\n", i, v); else printf("a[%d]: out of range\n", i); } scanf("%d %d", &x, &y); if (y == 0) printf("%d / %d: cannot divide\n", x, y); /* 0으로 나누면 정의되지 않은 동작 */ else printf("%d / %d = %d\n", x, y, x / y); printf("average %.1f\n", (double)sum / n); /* sum / n은 2 */ return 0;}get(a, i){ if (i >= 0 && i < a.Count) { return a[i]; } return null;} n = Console.ReadLine().ToNumber();a = Console.ReadNumbers();q = Console.ReadLine().ToNumber();foreach (i in Console.ReadNumbers()){ v = get(a, i); if (v == null) { Console.WriteLine("a[" + i + "]: out of range"); } else { Console.WriteLine("a[" + i + "] = " + v); }}xy = Console.ReadNumbers();if (xy[1] == 0){ Console.WriteLine(xy[0] + " / " + xy[1] + ": cannot divide");}else{ Console.WriteLine(xy[0] + " / " + xy[1] + " = " + Mathf.Quot(xy[0], xy[1]));}합 = 0;for (k = 0; k < a.Count; k++){ 합 += a[k];}Console.WriteLine("average " + Str.Fixed(합 / n, 1));5 3 1 4 1 5 3 2 7 -1 7 0
a[2] = 4 a[7]: out of range a[-1]: out of range 7 / 0: cannot divide average 2.8
Key points
- In an error message, look for the error name, the reason and the line number.
In Python, read from the bottom line. - In compiled languages (C, C++, Java, C#), fix the first error first, even when there are many.
The later ones are often knock-on effects. - Indexes run from 0 to
n - 1, so a loop needsi < n.
Writingi <= nsteps one past the end: the off-by-one error. =stores,==compares.- Before dividing, check the divisor isn't 0.
Before using a value, check it isn't null. - Give every variable a starting value when you create it (
int sum = 0;).
How each language writes it
| Python | The last line has the name and reason, like IndexError: list index out of range, with the line number just above.Dividing by 0 raises ZeroDivisionError, calculating with None raises TypeError, an unknown name raises NameError.a[-1] isn't an error but the last item, and if not v: also catches 0 (ask v is None) |
|---|---|
| JavaScript | An out-of-range index gives undefined with no error, and 7 / 0 is Infinity."No value" is null and undefined, and undefined + 1 is NaN while null + 1 is 1, so it goes quietly wrong.Compare with === ("1" == 1 is true) |
| TypeScript | Same as JavaScript |
| Java | The first line is ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 5, and at Main.main(Main.java:12) below gives the line.Dividing by 0 throws ArithmeticException, null throws NullPointerException (int can't hold it, so use Integer).A variable with no starting value is a compile error: "might not have been initialized" |
| C# | Out of range throws IndexOutOfRangeException, dividing by 0 throws DivideByZeroException."No value" is int?.A variable with no starting value is compile error CS0165 |
| C++ | a[i] doesn't check, so out of range is undefined behaviour; a.at(i) throws std::out_of_range.Integer division by 0 is undefined behaviour too (usually a crash). "No value" is std::optional.int sum; starts with a garbage value |
| C | Arrays aren't checked, so out of range is undefined behaviour: a garbage value, another variable overwritten, or a crash. Division by 0 and uninitialized locals behave as in C++ |
| Craykon | Out of range stops with "List only has indexes 0–4".7 / 0 is Infinity; Mathf.Quot(7, 0) stops with "Can't divide by 0".null + 1 stops with "Can't calculate with null" (joined to text it shows as 빈값), and an unknown name "hasn't been created yet" |
Common mistakes
i <= n stepped past the endC · C++ · Java · C# · JavaScript · TypeScript
int sum = 0;
for (int i = 0; i <= n; i++)
sum += a[i];→ Java and C# throw an out-of-range exception, JavaScript adds undefined and gets NaN, and C quietly adds a garbage value
Write i < n.
The average came out wholeJava · C# · C · C++
int sum = 7, n = 2;
double avg = sum / n;→ avg is 3.0: 7 / 2 is integer division, so the fraction is dropped first
Convert one side first: (double)sum / n.
= instead of ==C · C++ · JavaScript
if (x = 5) {
puts("five");
}→ No error: 5 is stored in x and the condition is always true (gcc -Wall warns about it)
Compare with ==.
Java and C# refuse to compile, Python raises SyntaxError (since 3.10: "Maybe you meant '=='"), and Craykon rejects it as a syntax error.
An error that stops your program is actually a favour.
The truly scary cases give a wrong value with no error, like out-of-range access in C/C++ or
undefined in JavaScript.