우선순위, 비트 연산, 삼항, break 없는 switch, static 지역변수, 진법. 짧은 코드에 함정 하나씩이다
<< 는 곱셈, & 와 && 는 다른 것, switch 는 break 없으면 흘러내리고, static 은 남는다. 규칙 10개를 표로 굳히고 기출 11문항에 대 본다.왜 이걸 하나 — C 42문항 중 11문항이 이 장이고, 짧아서 시간이 덜 드는 5점이다. 규칙만 맞으면 30초짜리다.
11회분 220문항 중 이 장의 기출은 11문항이다. 11회 중 8회에 나왔고 2023년 2회 · 2025년 3회에 2문항씩이었다. 훈련 C 10문항(5 · 6 · 11 · 14~16 · 20~22 · 27 · 30)이 붙는다.
| 꼴 | 몇 문항 | 무엇을 적나 | 보기 |
|---|---|---|---|
| 연산자 식 계산 | 4 | 시프트 · 삼항 · 비트 AND · 논리 · unsigned · XOR | 2024-1회 2번 · 2025-1회 19번 · 2025-3회 15번 · 17번 |
| switch 흘러내림 | 2 | break 없는 case 의 출력 · 누적 | 2023-2회 10번 · 2024-2회 10번 |
| 반복 누적 · 판별 | 2 | 배수 세기 · 완전수 합 | 2023-2회 4번 · 2023-3회 9번 |
| 빈칸 — 식 | 2 | 진법 변환의 % 와 자리값, 나눗셈 · 나머지 식 4개 | 2023-1회 9번 · 2023-2회 13번 |
| static 지역변수 | 1 | 호출마다 누적된 값의 합 | 2024-3회 6번 |
→ 11문항 중 답이 숫자 하나인 것이 8문항이다. 계산이 짧은 만큼 규칙을 하나만 잘못 알아도 통째로 틀리고, 부분 점수도 없다. 2023년 2회 13번(식 4개)만 소문항이 있다.
E01 진단에 이 장 문항은 없었다. 그러나 2025년 3회에 2문항(비트 · unsigned)이 나왔고 2026년에는 안 나왔으니, 3회에 다시 나올 자리로 본다. 03절의 규칙 표를 외우면 이 장은 끝난다.
문항 수는 이 노트의 문제 데이터에서 ch=E04 인 것을 센 값이다(2026-09-14). 2023-2회 13번은 grandlife 복원이 Java 코드라 그대로 실었다(식 자체는 C 와 같다). 11문항 전부 실행하거나 빈칸을 채워 실행해 정답을 확인했다.
왜 이걸 하나 — 시험 전날 규칙 10개를 다시 본다.
++ -- ! ~ * & 주소) → * / % → + - → 시프트 << >> → 비교 < > <= >= → == != → 비트 & → ^ → | → 논리 && → || → 삼항 ?: → 대입. 비트 & 는 == 보다 낮다.x << n = x × 2ⁿ, x >> n = x ÷ 2ⁿ(내림). 37 << 2 = 148.& 둘 다 1 · | 하나라도 1 · ^ 다르면 1 · ~ 뒤집기. 2진수 8자리로 펴서 자리마다 계산. 12 & 10 = 8, 12 | 10 = 14, 12 ^ 10 = 6.&& 는 둘 다 참, || 는 하나라도. 0 이 아니면 참. &(비트)와 &&(논리)는 다른 연산자.조건 ? A : B. x++ 는 쓰고 나서 증가, ++x 는 증가하고 나서 씀. i++ + ++i 같은 식은 왼쪽부터 값을 적으며 간다.7 / 2 = 3, 7 % 2 = 1. 금액 분해는 m / 1000, (m % 1000) / 500 …. 자릿수 분리는 n % 10 과 n /= 10.% 10 으로 떼어 place(1 · 2 · 4 …)를 곱해 더한다. 10진수 → 2진수: % 2 로 떼어 거꾸로. 16진수 A~F = 10~15, 0xA5 = 1010 0101.%u 로 찍는다. 5u · 7u 는 unsigned 상수.왜 이걸 하나 — 규칙 10개는 2진수 한 줄과 흐름 한 줄이면 전부 그려진다.
비트 연산은 숫자를 2진수로 펴 놓고 같은 자리끼리 계산한다. 12 는 1100, 10 은 1010 이라 AND 는 둘 다 1 인 자리만 → 1000 = 8, OR 는 하나라도 1 → 1110 = 14, XOR 는 다르면 1 → 0110 = 6(예상 1회 6번). 시프트는 자리를 옮기는 것이라 왼쪽 n 칸은 2ⁿ 배, 오른쪽 n 칸은 2ⁿ 으로 나눈 몫이다.
2024년 1회 2번은 삼항과 시프트다. x = 37 은 20 보다 크니 x << 2 = 148, 거기에 3 을 더해 151. 2025년 1회 19번은 value & 0xA5 로 점수마다 1010 0101 자리만 남긴다 — 0xDB(1101 1011) & 0xA5 = 1000 0001 = 129 처럼 한 값씩 표로 계산해 합하면 908 이다. 16진수 한 자리가 2진수 네 자리라는 것만 알면 된다.
2025년 3회 15번은 & 와 && 가 한 식에 있다. y % 3 < 3 은 1 < 3 참이라 z = 2, z & z >> 1 은 시프트가 먼저라 2 & 1 = 0, 마지막 삼항에서 x > 5 && z <= 3 이 참이라 z × x = 0. 비트 & 는 시프트보다 늦고 논리 && 는 비교보다 늦다는 우선순위가 답을 정한다.
switch 는 맞는 case 로 뛰어 들어간 뒤 break 를 만날 때까지 아래로 계속 실행한다. 2023년 2회 10번은 total 240 을 30 으로 나눈 8 이라 case 8 부터 시작해 B · C · D 를 전부 찍는다(A 는 위라 안 찍힘). 2024년 2회 10번은 7 % 3 = 1 이라 case 1 부터 −7 − 4 − 2 = −13 이다.
case 값이 겹쳐 적힌 것(case 10: case 9:)은 둘 중 어느 값이든 같은 자리에서 시작한다는 뜻이다. break 가 하나도 없는 switch 는 「시작점만 정하고 아래는 전부」라고 읽으면 틀리지 않는다.
함수 안의 static int value = 0; 은 첫 호출 때 한 번만 0 이 되고 그 뒤로는 이전 호출의 값이 남는다. 2024년 3회 6번의 next_value 는 부를 때마다 2 · 4 · 6 · 8 을 돌려주고 합이 20 이다. main 에도 value 라는 변수가 있지만 이름만 같은 다른 변수라 서로 건드리지 않는다(훈련 11 · 27번).
반복 누적 문제는 조건이 전부다. 2023년 2회 4번은 1~2023 에서 4 의 배수를 세면 2023 / 4 = 505 이고, 2023년 3회 9번은 1~100 의 완전수(약수 합이 자기 자신: 6 · 28)를 더해 34 다. 반복 변수의 시작 · 끝 · 증가폭과 조건식을 표에 적으면 손으로도 센다.
2진수 101110 을 10진수로 바꾸는 코드(2023년 1회 9번)는 아래 자리부터 input % 10 으로 한 자리를 떼고, 자리값 place 를 1 · 2 · 4 · 8 로 키우며 곱해 더한다. 빈칸은 % 와 2(place *= 2)이고, 채워 돌리면 46 이 나온다. 거꾸로 10진수 → 2진수는 % 2 로 떼어 뒤에서부터 적는다(훈련 30번).
금액 4620 을 1000 · 500 · 100 · 10 으로 나누는 식(2023년 2회 13번)은 큰 단위부터 몫을 취하고 나머지를 다음 단위로 넘긴다 — money / 1000 = 4, (money % 1000) / 500 = 1, (money % 500) / 100 = 1, (money % 100) / 10 = 2. 정수 나눗셈이 몫만 남긴다는 것이 이 식의 근거다.
unsigned(2025년 3회 17번)는 음수가 없는 정수다. 이 문제는 되감김이 없고 리스트 값을 sum × 3 + value 로 모아 125 를 만든 뒤 42 와 XOR 해 87, 100 을 더해 187 이다. XOR 도 2진수로 펴서 자리마다 다르면 1 로 계산한다.
& 는 비트끼리, && 는 참 · 거짓끼리다. 2 & 1 은 0(0010 과 0001 은 겹치는 자리가 없다)이지만 2 && 1 은 1(둘 다 0 이 아니라 참). 2025년 3회 15번이 이 둘을 한 식에 넣었다.왜 이걸 하나 — 규칙 10개를 기출 11문항에 하나씩 대 본다. 어느 규칙이 빠졌는지 정답을 열면 보인다.
비트 식은 2진수 8자리를 종이에 적고, switch 는 시작 case 에 표시를 하고 아래로 선을 긋고, 반복문은 변수 표를 그린다. 답이 숫자 하나라도 과정을 답 칸에 적어 두면 틀린 자리가 남는다.
다음 C 프로그램에서 ①과 ②에 들어갈 연산자와 값을 순서대로 쓰시오.
답 — ① % ② 2. 2진수로 적힌 수 101110 을 10진수 46 으로 바꾸는 코드다.
원리 — 2진수 101110 은 자리마다 값이 다르다. 오른쪽 끝 자리는 1, 그다음은 2, 4, 8, 16, 32 다. 그러니 10진수로 바꾸려면 "각 자리의 숫자 × 그 자리의 값"을 전부 더하면 된다. 코드는 input 을 10 으로 나눈 나머지(input % 10)로 맨 오른쪽 자리를 떼어 내고, input /= 10 으로 그 자리를 버린다. 자리 값 place 는 1 에서 시작해 자리를 옮길 때마다 2배(place *= 2)가 된다. 그래서 ① 은 한 자리를 떼는 나머지 연산, ② 는 자리 값을 키우는 2 다.
따라가기 — input = 101110, place = 1, sum = 0.
헷갈리는 자리 — ② 에 10 을 적는 것. 10 을 곱하면 101110 을 그대로 다시 만드는 셈이라 아무 변환도 안 된다. 2진 → 10진은 자리 값이 2배씩이라 2 다. ① 에 / 를 적으면 자리를 떼는 게 아니라 버리는 것이라 값이 커진다. 답은 기호 하나와 숫자 하나다.
빈칸에 답을 넣어 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 505. 1 부터 2023 까지 4 의 배수가 몇 개인지 세는 코드이고, 2023 ÷ 4 = 505.75 이므로 505 개다.
원리 — number % 4 == 0 은 "4 로 나눠 나머지가 없다", 즉 4 의 배수라는 뜻이다. 1 부터 N 까지 k 의 배수 개수는 N 을 k 로 나눈 몫이다 — 4, 8, 12, … 처럼 k 칸마다 하나씩 있기 때문이다. 코드는 2023 번 반복하며 하나씩 세지만 손으로는 나눗셈 한 번이면 된다. 시험에서는 반복문을 실제로 돌리지 말고 "무엇을 세는가"를 읽어 수식으로 바꾸는 것이 시간을 아끼는 길이다.
따라가기
number <= 2023)헷갈리는 자리 — 505.75 를 반올림해 506 으로 적는 것. 마지막 배수 2020 뒤에 2024 는 없으니 몫만 센다. 범위가 < 2023 이어도 2023 은 배수가 아니라 답이 같지만, 2024 까지였다면 506 이다 — 끝 값이 배수인지 확인하는 습관을 둔다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — BCD. 합 240 을 30 으로 나눈 몫 8 에서 시작해, break 가 없어 그 아래 case 를 전부 지나간다.
원리 — switch 는 값이 맞는 case 로 뛰어든 뒤 break 를 만날 때까지 아래로 계속 흘러내린다. 이 코드에는 break 가 하나도 없으므로 case 8 에 들어가면 그 아래의 case 7 · 6 · default 까지 전부 실행된다. 이름표(case)는 "여기서부터 시작"을 정할 뿐 "여기까지"를 정하지 않는다. 정수 나눗셈 total / 30 은 소수점을 버리므로 240 / 30 = 8 이다.
따라가기
헷갈리는 자리 — B 만 적는 것(break 가 있을 때의 답). 그리고 A 부터 적는 것 — 8 은 case 10 · 9 를 거치지 않고 case 8 로 바로 들어간다. 위쪽은 안 지나가고 아래쪽만 흘러내린다는 방향을 기억한다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
금액 4,620원을 1,000원, 500원, 100원, 10원 단위로 나눌 때 각 개수를 구하는 ①부터 ④의 식을 쓰시오.
답 — ① money / 1000 ② (money % 1000) / 500 ③ (money % 500) / 100 ④ (money % 100) / 10. 큰 단위부터 몫을 세고, 나머지를 다음 단위로 넘긴다.
원리 — 4,620원을 지폐와 동전으로 바꾸는 절차 그대로다. 1,000원짜리는 4,620 을 1,000 으로 나눈 몫(4장). 남은 돈은 4,620 을 1,000 으로 나눈 나머지 620 이고, 그것을 500 으로 나눈 몫이 500원짜리(1개). 다시 나머지 120 을 100 으로 나눈 몫이 100원(1개), 나머지 20 을 10 으로 나눈 몫이 10원(2개). 정수 나눗셈 / 은 "몇 개", 나머지 % 는 "남은 돈"이다. 앞 단위의 나머지가 다음 단위의 입력이 되는 사슬이라 식마다 % 앞 단위 가 붙는다.
따라가기
헷갈리는 자리 — ② 를 money / 500 으로 적으면 9 가 된다(1,000원짜리로 이미 낸 돈을 또 센다). 나머지를 먼저 취해야 한다. money % 500 / 100 처럼 괄호를 빼도 % 와 / 는 같은 순위라 왼쪽부터 계산돼 결과는 같지만, 답안에는 괄호를 넣는 편이 안전하다.
빈칸에 답을 넣어 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 34. 2 부터 100 사이의 완전수는 6 과 28 뿐이고 그 합이 34 다.
원리 — 완전수는 자기 자신을 뺀 약수를 전부 더하면 자기 자신이 되는 수다. 6 의 약수 1 · 2 · 3 은 더하면 6 이다. isPerfect 는 1 부터 number / 2 까지 나눠떨어지는 수(약수)를 더해 number == total 인지 돌려준다. 자기 자신보다 큰 약수는 없고 자기 자신의 절반보다 큰 약수도 자기 자신뿐이라 절반까지만 본다. main 은 2 부터 100 까지 그 검사를 돌려 참인 수를 result 에 더한다. C 에서 비교식은 참이면 1, 거짓이면 0 이라 return number == total 이 그대로 조건이 된다.
따라가기
헷갈리는 자리 — 1 을 완전수로 세는 것. 1 의 약수 합은 0 이라 아니고, 어차피 반복이 2 부터 시작한다. 2 부터 100 을 손으로 다 돌리지 말고 "완전수 6 · 28 · 496 · 8128" 네 개를 외워 두면 이 유형은 즉답이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 151. 37 은 20 보다 크므로 왼쪽 시프트 37 << 2 = 148 이 y 가 되고, 3 을 더한다.
원리 — 삼항 연산자 조건 ? A : B 는 조건이 참이면 A, 거짓이면 B 를 고르는 한 줄짜리 if 다. 비트 시프트 << n 은 2진수 자릿수를 왼쪽으로 n 칸 미는 것이고, 그 결과는 값이 2ⁿ 배가 된다. 오른쪽 >> n 은 2ⁿ 으로 나눈 몫이다. 그래서 x << 2 는 × 4, x >> 1 은 ÷ 2 로 읽으면 2진수를 안 적어도 된다.
따라가기
x << 2 선택헷갈리는 자리 — 조건이 거짓인 쪽(37 >> 1 = 18)까지 계산해 섞는 것. 삼항은 한쪽만 계산한다. 시프트를 "2를 더한다"로 착각해 39 를 적는 것도 흔하다 — 시프트는 곱하기 · 나누기다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — −13. 7 % 3 = 1 이라 case 1 로 들어가고, break 가 없어 default 까지 흘러내려 −7 − 4 − 2 다.
원리 — int result = -value 로 출발점이 음수(−7)다. switch 는 맞는 case 로 뛰어든 뒤 break 가 없으면 아래 case 를 전부 실행한다. 이 코드는 case 0 · 1 · default 어디에도 break 가 없으니 진입한 자리부터 끝까지 다 더하고 뺀다. 7 을 3 으로 나눈 나머지는 1 이므로 case 0 의 += 3 은 건너뛰고 case 1 부터다. 음수에서 빼면 더 작아진다는 것만 조심하면 된다.
따라가기
헷갈리는 자리 — case 0 의 +3 까지 넣어 −10 으로 적는 것(위쪽 case 는 안 지나간다). break 가 있다고 넘겨짚어 −11 로 적는 것. 답의 음수 기호를 빼먹는 것. 세 함정이 한 문제에 있다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 20. static 변수는 함수가 끝나도 값을 기억하므로 next_value 는 2 · 4 · 6 · 8 을 차례로 돌려주고, 그 합이 20 이다.
원리 — 보통의 지역 변수는 함수가 불릴 때 새로 만들어지고 끝나면 사라진다. 그런데 static int value = 0 은 프로그램이 시작할 때 한 번만 0 으로 만들어지고, 함수가 끝나도 지워지지 않고 다음 호출 때 이어서 쓴다. 그래서 부를 때마다 2 씩 쌓인다. main 에도 value 라는 변수가 있지만 이름만 같을 뿐 다른 칸이고, main 의 value 는 어디에도 쓰이지 않는 미끼다.
따라가기
헷갈리는 자리 — static 을 무시해 매번 0 에서 시작한다고 보면 2 × 4 = 8 이 된다. main 의 value++ 를 함수 안 value 와 섞어 계산하는 것 — 이름이 같아도 범위가 다르면 남남이다. 함수 안의 value 는 밖에서 볼 수도 없다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 908. 점수 여섯 개를 각각 0xA5 와 비트 AND 한 값의 합이고, 두 학생 모두 454 다.
원리 — 비트 AND(&)는 두 수를 2진수로 나란히 놓고 자리마다 둘 다 1 일 때만 1 을 남긴다. 0xA5 는 2진수 1010 0101 이라 "그 자리들만 남기는 거름망"이다. 16진수 한 자리는 2진수 네 자리이므로 A = 1010, 5 = 0101, D = 1101, B = 1011, E = 1110, 8 = 1000, 1 = 0001, 0 = 0000 으로 펴서 자리별로 맞춘다. 구조체 배열 두 개를 돌며 각 학생의 세 점수를 거른 뒤 전부 더한다.
따라가기 — 거름망 1010 0101.
헷갈리는 자리 — AND 를 "둘 중 하나라도 1"(OR)로 계산하는 것과, 16진수를 10진수로 먼저 바꾼 뒤 논리 AND(&&)처럼 다루는 것. 한 자리씩 2진수로 펴서 겹치는 1 만 남기는 것이 전부이고, 마지막에 10진수로 돌린다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 0. 둘째 줄에서 z & z >> 1 이 2 & 1 = 0 이 되고, 그 뒤로는 0 에 무엇을 곱해도 0 이다.
원리 — 한 줄에 연산자가 여럿이면 우선순위가 계산 순서를 정한다. 산술(%) → 시프트(>>) → 비교(<, >) → 비트 AND(&) → 논리 AND(&&) → 삼항(?:) 순이다. 둘째 줄 z & z >> 1 은 시프트가 먼저라 z & (z >> 1) 이다. 셋째 줄은 && 가 삼항보다 먼저 묶여 (x > 5 && z <= 3) ? z * x : z / x 로 읽는다.
따라가기 — x = 7, y = 4.
헷갈리는 자리 — 둘째 줄을 (z & z) >> 1 로 읽어 1 을 얻는 것. 비트 AND 는 시프트보다 나중이다. 셋째 줄에서 조건이 거짓이라고 보고 z / x 로 가도 0 / 7 = 0 이라 답은 같지만, 이유가 다르면 다음 문제에서 틀린다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 187. 리스트를 11 → 7 → 5 순서로 돌며 sum = sum × 3 + 값 으로 125 를 만들고, 42 와 XOR 한 87 에 100 을 더한다.
원리 — sum = sum * 3 + value 는 "지금까지의 결과를 3배 하고 새 값을 더한다"로, 값을 3진수 자릿수처럼 쌓는 식이다. 사슬은 n3 → n2 → n1(next 대입 두 줄)이라 값 순서는 11 · 7 · 5 다. XOR(^)는 두 수를 2진수로 놓고 자리가 다르면 1, 같으면 0 이다. unsigned 는 음수를 안 쓰는 정수라는 뜻일 뿐 여기선 값에 영향이 없고, %u 로 그대로 찍는다.
따라가기
헷갈리는 자리 — 사슬을 n1 → n2 → n3(5 · 7 · 11)로 돌려 sum 을 5 → 22 → 77 로 만드는 것. cur 의 시작이 n3 이고 n3.next = n2, n2.next = n1 이다. XOR 를 OR(127)나 AND(40)로 계산하는 것도 흔하다 — "다르면 1"이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 코드의 출력을 쓰시오.
답 — 8 14 6. 12 = 1100, 10 = 1010 을 비트 단위로 AND · OR · XOR 한 값이다.
원리 — 비트 연산은 두 수를 2진수로 놓고 같은 자리끼리 계산한다. AND(&)는 둘 다 1 일 때만 1, OR(|)는 하나라도 1 이면 1, XOR(^)는 서로 다를 때만 1 이다. 12 는 8+4 = 1100, 10 은 8+2 = 1010 이다. 자리별로 보면 8의 자리는 둘 다 1, 4의 자리는 12 만, 2의 자리는 10 만, 1의 자리는 둘 다 0 이다. AND 는 8의 자리만 남아 8, OR 는 8+4+2 = 14, XOR 는 4+2 = 6 이다. 2진수로 바꿔 세로로 놓고 푸는 것이 가장 안 틀린다.
따라가기
헷갈리는 자리 — & 와 && 를 섞는 것. && 는 논리 AND 라 12 && 10 은 1 이다. 한 글자면 비트, 두 글자면 논리다. 그리고 XOR 는 "같은 수를 두 번 XOR 하면 원래대로" 라는 성질(a ^ b ^ b = a)이 있어 값 교환 · 암호 문제에 나온다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
다음 코드의 출력을 쓰시오.
답 — 9. 36 의 약수 1 · 2 · 3 · 4 · 6 · 9 · 12 · 18 · 36 이 아홉 개다.
원리 — n % i == 0 은 "n 을 i 로 나눈 나머지가 0" 곧 i 가 n 의 약수라는 뜻이다. 1 부터 n 까지 전부 나눠 보며 약수를 세는 가장 단순한 방법이다. 36 = 2² × 3² 이라 약수 개수는 (2+1)(2+1) = 9 로 공식으로도 확인된다. 반복 범위가 i <= n 이라 36 자신도 포함된다 — 범위를 i < n 으로 바꾸면 8 이 된다. 시험은 이런 경계 하나를 바꿔서 낸다.
따라가기
헷갈리는 자리 — 약수를 세다가 6 을 두 번 세거나(6 × 6 = 36 이라 짝이 자기 자신) 1 · 36 을 빼먹는 것. 코드는 i 를 하나씩 올리니 그런 실수가 없다 — 손으로 셀 때는 짝(1·36, 2·18, 3·12, 4·9, 6)으로 세면 9 가 바로 나온다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
다음 코드의 출력을 쓰시오.
답 — 10 20. 0 + 2 + 4 + 6 + 8 = 20 을 더하고 i 는 10 에서 멈춘다.
원리 — do-while 은 본문을 먼저 한 번 실행하고 그다음에 조건을 검사한다. 조건이 처음부터 거짓이어도 본문이 한 번은 돈다는 것이 while 과의 차이다. 여기서는 sum += i 를 한 뒤 i 를 2 올리고 i < 10 인지 본다. i 가 8 일 때 sum 에 8 을 더하고 i 가 10 이 되어 조건이 거짓이라 끝난다. 그래서 마지막으로 더해진 값은 8 이고 i 의 최종값은 10 이다 — "더한 값"과 "멈춘 i" 가 다르다.
따라가기
헷갈리는 자리 — 10 도 더해서 30 으로 적는 것. 10 은 조건 검사에서 걸러져 본문에 들어오지 못한다. 그리고 출력 순서 — printf 가 i 를 먼저, sum 을 나중에 찍는다. 변수 순서를 바꿔 읽으면 20 10 이 된다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
왜 이걸 하나 — 짧은 코드는 규칙 하나에서 통째로 깎인다.
| 자리 | 새는 꼴 | 적는 법 | 기출 |
|---|---|---|---|
| 우선순위 | z & z >> 1 을 왼쪽부터 계산한다 | 시프트가 & 보다 먼저. 표를 외운다 | 2025-3회 15번 |
| & · && | 비트를 논리로, 논리를 비트로 | 기호 개수를 센다. 하나면 비트, 둘이면 논리 | 2025-3회 15번 |
| 흘러내림 | 맞는 case 하나만 적는다 | break 가 없으면 아래 전부 | 2023-2회 10번 · 2024-2회 10번 |
| static | 호출마다 0 으로 초기화한다 | 초기화는 첫 호출 한 번. 값이 누적된다 | 2024-3회 6번 |
| 같은 이름 | main 의 value 와 함수의 value 를 섞는다 | 다른 변수. 함수 안 static 만 누적 | 2024-3회 6번 |
| 16진수 | 0xA5 를 10진수로 바꾸지 않고 AND 한다 | 2진수 8자리로 펴서 자리마다 | 2025-1회 19번 |
| 빈칸 식 | place *= 2 를 10 으로 | 2진수 자리값은 2 의 거듭제곱 | 2023-1회 9번 |
| 서식 | %u 를 %d 로 읽어 음수를 적는다 | unsigned 는 음수가 없다 | 2025-3회 17번 |
이 장의 답은 계산 한 번에 숫자 하나라 되돌아볼 자리가 없다. 정답을 적기 전에 규칙 10개 중 무엇을 썼는지 하나씩 표시하며 검산한다.
왜 이걸 하나 — 규칙 10개를 짧은 코드 10개로 돌린다. 매일 5문항씩 곁들이는 자리다.
훈련 10문항은 전위 · 후위 증감, continue 와 break, static, switch 흘러내림, 비트 3종, 중첩 삼항, 초 변환, do-while, 중첩 반복, 전역 · 지역 가리기, 10진수 → 2진수다. 정답은 전부 gcc 로 실행해 확인했다.
답 — 5 7 7. 후위 증가는 "쓰고 나서 올리고", 전위 증가는 "올리고 나서 쓴다".
원리 — x++ 는 식의 값이 "올리기 전 x" 이고 그 뒤에 x 가 1 커진다. ++x 는 먼저 1 올리고 식의 값이 "올린 뒤 x" 다. 첫 printf 는 x++ 라 5 를 찍고 x 는 6 이 된다. 둘째 printf 는 ++x 라 x 를 7 로 만들고 7 을 찍는다. 셋째는 그냥 x 라 7 이다. 결국 두 번 올라 7 이 되는 것은 같고, "언제 읽었나"만 다르다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 16. 홀수 1 + 3 + 5 + 7 을 더하고 9 에서 멈춘다.
원리 — continue 는 "이번 회차의 나머지를 건너뛰고 다음 회차로", break 는 "반복문을 아예 나간다"이다. 짝수는 첫 if 에서 continue 로 걸러져 더해지지 않는다. 홀수 중 7 보다 크면 break 로 반복이 끝난다. 그래서 1 · 3 · 5 · 7 만 더해지고, 9 에서는 i > 7 이 참이라 더하지 못하고 나간다. 두 문장의 순서도 중요하다 — 8 은 짝수라 continue 로 넘어가 break 검사를 안 받는다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 6. static 변수는 함수가 끝나도 값을 유지하므로 호출마다 2 씩 쌓여 세 번째 호출에서 6 이다.
원리 — 보통의 지역 변수는 함수가 불릴 때마다 새로 만들어지고 끝나면 사라진다. static 을 붙이면 프로그램이 시작할 때 한 번만 0 으로 초기화되고, 함수가 끝나도 메모리에 남아 다음 호출 때 이어서 쓴다. static int c = 0 은 "처음 한 번만" 실행되는 초기화다. 그래서 f() 를 부를 때마다 c 가 2 · 4 · 6 으로 커진다. static 이 없었다면 매번 0 에서 시작해 항상 2 다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 8. case 3 에 들어간 뒤 break 가 없어 case 5 까지 흘러내려(fall-through) 3 + 5 가 더해진다.
원리 — switch 는 값이 맞는 case 로 "점프"한 뒤, break 를 만날 때까지 아래로 계속 실행한다. case 는 출입구이지 칸막이가 아니다. n = 3 이라 case 3 부터 시작해 r += 3, 이어서 case 5 의 r += 5 를 실행하고 거기 break 가 있어 나간다. case 1 은 위에 있어 실행되지 않고, case 7 은 break 뒤라 닿지 않는다. break 를 빠뜨린 switch 가 시험의 단골이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 0 15 2. 9 = 1001, 6 = 0110 이라 AND 는 겹치는 비트가 없고, OR 는 전부 채워지며, 9 를 오른쪽으로 2칸 밀면 2 다.
원리 — 9 와 6 은 2진수에서 1 의 자리가 하나도 안 겹친다(1001 · 0110). 그래서 AND 는 0000 = 0 이고 OR 는 1111 = 15 다. >> 는 비트를 오른쪽으로 미는 것이고 한 칸마다 2 로 나눈 몫이 된다 — 9 >> 2 는 9 ÷ 4 = 2(1001 → 10). 반대로 << 는 2 를 곱한다. 시프트는 밀려 나간 비트가 버려지므로 나머지는 사라진다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 2. 바깥 조건 8 > 5 가 참이라 안쪽 삼항으로 들어가고, 8 % 5 = 3 이 0 이 아니라 2 다.
원리 — 삼항 연산자 조건 ? 참값 : 거짓값 은 if-else 를 식 하나로 쓴 것이다. 괄호 안에 삼항이 또 있으면 바깥 조건을 먼저 판정하고, 참이면 괄호 안 삼항을 다시 판정한다. x > y 는 8 > 5 참 → (x % y == 0 ? 1 : 2) 를 계산 → 8 % 5 = 3, 0 이 아니므로 거짓 → 2. 바깥이 거짓이었다면 안쪽은 아예 계산하지 않고 3 이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 1:2:30. 3750초 = 1시간 2분 30초다.
원리 — 초를 시 · 분 · 초로 쪼개는 정석이다. 시는 3600 으로 나눈 몫(정수 나눗셈이라 소수점 버림). 시를 뺀 나머지 t % 3600 을 60 으로 나눈 몫이 분. 60 으로 나눈 나머지 t % 60 이 초다 — 3600 이 60 의 배수라 시를 뺄 필요 없이 바로 t % 60 이 초다. 서식 "%d:%d:%d" 라 콜론이 그대로 찍힌다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 4. 2026 을 10 으로 계속 나누며 0 이 될 때까지 센 횟수 = 자릿수다.
원리 — 10 으로 나누면(정수 나눗셈) 마지막 자리가 하나 떨어진다. 2026 → 202 → 20 → 2 → 0 까지 네 번 나누므로 자릿수 4 다. do-while 이라 n 이 0 이어도 한 번은 돈다 — 그래서 n = 0 일 때 자릿수 1 이 정확히 나온다(while 이었다면 0 이 된다). 이 코드는 "자릿수 세기"의 표준형이라 통째로 알아 둔다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 19. i = 2 · 3 · 4 각각에 대해 1 부터 i 까지 더한 3 + 6 + 10 이다.
원리 — 안쪽 반복이 바깥 변수 i 에 묶여 있다(j <= i). 그래서 바깥이 한 바퀴 돌 때마다 안쪽 횟수가 달라진다 — 삼각형 모양의 이중 반복이다. i = 2 면 j 는 1 · 2 로 합 3, i = 3 이면 1 · 2 · 3 으로 합 6, i = 4 면 합 10. 안쪽 합은 1 부터 i 까지의 합 i(i+1)/2 이고 그것을 i = 2~4 에 대해 더한다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 11 6. 함수 안의 x 는 전역 x 와 다른 변수라 서로 영향을 주지 않는다.
원리 — 전역 변수 x = 1 이 있어도 f() 안에서 int x = 10 으로 다시 선언하면 그 함수 안에서는 지역 x 가 전역 x 를 가린다(shadowing). f() 의 x++ 는 지역 x 를 11 로 만들고 찍는다. 함수가 끝나면 지역 x 는 사라지고 전역 x 는 여전히 1 이다. main 의 x += 5 는 전역 x 를 6 으로 만든다. "같은 이름 = 같은 변수"가 아니다 — 선언된 범위(스코프)를 본다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 1101. 13 을 2 로 나눈 나머지를 모아 거꾸로 찍은 2진수다.
원리 — 10진수를 2진수로 바꾸는 손 계산 그대로다. 2 로 나눈 나머지가 가장 낮은 자리부터 나오므로 b[0] 에 1의 자리, b[1] 에 2의 자리… 순으로 쌓인다. 13 → 나머지 1, 몫 6 → 나머지 0, 몫 3 → 나머지 1, 몫 1 → 나머지 1, 몫 0. b = [1 0 1 1], i 는 4. 출력은 높은 자리부터여야 하니 i − 1 = 3 부터 0 까지 거꾸로 찍어 1101 이 된다. 8 + 4 + 1 = 13 으로 검산된다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
왜 이걸 하나 — 아래를 안 보고 적을 수 있어야 이 장이 끝난다.
& 와 && 의 차이, 논리 연산의 결과값.% · 2), 금액 분해 식 4개.%u.