2025년 1회 실전 E25

이전 자료에 없던 9번(서브넷 판정)을 채워 20문항이다. 생성자 안의 오버라이딩 호출 54, 비트 AND 908, 문장 번호 순서가 갈림길

왜 이 장을 하나
2025년 1회는 Java 가 4문항 전부 규칙 문제다. 13번은 부모 생성자 안에서 부른 update() 가 자식 것이라는 것, 20번은 calc("5") 가 String 판 재귀에서 int 판 재귀로 넘어간다는 것, 5번은 catch 뒤에 finally 가 꼭 돈다는 것이다. 9번은 이전 자료가 빠뜨린 문항이라 처음 보는 문제로 푼다.
다루는 것2025년 1회 20문항 · 복원본
시계150분 · 실제 시험과 같다
끝나면문항마다 가는 장이 표로 나온다

01푸는 법

왜 이걸 하나 — 세트는 시험장과 같은 조건에서만 숫자가 된다. 조건은 E01 과 같다.

규칙은 E01 진단의 01절 그대로다. 시작을 누르면 150분이 돌고, 1회독 100분 · 2회독 40분 · 검토 10분으로 나눈다. 한 문항에 5분이 넘으면 답 칸을 비우고 넘어가며, 정답은 20문항을 다 적은 뒤에 연다.

이 회차의 배점은 프로그래밍 9문항(45점) · 네트워크 3문항(15점) · SQL·DB 3문항(15점) · SW공학 3문항(15점) · 보안 2문항(10점)이다. 코드 문항 수만큼 5분씩을 1회독에서 먼저 떼어 두고, 남는 시간을 용어에 쓴다. 용어는 아는 것을 바로 적고 모르는 것은 비운다 — 용어에서 고민하는 시간이 코드 한 문항의 값이다.

자가 판정은 답안지에 그대로 적었을 때 채점자가 맞다고 할 것인가 하나다. 철자 하나, 줄바꿈 하나, 기호 대신 이름이면 틀렸다를 누른다. 후하게 준 5점은 시험장에서 사라진다.

02실전 세트

왜 이걸 하나 — 20문항을 한 번에 150분 안에 푸는 것 자체가 연습이다. 분야 장의 문제와 같은 문항이어도 조건이 다르다.

시작을 누르면 시계가 돌고 화면을 닫아도 이어진다. 다 적은 뒤 문항마다 정답 보기 → 맞았다 · 틀렸다를 누르면 위 막대에 점수와 분야별 결과가 모인다. 이 세트에서 채점한 기록은 분야 장의 같은 문항에도 그대로 보인다.

2025-1회 · 1번보안

인증된 사용자의 세션(시퀀스 번호 등)을 가로채 인증 절차를 우회하고 접속을 탈취하는 공격은?

정답세션 하이재킹 (Session Hijacking)

— 세션 하이재킹(Session Hijacking). 이미 로그인된 사람의 세션을 가로채 그 사람인 척 이어 쓰는 공격이다.

원리 — 로그인이 끝나면 서버와 사용자는 세션(TCP 연결이나 쿠키의 세션 ID)으로 "아까 그 사람"을 알아본다. 공격자가 그 세션 식별자를 훔치면(TCP 시퀀스 번호 예측, 쿠키 탈취) 비밀번호 없이도 인증을 건너뛰고 그 사람으로 행세한다. 통화 중인 전화를 중간에 가로채 상대인 척 이어가는 것과 같다. 막으려면 세션 ID 를 예측 불가능하게 만들고 HTTPS 로 쿠키를 숨긴다.

따라가기

  1. 인증된 세션 가로채기 + 인증 우회 + 접속 탈취 → 세션 하이재킹

헷갈리는 자리 — 스니핑(엿보기만)이나 스푸핑(주소 위조)을 적는 것. 세션을 "이어받아 쓰는" 것이 하이재킹이다. 시퀀스 번호 이야기는 TCP 세션 하이재킹의 세부다.

표준 · 교재 정의(공격 기법 · 보안 솔루션 · 시큐어 코딩 가이드)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 2번DB

무결성 3종 빈칸: ① 속성 값은 정의된 범위의 값이어야 한다 ② 기본키는 NULL·중복 불가 ③ 외래키는 참조하는 기본키와 일치하거나 NULL

정답① 도메인 무결성 ② 개체 무결성 ③ 참조 무결성

— ① 도메인 무결성 ② 개체 무결성 ③ 참조 무결성. 값의 범위 · 기본키 · 외래키에 걸리는 세 규칙이다.

원리 — 무결성 규칙은 "무엇에 거는가"로 이름이 갈린다. 속성 값이 정해진 범위(도메인) 안이어야 한다 → 도메인 무결성. 기본키는 NULL · 중복 불가 → 개체 무결성. 외래키는 상대 기본키에 있는 값이거나 NULL → 참조 무결성. 문제 문장에서 "속성 값 · 범위"는 도메인, "기본키"는 개체, "외래키"는 참조로 낱말이 곧 답이다.

따라가기

  1. 속성 값은 정의된 범위의 값 → 도메인
  2. 기본키는 NULL · 중복 불가 → 개체
  3. 외래키는 참조하는 기본키와 일치하거나 NULL → 참조

헷갈리는 자리 — 도메인 무결성을 "속성 무결성"이라 적는 것 — 정식 이름은 도메인이다. 순서를 바꿔 적으면 그 칸만 틀린다. 세 규칙을 한 줄씩 외워 두면 어느 하나만 물어도 즉답이다.

교재 정의(관계형 모델 · 정규화 · 트랜잭션 표준 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 3번네트워크

다항식 나눗셈을 기반으로 오류를 검출하는 순환 중복 검사 방식은? (영문 약자)

정답CRC

— CRC. 데이터를 정해진 다항식으로 나눈 나머지를 붙여 보내고 받는 쪽이 같은 나눗셈으로 오류를 잡는 순환 중복 검사다.

원리 — 보내는 쪽은 데이터 비트열을 미리 약속한 생성 다항식으로 나눠 나머지(CRC 값)를 데이터 뒤에 붙인다. 받는 쪽은 데이터와 나머지를 합쳐 같은 다항식으로 나눠 나머지가 0 이면 정상, 아니면 오류로 판단한다. 검출 능력이 패리티보다 훨씬 좋아 이더넷 프레임 · 파일 검사에 널리 쓰이고, 고치지는 못하므로 검출 뒤 재전송(BEC)과 짝이 된다. "다항식 · 나눗셈 · 순환"이 표지다.

따라가기

  1. 다항식 나눗셈 기반 오류 검출 → CRC

헷갈리는 자리 — 체크섬(덧셈 기반)이나 해밍 코드(수정까지)와 섞는 것. CRC 는 검출만 하고 나눗셈을 쓴다. 영문 약자 CRC(Cyclic Redundancy Check) 세 글자가 답이다.

표준 · 교재 정의(OSI · TCP/IP · IEEE · RFC 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 4번보안

"바이러스에 감염됐습니다!" 같은 가짜 경고로 사용자를 겁주어 가짜 백신 구매·결제를 유도하는 악성 소프트웨어는?

정답스캐어웨어 (Scareware)

— 스캐어웨어(Scareware). 가짜 경고로 겁을 줘(scare) 가짜 백신을 사게 하거나 설치하게 만드는 악성 소프트웨어다.

원리 — "바이러스 37개 발견! 지금 치료하세요" 같은 창을 띄워 불안하게 만든 뒤, 돈을 내거나 프로그램을 깔게 한다 — 그 프로그램이 진짜 악성코드이거나 아무 일도 안 하는 사기다. 기술적 취약점이 아니라 사람의 공포를 파고드는 사회공학 계열이다. 이름의 scare(겁주다) + ware(소프트웨어)가 뜻 그대로다.

따라가기

  1. 가짜 경고로 겁줌 + 가짜 백신 구매 유도 → 스캐어웨어

헷갈리는 자리 — 랜섬웨어(파일을 인질로 돈 요구)나 애드웨어(광고)와 섞는 것. "가짜 경고 · 겁"이면 스캐어웨어다. 랜섬웨어는 실제로 파일을 암호화한다는 점이 다르다. 대책은 기술이 아니라 습관이다 — 브라우저 팝업의 경고는 백신이 아니므로 닫는다.

표준 · 교재 정의(공격 기법 · 보안 솔루션 · 시큐어 코딩 가이드)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 5번Java

다음 Java 프로그램의 실행 결과를 쓰시오.

public class Main { public static void main(String[] args) { int number = 5; int divisor = 0; try { System.out.print(number / divisor); } catch (ArithmeticException e) { System.out.print("출력1"); } catch (ArrayIndexOutOfBoundsException e) { System.out.print("출력2"); } catch (Exception e) { System.out.print("출력4"); } finally { System.out.print("출력5"); } } }
정답출력1출력5

— 출력1출력5. 5 를 0 으로 나눠 ArithmeticException 이 나고, 그것을 잡는 첫 catch 와 finally 만 돈다.

원리 — 정수를 0 으로 나누면 자바는 ArithmeticException 을 던진다(실수 나눗셈이면 Infinity 가 되어 예외가 없다). 예외가 나는 순간 System.out.print(number / divisor) 는 아무것도 찍지 못하고 catch 로 넘어간다. catch 는 위에서부터 종류가 맞는 첫 하나만 돈다 — ArithmeticException 은 첫 catch 에 정확히 맞고, 셋째 catch(Exception)도 맞지만 이미 잡혔다. finally 는 마지막에 반드시 돈다. 출력2 · 출력4 는 이 흐름에서 닿을 수 없다.

따라가기

  1. 5 / 0 → ArithmeticException, print 는 실행되지 않음
  2. catch (ArithmeticException) → 출력1
  3. finally → 출력5. 한 줄에 이어 출력1출력5

헷갈리는 자리 — 출력4 까지 적는 것(Exception 도 맞으니까) — catch 는 하나만. 출력1 과 출력5 사이에 줄바꿈이나 공백을 넣는 것 — 전부 print 라 붙는다. 출력3 이 코드에 없는 것은 미끼가 아니라 그냥 없는 것이다.

복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 6번네트워크

① IP 주소를 MAC 주소로 변환하는 프로토콜 ② MAC 주소로 IP 주소를 알아내는 프로토콜

정답① ARP ② RARP

— ① ARP ② RARP. IP 에서 MAC 을 찾으면 ARP, 거꾸로 MAC 에서 IP 를 찾으면 RARP 다.

원리 — 같은 네트워크 안에서 패킷을 실제로 전달하려면 상대의 물리 주소(MAC)가 필요한데 우리는 IP 주소만 안다. ARP(Address Resolution Protocol)는 "이 IP 가진 사람 MAC 알려줘"를 브로드캐스트로 물어 답을 받고 캐시에 둔다. RARP 는 반대로 MAC 만 아는 장비(디스크 없는 단말)가 자기 IP 를 서버에 묻는 것이다 — 지금은 DHCP 가 그 일을 한다. R 은 Reverse(거꾸로)다.

따라가기

  1. IP → MAC → ARP
  2. MAC → IP → RARP

헷갈리는 자리 — 방향을 바꿔 적는 것. "보통은 IP 를 알고 MAC 을 찾는다 = ARP", R 이 붙으면 거꾸로. ARP 를 3계층 프로토콜로 볼지 2계층으로 볼지는 교재마다 다르니 계층을 묻는 문제에서는 문제의 분류를 따른다.

표준 · 교재 정의(OSI · TCP/IP · IEEE · RFC 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 7번SQL

다음 두 테이블과 SQL문을 보고 조회 결과를 테이블 형태로 쓰시오.

직원

직원번호이름
101이순신
102강감찬
103김유신

보상

직원번호성과급
1011000
102300
103450
SELECT e.이름, b.성과급 FROM 직원 e, 보상 b WHERE e.직원번호 = b.직원번호 AND b.성과급 >= 500;
정답이름 | 성과급
이순신 | 1000

— 열 이름 · 성과급, 한 행 이순신 · 1000. 직원번호가 같은 행끼리 이어 붙인 뒤 성과급 500 이상만 남긴다.

원리FROM 직원 e, 보상 b 는 두 테이블을 전부 짝지은 뒤(3 × 3 = 9 행) WHERE e.직원번호 = b.직원번호 로 번호가 같은 짝만 남기는 옛 방식의 조인이다(JOIN … ON 과 같다). 남은 세 짝 중 b.성과급 >= 500 인 것은 101 번(1000)뿐이다. SELECT 에서 e.이름, b.성과급 두 열만 뽑으므로 결과 표는 열 둘, 행 하나다.

따라가기

  1. 번호 같은 짝: 101 이순신 1000 · 102 강감찬 300 · 103 김유신 450
  2. 성과급 >= 500 → 101 만
  3. 결과: 이름 | 성과급 / 이순신 | 1000

헷갈리는 자리 — 답에 직원번호 열을 넣는 것(SELECT 에 없다). 450 을 "500 가까우니" 넣는 것 — 이상은 500 부터다. 표 꼴로 쓰라고 했으니 열 이름 줄을 먼저 적는다. 열 이름은 별칭이 없으니 원래 이름(이름 · 성과급)이고, e · b 같은 테이블 별칭은 결과에 안 나온다.

표를 sqlite 3.49 에 넣고 같은 SQL 을 실행해 결과를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.

2025-1회 · 8번DB

관계형 DB 용어 매칭: ① 속성의 개수 ② 튜플의 개수 ③ 다른 릴레이션의 기본키를 참조하는 키 ④ 속성이 가질 수 있는 값들의 범위 (영문으로)

정답① degree ② cardinality ③ foreign key ④ domain

— ① degree ② cardinality ③ foreign key ④ domain. 관계형 모델 용어를 영문으로 묻는다.

원리 — 우리말 용어와 영문을 짝으로 두어야 한다. 속성(열)의 개수는 차수 = degree, 튜플(행)의 개수는 카디널리티 = cardinality, 다른 표의 기본키를 참조하는 키는 외래키 = foreign key, 한 속성이 가질 수 있는 값의 범위는 도메인 = domain 이다. 2023년 1회 12번 · 2024년 2회 4번과 같은 내용인데 영문으로 적으라는 것만 다르다.

따라가기

  1. 속성의 개수 → degree
  2. 튜플의 개수 → cardinality
  3. 다른 릴레이션의 기본키를 참조 → foreign key
  4. 값의 범위 → domain

헷갈리는 자리 — degree 와 cardinality 를 바꾸는 것(열은 degree). 철자 — cardinality 에 l 이 하나, foreign 의 g 뒤에 n. 영문으로 쓰라는데 우리말을 적으면 0 점이다.

교재 정의(관계형 모델 · 정규화 · 트랜잭션 표준 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 9번네트워크

IP 주소가 192.168.35.10 이고 서브넷 마스크가 255.255.252.0 일 때, 같은 네트워크에 있어 라우터 없이 직접 수신할 수 있는 주소를 보기에서 모두 고르시오.

ㄱ. 192.168.34.1
ㄴ. 192.168.32.19
ㄷ. 192.168.35.200
ㄹ. 192.168.33.138
ㅁ. 192.168.35.50

정답ㄱ, ㄴ, ㄷ, ㄹ, ㅁ

— ㄱ, ㄴ, ㄷ, ㄹ, ㅁ 전부. /22 는 셋째 옥텟 32~35 가 한 네트워크라 다섯 주소가 모두 같은 망이다.

원리 — 마스크 255.255.252.0 은 앞 22비트가 네트워크 부분이라는 뜻이고, 셋째 옥텟 252 = 1111 1100 이라 그 옥텟은 4(256 − 252)씩 묶인다 — 0~3, 4~7, …, 32~35, 36~39. 192.168.35.10 의 셋째 옥텟 35 는 32~35 묶음이니 네트워크 주소는 192.168.32.0, 호스트 범위는 192.168.32.1 ~ 192.168.35.254 다. 같은 네트워크면 라우터 없이 직접 주고받는다. 보기의 셋째 옥텟이 34 · 32 · 35 · 33 · 35 로 전부 32~35 안이다.

따라가기

  1. 마스크 252 → 묶음 크기 4 → 35 는 32~35 묶음
  2. 범위 192.168.32.1 ~ 192.168.35.254
  3. ㄱ 34.1 · ㄴ 32.19 · ㄷ 35.200 · ㄹ 33.138 · ㅁ 35.50 → 전부 안 → ㄱ ㄴ ㄷ ㄹ ㅁ

헷갈리는 자리 — /24 처럼 셋째 옥텟이 같아야 한다고 보고 ㄷ · ㅁ 만 고르는 것. 마스크가 252 이면 셋째 옥텟이 달라도 같은 묶음일 수 있다. 32.19 를 "32.0 네트워크 주소 근처"라며 빼는 것 — 네트워크 주소는 192.168.32.0 하나뿐이고 32.19 는 호스트다.

파이썬 ipaddress 로 네트워크 · 범위를 계산해 같은 값을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.

2025-1회 · 10번C

다음 C 프로그램의 실행 결과를 두 줄로 쓰시오.

#include <stdio.h> int main(void) { char letters[5] = { 'B', 'A', 'D', 'E', '\0' }; char target = 'C'; int pos; printf("%d\n", letters[3] - letters[1]); for (pos = 0; pos < 4; pos++) { if (letters[pos] > target) break; } for (int i = 4; i > pos; i--) { letters[i] = letters[i - 1]; } letters[pos] = target; for (int i = 0; i < 5; i++) printf("%c", letters[i]); return 0; }
정답4
BACDE

— 두 줄: 4 / BACDE. 첫 줄은 글자 코드의 차이, 둘째 줄은 C 를 제자리에 끼워 넣은 결과다.

원리 — 글자는 숫자(코드)라 빼기가 된다. E 는 69, A 는 65 이니 letters[3] - letters[1] 은 4 다. 둘째 부분은 "끼워 넣기"다. 배열 B A D E 에서 target C 보다 큰 첫 글자를 찾아(그 자리가 pos) 그 자리부터 뒤의 글자들을 한 칸씩 뒤로 밀고 빈 자리에 C 를 놓는다. 뒤에서부터 미는 이유는 앞에서부터 밀면 밀린 글자가 다음 글자를 덮어 버리기 때문이다. 다섯째 칸(끝표)이 밀려 사라지지만 출력은 다섯 글자를 그대로 찍는다.

따라가기

  1. 첫 printf: 'E' − 'A' = 69 − 65 = 4, 줄바꿈
  2. pos 찾기: B > C 아니다, A > C 아니다, D > C → break, pos = 2
  3. 밀기: i = 4 → letters[4] = letters[3] = 'E'; i = 3 → letters[3] = letters[2] = 'D' → [B, A, D, D, E]
  4. letters[2] = 'C' → [B, A, C, D, E] → BACDE

헷갈리는 자리 — B A 가 정렬돼 있지 않은데 "정렬된 배열에 끼워 넣기"로 넘겨짚어 ABCDE 라 적는 것. 코드는 정렬하지 않고 C 보다 큰 첫 글자 앞에 끼울 뿐이다. 첫 줄의 4 는 첨자 차이(3 − 1 = 2)가 아니라 글자 값 차이다.

복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 11번C

다음 C 프로그램의 실행 결과를 쓰시오.

#include <stdio.h> void place(int grid[3][3], const int values[9]) { for (int i = 0; i < 9; i++) { grid[((i + 1) / 3) % 3][(i + 1) % 3] = values[i]; } } int main(void) { int grid[3][3]; int values[9] = { 5, 2, 7, 4, 1, 8, 3, 6, 9 }; int total = 0; place(grid, values); for (int i = 0; i < 9; i++) { total += grid[i / 3][i % 3] * (i % 2 == 0 ? 1 : -1); } printf("%d", total); return 0; }
정답13

— 13. 아홉 값을 3×3 격자에 한 칸 밀린 자리로 채운 뒤 짝수 첨자는 더하고 홀수 첨자는 뺀다.

원리 — 2차원 배열의 칸 번호를 한 줄 번호로 바꾸는 규칙은 행 = 번호 / 3, 열 = 번호 % 3 이다(3열짜리). place 는 값 i 를 번호 i + 1 자리에 넣되 행에 % 3 을 한 번 더 걸어, 번호 9 는 행 3 이 아니라 행 0 으로 돌아간다. 즉 values 를 격자에 순서대로 넣되 한 칸 뒤로 밀고 마지막 값이 맨 앞으로 돈다. 합을 구할 때 i % 2 == 0 ? 1 : -1 은 첨자가 짝수면 +, 홀수면 − 라는 뜻이다.

따라가기

  1. i = 0 → grid[0][1] = 5, i = 1 → grid[0][2] = 2, i = 2 → grid[1][0] = 7
  2. i = 3 → grid[1][1] = 4, i = 4 → grid[1][2] = 1, i = 5 → grid[2][0] = 8
  3. i = 6 → grid[2][1] = 3, i = 7 → grid[2][2] = 6, i = 8 → (9 / 3) % 3 = 0, 9 % 3 = 0 → grid[0][0] = 9
  4. 격자를 한 줄로: 9 5 2 / 7 4 1 / 8 3 6
  5. 부호 번갈아: +9 −5 +2 −7 +4 −1 +8 −3 +6 = 13

헷갈리는 자리 — i = 8 에서 행이 3 이 되어 배열 밖이라고 보는 것. % 3 때문에 0 행으로 돈다. 그리고 부호는 값의 첨자(i)가 아니라 합칠 때의 i 로 정해진다 — 격자를 한 줄로 편 뒤에 번갈아 붙인다.

복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 12번SW공학

다음 설명에 해당하는 결합도를 ①부터 ③까지 순서대로 쓰시오.

① 다른 모듈 내부의 변수나 기능을 직접 사용한다.
② 모듈 사이에서 배열, 객체, 구조체 같은 자료구조 전체를 전달한다.
③ 여러 모듈이 모듈 밖의 전역 변수를 함께 참조하거나 갱신한다.

정답① 내용 결합도 ② 스탬프 결합도 ③ 공통 결합도

— ① 내용 결합도 ② 스탬프 결합도 ③ 공통 결합도. "남의 속 · 자료구조째 · 전역 변수"가 각각의 열쇠말이다.

원리 — 결합도 6단계는 "무엇을 통해 얽혔나"로 구분한다. 자료 결합은 필요한 값만 인자로 넘긴다(가장 좋다). 스탬프 결합은 배열 · 구조체 · 객체를 통째로 넘기고 받는 쪽은 일부만 쓴다 — 구조가 바뀌면 안 쓰는 쪽도 영향받는다. 제어 결합은 플래그로 조종한다. 외부 결합은 외부 파일 형식 · 프로토콜을 서로 안다. 공통 결합은 여러 모듈이 같은 전역 변수를 읽고 쓴다 — 누가 바꿨는지 추적이 안 된다. 내용 결합은 다른 모듈의 내부 변수 · 코드를 직접 건드린다(가장 나쁘다) — 상대를 고칠 수 없게 만든다.

따라가기

  1. "다른 모듈 내부의 변수나 기능을 직접 사용" → 남의 속 → 내용 결합도
  2. "배열 · 객체 · 구조체 전체를 전달" → 자료구조째 → 스탬프 결합도
  3. "전역 변수를 함께 참조 · 갱신" → 공유 저장소 → 공통 결합도

헷갈리는 자리 — 공통과 내용을 바꾸는 것. 공통은 "밖에 있는 전역"을 같이 쓰는 것이고, 내용은 "상대 안에 있는 것"을 직접 쓰는 것이다. 스탬프는 자료를 넘기긴 하는데 "덩어리째"라는 점이 자료 결합과 다르다.

표준 · 교재 정의(결합도 6단계 · 응집도 7단계 · UML 2.x 다이어그램 분류)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 13번Java

다음 Java 프로그램의 실행 결과를 쓰시오.

public class Main { public static void main(String[] args) { new Derived(); System.out.println(Base.total); } } class Base { static int total = 0; int value = 1; Base() { total += ++value; update(); } void update() { total += total; } } class Derived extends Base { int value = 10; Derived() { value += 2; total += value++; update(); } @Override void update() { total += total * 2; } }
정답54

— 54. 부모 생성자 안에서 부른 update() 도 자식 판이 돌아 total 이 2 → 6 이 되고, 자식 생성자에서 12 를 더해 18, 다시 자식 update 로 54 가 된다.

원리new Derived() 는 부모 생성자 Base() 를 먼저 돌린다. 그 안에서 update() 를 부르면 만들어지는 객체가 Derived 이므로 갈아끼운 Derived.update 가 돈다 — 생성자 안이라도 오버라이딩은 그대로다. ++value 는 먼저 1 을 올린 값을 쓰고, value++ 는 지금 값을 쓴 뒤 올린다. Base 의 value 와 Derived 의 value 는 이름만 같은 다른 칸이다. static 인 total 은 클래스에 하나뿐이라 부모 · 자식이 같은 것을 고친다.

따라가기 — total = 0.

  1. Base(): total += ++value → Base.value 1 → 2, total = 2
  2. Base() 안 update() → Derived.update: total += total × 2 → 2 + 4 = 6
  3. Derived(): value(10) += 2 → 12; total += value++ → 6 + 12 = 18 (value 는 13)
  4. update() → 18 + 36 = 54

헷갈리는 자리 — 부모 생성자 안의 update 를 부모 판(total += total → 4)으로 계산해 다른 값을 얻는 것. 그리고 ++value 를 1 로 쓰는 것 — 앞에 붙은 ++ 는 올린 뒤의 값 2 다. 6 → 18 → 54 의 세 배 규칙이 보이면 맞게 간 것이다.

복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 14번디자인패턴

서로 호환되지 않는 인터페이스를 변환해 클래스들을 함께 동작하게 하는 구조 패턴은?

정답어댑터 (Adapter)

— 어댑터(Adapter). 모양이 안 맞는 두 인터페이스 사이에 변환기를 끼워 함께 돌게 하는 구조 패턴이다.

원리 — 클라이언트는 Target 인터페이스를 기대하는데, 쓰고 싶은 기존 클래스(Adaptee)는 다른 메서드 이름 · 형식을 가진다. 어댑터는 Target 을 구현하면서 안에서 Adaptee 의 메서드를 호출해 형식을 맞춘다 — 220V 콘센트에 110V 기기를 꽂는 변환 플러그와 같다. 기존 클래스를 고치지 않고(고칠 수 없는 외부 라이브러리일 때 특히) 재사용할 수 있다. 상속으로 만들면 클래스 어댑터, 합성으로 Adaptee 를 갖고 있으면 객체 어댑터다. 별명은 Wrapper 다.

따라가기

  1. "서로 호환되지 않는 인터페이스를 변환" → 변환기
  2. "클래스들을 함께 동작하게" → 기존 코드 재사용
  3. 구조 패턴 → 어댑터

헷갈리는 자리 — 브리지(Bridge)와 섞는 것. 브리지는 "처음부터 추상과 구현을 나눠 설계"하는 것이고, 어댑터는 "이미 있는 안 맞는 것을 나중에 맞추는" 것이다. 퍼사드는 복잡한 것을 "단순하게" 보여 주는 것이라 변환과는 다르다.

GoF 책 Design Patterns 의 패턴 정의(생성 5 · 구조 7 · 행위 11)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-1회 · 15번테스트

다음 C 함수가 values = {-3}, count = 1로 호출될 때 실행되는 문장 번호를 순서대로 쓰시오.

int normalize(int values[], int count) { int index = 0; // ① while (index < count) { // ② if (values[index] < 0) { // ③ values[index] = -values[index]; // ④ } index++; // ⑤ } return 1; // ⑥ }
정답① → ② → ③ → ④ → ⑤ → ② → ⑥ (1234526)

— ① → ② → ③ → ④ → ⑤ → ② → ⑥ (1234526). 음수 하나를 뒤집고 반복 조건을 다시 검사한 뒤 빠져나온다.

원리 — while 문은 "조건 검사 → 본문 → 다시 조건 검사"를 반복한다. 그래서 반복이 끝날 때도 조건 줄(②)을 한 번 더 지난다 — 이것을 빠뜨리는 것이 이 문제의 함정이다. values = {−3}, count = 1 이니 반복은 한 번만 돈다. 본문에서 values[0] = −3 < 0 이 참이라 ④ 가 실행되어 3 이 되고, ⑤ 에서 index 가 1 이 된다. 다시 ② 로 가서 1 < 1 이 거짓이라 반복을 나가 ⑥ return 1 로 끝난다. 실행된 문장을 "순서대로, 중복 포함" 적는 것이 문제의 요구다.

따라가기

  1. ① index = 0
  2. ② 0 < 1 참 → 본문 진입
  3. ③ values[0] = −3 < 0 참 → ④ values[0] = 3
  4. ⑤ index = 1
  5. ② 1 < 1 거짓 → 반복 종료
  6. ⑥ return 1 → 순서 ①②③④⑤②⑥

헷갈리는 자리 — 마지막 ② 를 빼고 ①②③④⑤⑥ 으로 적는 것. while 은 조건이 거짓이 되는 순간에도 조건 줄을 실행한다. 반대로 values 가 양수였다면 ③ 이 거짓이라 ④ 가 빠져 ①②③⑤②⑥ 이 된다 — 문장 커버리지 문제의 전형이다.

주어진 값으로 코드를 한 줄씩 손으로 따라가 실행 순서를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 코드가 실제와 다를 수 있다.

2025-1회 · 16번Java

다음 Java 프로그램의 실행 결과를 쓰시오.

public class Main { static int search(int[] data, int start, int end) { if (start >= end) return 0; int middle = (start + end) / 2; return data[middle] + Math.max( search(data, start, middle), search(data, middle + 1, end) ); } public static void main(String[] args) { int[] data = { 3, 5, 8, 12, 17 }; System.out.println(search(data, 0, data.length - 1)); } }
정답20

— 20. 가운데 값을 더하고 왼쪽 · 오른쪽 반쪽 중 큰 쪽을 택하는 재귀라, 8 + max(8, 12) = 20 이다.

원리 — search(start, end) 는 구간의 가운데 첨자 middle 을 잡고 data[middle] 에, 왼쪽 구간(start~middle)과 오른쪽 구간(middle + 1~end)의 결과 중 큰 것을 더한다. start >= end 면 0 으로 멈춘다. 즉 "가운데를 하나 더하고, 반쪽 중 큰 길로 계속 간다"는 뜻이다. 가운데 첨자는 (start + end) / 2 의 정수 나눗셈이라 (0 + 4) / 2 = 2, (0 + 2) / 2 = 1, (0 + 1) / 2 = 0 이다. 재귀는 작은 구간부터 값을 정해 올라오면 된다.

따라가기 — data = [3, 5, 8, 12, 17].

  1. search(0, 4): middle 2 → 8 + max(search(0, 2), search(3, 4))
  2. search(0, 2): middle 1 → 5 + max(search(0, 1), search(2, 2) = 0)
  3. search(0, 1): middle 0 → 3 + max(0, 0) = 3 → search(0, 2) = 5 + 3 = 8
  4. search(3, 4): middle 3 → 12 + max(0, 0) = 12
  5. 8 + max(8, 12) = 20

헷갈리는 자리 — 오른쪽 구간을 middle 부터 시작한다고 보고 8 을 두 번 더하는 것 — 오른쪽은 middle + 1 부터다. search(2, 2) 처럼 start == end 인 구간이 0 이라는 것(원소가 하나 있어도 0)을 놓치면 8 이 더 붙는다. 조건이 start > end 였다면 답이 달라진다.

복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 17번Python

다음 Python 프로그램의 실행 결과를 쓰시오.

class Node: def __init__(self, value): self.value = value self.children = [] def build(values): nodes = [Node(value) for value in values] for index in range(1, len(nodes)): nodes[(index - 1) // 2].children.append(nodes[index]) return nodes[0] def odd_level_sum(node, level=0): own = node.value if level % 2 == 1 else 0 return own + sum(odd_level_sum(child, level + 1) for child in node.children) root = build([3, 5, 8, 12, 15, 18, 21]) print(odd_level_sum(root))
정답13

— 13. 트리에서 레벨이 홀수(1)인 노드는 5 와 8 뿐이고 그 합이 13 이다.

원리 — build 는 리스트를 이진 트리로 만든다. 첨자 index 의 노드를 첨자 (index − 1) // 2 노드의 자식으로 붙이므로, 0 아래에 1 · 2, 1 아래에 3 · 4, 2 아래에 5 · 6 이 온다(힙과 같은 배열 표현). odd_level_sum 은 루트를 레벨 0 으로 두고 자식으로 내려갈 때마다 레벨을 1 씩 올리며, 레벨이 홀수인 노드의 값만 더한다. level=0 은 기본값 인자라 루트 호출 때 안 적어도 0 이다.

따라가기 — 값 [3, 5, 8, 12, 15, 18, 21].

  1. 레벨 0: 3(첨자 0)
  2. 레벨 1: 5(첨자 1), 8(첨자 2) → 홀수 레벨
  3. 레벨 2: 12, 15(5 의 자식), 18, 21(8 의 자식) → 짝수 레벨
  4. 홀수 레벨 합 5 + 8 = 13

헷갈리는 자리 — 루트를 레벨 1 로 세어 3 + 12 + 15 + 18 + 21 = 69 를 적는 것. 코드가 level=0 에서 시작한다. 자식을 붙이는 규칙을 몰라 트리를 한 줄 사슬로 보는 것 — (index − 1) // 2 가 부모라는 것을 표로 확인한다.

복원 코드를 Python 3.12 로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 18번C

다음 C 프로그램의 실행 결과를 쓰시오.

#include <stdio.h> #include <stdlib.h> typedef struct Node { int value; struct Node *next; } Node; Node *push(Node *head, int value) { Node *node = malloc(sizeof(Node)); node->value = value; node->next = head; return node; } Node *move_front(Node *head, int target) { if (head == NULL || head->value == target) return head; Node *previous = NULL; Node *current = head; while (current != NULL && current->value != target) { previous = current; current = current->next; } if (current != NULL) { previous->next = current->next; current->next = head; head = current; } return head; } int main(void) { Node *head = NULL; for (int i = 1; i <= 5; i++) head = push(head, i); head = move_front(head, 3); for (Node *p = head; p != NULL; p = p->next) { printf("%d", p->value); } return 0; }
정답35421

— 35421. 1~5 를 앞에 끼워 5 4 3 2 1 이 된 리스트에서 3 을 떼어 맨 앞에 붙인다.

원리push 는 새 노드를 만들어 next 를 지금의 머리에 걸고 새 노드를 머리로 돌려준다. 앞에 끼우는 방식이라 1 · 2 · 3 · 4 · 5 순으로 넣으면 5 → 4 → 3 → 2 → 1 로 거꾸로 선다. move_front 는 목표 노드를 찾을 때까지 previous(바로 앞 노드)와 current 를 나란히 옮기고, 찾으면 앞 노드의 next 를 목표의 다음으로 잇고(사슬에서 빼기), 목표의 next 를 옛 머리로 걸고(맨 앞에 끼우기), 목표를 새 머리로 삼는다. 노드를 새로 만들지 않고 화살표 두 개만 바꾼다.

따라가기

  1. push 다섯 번: 5 → 4 → 3 → 2 → 1
  2. move_front(3): current 5(아님) → previous 5, current 4(아님) → previous 4, current 3(찾음)
  3. previous(4).next = 3.next = 2 → 5 → 4 → 2 → 1
  4. 3.next = 옛 머리 5, head = 3 → 3 → 5 → 4 → 2 → 1
  5. 출력 35421

헷갈리는 자리 — push 가 뒤에 붙인다고 보고 1 2 3 4 5 에서 시작하는 것. node->next = head 가 "새 노드 뒤에 옛 머리"라 앞 끼우기다. 그리고 목표를 뺀 뒤 앞 노드(4)의 next 를 2 로 잇는 줄을 빼먹으면 4 → 3 이 남아 3 이 두 번 나온다.

복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 19번C

다음 C 프로그램의 실행 결과를 쓰시오.

#include <stdio.h> typedef struct { const char *name; int score[3]; } Student; int decode(int value) { return value & 0xA5; } int total(const Student *student) { return decode(student->score[0]) + decode(student->score[1]) + decode(student->score[2]); } int main(void) { Student students[2] = { { "Kim", { 0xA0, 0xA5, 0xDB } }, { "Lee", { 0xA0, 0xED, 0x81 } } }; int result = 0; for (int i = 0; i < 2; i++) result += total(&students[i]); printf("%d", result); return 0; }
정답908

— 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.

  1. 0xA0 = 1010 0000 → 1010 0000 = 0xA0 = 160
  2. 0xA5 = 1010 0101 → 그대로 165
  3. 0xDB = 1101 1011 → 1000 0001 = 0x81 = 129 → Kim 합 454
  4. Lee: 0xA0 → 160, 0xED = 1110 1101 → 1010 0101 = 165, 0x81 = 1000 0001 → 129 → 454
  5. 454 + 454 = 908

헷갈리는 자리 — AND 를 "둘 중 하나라도 1"(OR)로 계산하는 것과, 16진수를 10진수로 먼저 바꾼 뒤 논리 AND(&&)처럼 다루는 것. 한 자리씩 2진수로 펴서 겹치는 1 만 남기는 것이 전부이고, 마지막에 10진수로 돌린다.

복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2025-1회 · 20번Java

다음 Java 프로그램의 실행 결과를 쓰시오.

public class Main { static int calc(int value) { if (value <= 1) return value; return calc(value - 1) + calc(value - 2); } static int calc(String text) { int value = Integer.parseInt(text); if (value <= 1) return value; return calc(value - 1) + calc(value - 3); } public static void main(String[] args) { System.out.println(calc("5")); } }
정답4

— 4. calc("5") 는 String 판에서 시작해 calc(4)calc(2) 를 부르는데, 인자가 int 라 그 뒤로는 전부 int 판(n − 1, n − 2)이다.

원리 — 같은 이름 calc 가 둘인데 하나는 String 을, 하나는 int 를 받는다(오버로딩). 어느 것을 부를지는 넘기는 값의 타입으로 정해진다. calc("5") 는 String 판이고, 그 안의 calc(value - 1) 은 int 를 넘기니 int 판이다. String 판은 딱 한 번만 돌고 규칙(n − 1, n − 3)도 그 한 번에만 쓰인다. 나머지는 int 판의 피보나치 규칙이다. 두 규칙을 언제 바꿔 타는지가 전부다.

따라가기 — int 판: c(0) = 0, c(1) = 1, c(2) = 1, c(3) = 2, c(4) = 3.

  1. calc("5") → value 5 → calc(4) + calc(2) (둘 다 int 판)
  2. calc(4) = c(3) + c(2) = 2 + 1 = 3
  3. calc(2) = c(1) + c(0) = 1
  4. 3 + 1 = 4

헷갈리는 자리 — String 판 규칙(n − 1, n − 3)을 끝까지 쓰는 것. 첫 호출 뒤에는 인자가 int 라 String 판으로 돌아오지 않는다. 반대로 처음부터 int 판으로 보고 c(5) = 5 를 적는 것 — 첫 갈림이 (4, 2) 다.

복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

03채점 뒤 할 일

왜 이걸 하나 — 점수보다 어느 장으로 돌아가느냐가 결과다. 문항마다 가는 장이 정해져 있다.

코드 9문항 중 C 4 · Java 4 · Python 1 이다. 10번은 문자 배열 BADE 에 C 를 끼워 BACDE, 11번은 (i + 1) / 3 과 (i + 1) % 3 으로 격자를 채운 뒤 부호를 번갈아 더해 13 이다. 19번은 0xA0 · 0xA5 · 0xDB 를 0xA5 로 AND 한 값을 더하는 문제라 16진수를 2진수로 펴서 자리마다 AND 한다.

13번은 순서가 전부다. new Derived() → Base 생성자에서 total += ++value(2) → update() 는 Derived 것이라 total += total * 2 → 6 → Derived 생성자에서 value 12, total += 12 → 18, update() 로 54. Base 의 value 와 Derived 의 value 는 이름만 같은 다른 필드라는 것까지 알아야 맞는다.

용어 11문항은 네트워크 3(CRC · ARP/RARP · 서브넷 판정) · SQL·DB 3(무결성 3칸 · 조인 결과표 · 용어 4칸) · SW공학 3(결합도 3칸 · 어댑터 · 문장 번호 순서) · 보안 2(세션 하이재킹 · 스캐어웨어)다. 7번 조회 결과는 열 이름까지 표로 적어야 한다.

문항마다 가는 장

틀린 문항의 「가는 장」을 열면 그 문항이 04절에 그대로 있고, 앞뒤로 같은 꼴의 문항이 붙어 있다. 몰라서 틀렸으면 그 장 03절부터, 알았는데 틀렸으면 05절만 읽는다. 판정 기준은 E01 의 03절 표와 같다.

문항분야가는 장무엇을 묻나
1보안E14세션 하이재킹
2DBE10도메인 · 개체 · 참조 무결성
3네트워크E11다항식 나눗셈 CRC
4보안E14스캐어웨어
5JavaE060 나누기 예외 catch 와 finally
6네트워크E11ARP 와 RARP
7SQLE08두 테이블 조인 조회 결과표
8DBE10degree · cardinality · foreign key · domain
9네트워크E12/22 같은 네트워크 판정
10CE02문자 배열에 한 글자 끼워 넣기
11CE023×3 격자 채우기와 부호 번갈아 합
12SW공학E15내용 · 스탬프 · 공통 결합도
13JavaE05static total 과 생성자에서 오버라이딩 호출
14디자인패턴E17어댑터 패턴
15테스트E18구문 실행 순서 — 문장 번호 나열
16JavaE06분할 재귀 Math.max 합
17PythonE07트리 홀수 레벨 값의 합
18CE03연결 리스트 앞으로 옮기기
19CE04비트 AND 0xA5 점수 합
20JavaE05int · String 오버로딩 재귀 calc("5")

이 회차에서 눈여겨볼 문항

문항왜 갈리나
9번255.255.252.0 은 /22, 셋째 옥텟 블록 4 → 32~35 가 한 네트워크. 보기 다섯이 전부 그 안이라 ㄱㄴㄷㄹㅁ
13번부모 생성자 안의 update() 는 자식 것이 불린다. 2 → 6 → 18 → 54. 순서를 한 줄씩 적는다
15번values = {−3}, count = 1. 문장 번호로 1 → 2 → 3 → 4 → 5 → 2 → 6. 반복이 한 번 더 조건을 검사한다는 것을 빼먹으면 2 가 하나 빠진다
20번calc("5") 는 String 판이라 n − 1 과 n − 3 을 int 판 calc 로 부른다. int 판은 n − 1 과 n − 2 다. 두 규칙이 섞여 4

채점 결과는 오답노트에 회차별 점수와 틀린 문항 목록으로 모인다. 세트를 하나 끝낼 때마다 거기서 같은 장에서 반복해서 틀리는지를 본다. 두 세트에서 같은 장이 나오면 그 장의 06절 훈련을 그날 5문항 푼다.

04다음

왜 이걸 하나 — 세트의 결과는 다음에 열 장의 이름이어야 한다.