2024년 1회 실전 E22

SW공학이 4문항으로 늘고, 페이지 교체 LRU · LFU 와 구성도 서브넷 고르기가 나왔다. 실행 순서 5 → 6 → 3 → 1 → 7 → 2 도 여기다

왜 이 장을 하나
2024년 1회는 계산 문항이 셋이다. 9번 LRU · LFU 부재 횟수, 5번 구성도에서 같은 서브넷 고르기, 10번 생성자 실행 순서. 셋 다 답이 하나뿐이라 절차를 종이에 적으면 15점이 확실해진다. 19번 시저 변환은 대문자 · 소문자 · 숫자의 규칙이 다른 것을 세 번 적용하는 문제다.
다루는 것2024년 1회 20문항 · 복원본
시계150분 · 실제 시험과 같다
끝나면문항마다 가는 장이 표로 나온다

01푸는 법

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

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

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

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

02실전 세트

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

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

2024-1회 · 1번Java

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

class Counter { private static final Counter INSTANCE = new Counter(); private int value = 0; private Counter() { } static Counter getInstance() { return INSTANCE; } void add() { value++; } int getValue() { return value; } } public class Main { public static void main(String[] args) { Counter a = Counter.getInstance(); Counter b = Counter.getInstance(); a.add(); b.add(); a.add(); b.add(); System.out.print(a.getValue()); } }
정답4

— 4. getInstance 가 늘 같은 객체 하나를 돌려주므로 a 와 b 는 같은 Counter 이고, add 네 번이 전부 그 한 칸에 쌓인다.

원리 — 이 클래스는 싱글톤 꼴이다. 생성자가 private 이라 밖에서 new Counter() 를 못 하고, 클래스 안에서 static final INSTANCE 로 딱 한 번 만든 객체를 getInstance() 가 돌려준다. 그래서 몇 번을 받아 와도 같은 객체다. a 와 b 는 이름만 둘이지 가리키는 것은 하나라, a.add() 도 b.add() 도 같은 value 를 올린다.

따라가기

  1. a = INSTANCE, b = INSTANCE (같은 객체)
  2. add 네 번 → value 0 → 1 → 2 → 3 → 4
  3. a.getValue() → 4

헷갈리는 자리 — a 와 b 를 다른 객체로 보고 a 의 add 두 번만 세어 2 를 적는 것. private 생성자 + static 인스턴스 + getInstance 의 세 줄이 보이면 "객체는 하나"다. 디자인 패턴 장의 싱글톤이 코드로 나온 것이다.

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

2024-1회 · 2번C

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

#include <stdio.h> int main(void) { int x = 37; int y = (x > 20) ? (x << 2) : (x >> 1); printf("%d", y + 3); return 0; }
정답151

— 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진수를 안 적어도 된다.

따라가기

  1. x = 37, 조건 37 > 20 참 → x << 2 선택
  2. 37 × 4 = 148 (2진수로 100101 → 10010100)
  3. y + 3 = 148 + 3 = 151

헷갈리는 자리 — 조건이 거짓인 쪽(37 >> 1 = 18)까지 계산해 섞는 것. 삼항은 한쪽만 계산한다. 시프트를 "2를 더한다"로 착각해 39 를 적는 것도 흔하다 — 시프트는 곱하기 · 나누기다.

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

2024-1회 · 3번SW공학

다음 응집도를 높은 것부터 순서대로 나열하시오: ㄱ. 기능적 ㄴ. 교환(통신)적 ㄷ. 우연적 ㄹ. 시간적

정답ㄱ → ㄴ → ㄹ → ㄷ (기능적 > 교환적 > 시간적 > 우연적)

— ㄱ → ㄴ → ㄹ → ㄷ. 기능적 > 교환(통신)적 > 시간적 > 우연적 순서다.

원리 — 응집도는 "한 모듈 안의 것들이 얼마나 한 가지 일을 위해 모였나"다. 높을수록 좋다. 7단계를 높은 쪽부터 외운다 — 기능적(한 가지 일) > 순차적(앞 출력이 뒤 입력) > 교환적(같은 데이터를 쓴다) > 절차적(순서대로 실행된다) > 시간적(같은 때 실행된다) > 논리적(비슷해 보여 모았다) > 우연적(아무 관계 없다). 위로 갈수록 "왜 같이 있는가"의 이유가 강하다. 기능적은 "이 일을 하려고", 교환적은 "같은 자료를 다루니까", 시간적은 "같은 시점에 도니까(초기화 · 종료)", 우연적은 "그냥"이다.

따라가기

  1. 보기 4개를 7단계 표에 놓는다 — 기능적 1위, 교환적 3위, 시간적 5위, 우연적 7위
  2. 높은 것부터 → 기능적(ㄱ) → 교환적(ㄴ) → 시간적(ㄹ) → 우연적(ㄷ)
  3. ㄱ → ㄴ → ㄹ → ㄷ

헷갈리는 자리 — 순차적과 교환적의 자리를 바꾸는 것. 순차적(출력 → 입력 연결)이 교환적(같은 데이터만 공유)보다 높다. 그리고 문제가 "높은 것부터"인지 "낮은 것부터"인지 반드시 확인한다 — 결합도 문제는 낮은 것부터 묻는 경우가 많아 방향을 헷갈리기 쉽다.

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

2024-1회 · 4번C

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

#include <stdio.h> #include <string.h> int main(void) { char word[] = "ABCDEFG"; int n = (int)strlen(word); for (int i = n - 1; i >= 0; i -= 2) putchar(word[i]); return 0; }
정답GECA

— GECA. 마지막 글자부터 두 칸씩 건너뛰며 앞으로 온다.

원리strlen("ABCDEFG") 은 7 이고 첨자는 0 부터 6 까지다. 반복은 i = n - 1(6, 마지막 글자)에서 시작해 i -= 2 로 두 칸씩 줄어들며 i >= 0 인 동안 돈다. 즉 6 · 4 · 2 · 0 네 자리를 차례로 찍는다. putchar 는 글자 하나를 줄바꿈 없이 찍는 함수다. "역순 + 건너뛰기"는 시작 첨자, 감소량, 멈춤 조건 세 가지를 적어 두면 틀릴 데가 없다.

따라가기

  1. 첨자: 0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G
  2. i = 6 → G, i = 4 → E, i = 2 → C, i = 0 → A
  3. i = −2 → 조건 i >= 0 거짓 → 끝. GECA

헷갈리는 자리 — n 을 7 로 두고 첨자 7 부터 시작하는 것(끝표 자리라 아무것도 안 찍히거나 엉뚱한 값). 마지막 첨자는 길이 − 1 이다. 그리고 i > 0 이었다면 0 번 A 가 빠져 GEC 가 된다 — 등호 유무를 본다. putchar 는 줄바꿈을 넣지 않으므로 네 글자가 한 줄에 붙고, strlen 을 쓰려면 string.h 가 있어야 한다는 것도 시험에서 빈칸으로 나올 수 있는 자리다.

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

2024-1회 · 5번네트워크

다음 구성도에서 각 라우터 인터페이스와 같은 서브넷에 할당할 수 있는 호스트 주소를 보기에서 고르시오. 구성도는 네트워크 A — 라우터 — 네트워크 B — 라우터 — 네트워크 C 로 이어지고, 각 네트워크에 인터페이스가 2개씩 있다.

네트워크인터페이스주소
A1192.168.35.3/24
A2( )
B3129.200.10.16/22
B4( )
C5( )
C6192.168.36.24/24

보기

번호후보 주소
1192.168.35.0
2192.168.35.72
3192.168.36.0
4129.200.8.249
5192.168.36.249
6129.200.8.0
정답2, 4, 5 (② 192.168.35.72 · ④ 129.200.8.249 · ⑤ 192.168.36.249)

— 2, 4, 5. 각 네트워크의 호스트 범위에 드는 후보만 고르고, 네트워크 주소(마지막 옥텟 0 등)는 뺀다.

원리 — 같은 서브넷에 속하려면 프리픽스만큼의 앞부분이 같아야 한다. A 는 192.168.35.x/24 라 192.168.35.1~254 가 호스트 범위이고 192.168.35.0(네트워크 주소) · 255(브로드캐스트)는 못 쓴다. B 는 /22 라 셋째 옥텟이 4 씩 묶인다 — 129.200.10.16 은 8~11 묶음이니 네트워크 129.200.8.0, 호스트 129.200.8.1~129.200.11.254 다. C 는 192.168.36.1~254. 후보 여섯을 이 세 범위에 넣어 보면 된다.

따라가기

  1. 1: 192.168.35.0 → A 의 네트워크 주소 → 불가
  2. 2: 192.168.35.72 → A 범위 안 → 가능
  3. 3: 192.168.36.0 → C 의 네트워크 주소 → 불가
  4. 4: 129.200.8.249 → B 범위(8.1~11.254) 안 → 가능
  5. 5: 192.168.36.249 → C 범위 안 → 가능, 6: 129.200.8.0 → B 의 네트워크 주소 → 불가

헷갈리는 자리 — 129.200.8.249 를 "10 이 아니라 8 이니 다른 망"으로 보는 것. /22 는 셋째 옥텟 8~11 이 한 망이다 — 마스크 255.255.252.0 에서 256 − 252 = 4 가 묶음 크기다. 마지막 옥텟이 0 인 주소를 호스트로 고르는 것도 흔한 오답이다.

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

2024-1회 · 6번DB

다음 릴레이션이 만족하는 제1~제3정규형 중 가장 높은 정규형을 쓰시오. 기본키는 (고객아이디, 강좌명)이며, 강사번호는 기본키 전체에만 함수 종속된다고 가정한다.

강좌신청

고객아이디강좌명강사번호
apple영어회화P001
banana기초토익P002
carrot영어회화P001
carrot기초토익P004
orange영어회화P003
orange기초토익P004
정답제3정규형

— 제3정규형. 복합키 전체에만 종속된 속성 하나뿐이라 부분 종속도 이행 종속도 없다.

원리 — 정규형은 사다리다. 제1정규형: 모든 값이 더 쪼갤 수 없는 하나의 값. 제2정규형: 1NF 이면서, 기본키가 여러 속성(복합키)일 때 그 일부에만 매달린 속성(부분 함수 종속)이 없다. 제3정규형: 2NF 이면서, 키가 아닌 속성이 다른 키 아닌 속성을 거쳐 매달리는 일(이행 함수 종속, A → B → C)이 없다. 이 표는 키가 (고객아이디, 강좌명)이고 키 아닌 속성은 강사번호 하나뿐이며 "기본키 전체에만 종속"이라고 했으니 부분 종속이 없고, 키 아닌 속성이 하나라 이행 종속도 생길 수 없다.

따라가기

  1. 값이 전부 원자값 → 1NF
  2. 강사번호가 키 전체에만 종속 → 부분 종속 없음 → 2NF
  3. 키 아닌 속성이 하나뿐 → 이행 종속 없음 → 3NF

헷갈리는 자리 — 강좌명 → 강사번호(같은 강좌면 같은 강사)로 보고 부분 종속이라 판단해 1NF 라 적는 것. 표를 보면 영어회화의 강사가 P001 · P003 으로 다르니 강좌명만으로는 강사가 정해지지 않고, 문제도 "기본키 전체에만 종속"이라고 못 박았다. BCNF 냐고 물으면 결정자가 키 전체뿐이라 BCNF 도 만족하지만, 보기가 1~3 이면 3NF 다.

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

2024-1회 · 7번네트워크

링크 상태(Link-State) 기반의 내부 라우팅 프로토콜로, 다익스트라 알고리즘으로 최단 경로를 계산하는 것은? (영문 약자)

정답OSPF

— OSPF. 망 전체의 링크 상태를 모아 다익스트라로 최단 경로를 계산하는 내부 라우팅 프로토콜이다.

원리 — RIP 이 이웃의 말만 듣고 표를 만든다면, OSPF(Open Shortest Path First)는 모든 라우터가 자기 링크의 상태(누구와 얼마의 비용으로 이어졌나)를 망 전체에 알려 같은 지도를 갖게 하고, 각자 다익스트라 알고리즘으로 자기부터의 최단 경로 트리를 계산한다. 변화가 있을 때만 알리므로 수렴이 빠르고 홉 제한이 없으며, 큰 망은 영역(Area)으로 나눠 관리한다. 비용은 대역폭 기반이라 홉이 많아도 빠른 길을 고른다.

따라가기

  1. 링크 상태 + 다익스트라 + 내부 → OSPF

헷갈리는 자리 — RIP(거리 벡터 · 벨만-포드 · 홉 15)과 바꾸는 것. "다익스트라"라는 낱말이 보이면 OSPF 다. BGP 는 외부(자율 시스템 사이)라 "내부"라는 조건에서 빠진다.

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

2024-1회 · 8번DB

조인 유형 매칭: ① 비교 연산자(=, >, < 등)를 사용하는 일반 조인 ② =만 사용하는 조인 ③ 동등 조인에서 중복 속성을 제거한 조인

정답① 세타 조인 ② 동등 조인 ③ 자연 조인

— ① 세타 조인 ② 동등 조인 ③ 자연 조인. 조인 조건의 연산자와 중복 열 처리로 나뉘는 세 이름이다.

원리 — 조인은 두 표의 행을 조건으로 짝짓는 것이다. 조건에 어떤 비교 연산자(=, >, < …)든 쓸 수 있는 가장 넓은 꼴이 세타 조인(θ 는 "임의의 비교"라는 뜻)이다. 그중 = 만 쓴 것이 동등 조인이고, 동등 조인 결과에는 같은 값의 열이 두 번 나온다(양쪽 표의 부서코드). 그 중복 열을 하나로 줄인 것이 자연 조인이다. 세타 ⊃ 동등 ⊃ 자연 순으로 좁아진다.

따라가기

  1. 비교 연산자 아무거나 → 세타 조인
  2. = 만 → 동등 조인
  3. 동등 조인 + 중복 속성 제거 → 자연 조인

헷갈리는 자리 — 동등과 자연을 바꾸는 것. "중복 제거"가 붙으면 자연이다. 외부 조인(LEFT · RIGHT · FULL)은 짝이 없는 행도 남기는 별개의 묶음이라 여기 세 개와 섞지 않는다.

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

2024-1회 · 9번OS

페이지 프레임이 3개이고 참조 문자열이 다음과 같을 때 LRU와 LFU의 페이지 부재 횟수를 각각 구하시오.

1, 2, 3, 1, 2, 4, 1, 2, 5, 7

정답LRU 6회, LFU 6회

— LRU 6회, LFU 6회. 프레임 3개에 1 · 2 · 3 을 채운 뒤 4 · 5 · 7 이 들어올 때마다 부재가 나 둘 다 6번이다.

원리 — 페이지 부재(page fault)는 필요한 페이지가 프레임에 없어 디스크에서 가져오는 일이다. 프레임이 꽉 찼을 때 누구를 내보내느냐가 교체 알고리즘이다. LRU(Least Recently Used)는 "가장 오래 안 쓴" 페이지를, LFU(Least Frequently Used)는 "가장 적게 쓴" 페이지를 내보낸다. 처음 세 개는 빈 프레임을 채우므로 무조건 부재 3번이다. 그다음부터 "이미 있나(적중)" 아니면 "없어서 교체(부재)"를 한 칸씩 표로 따라간다.

따라가기

  1. 1 · 2 · 3 → 빈 프레임 채움, 부재 3 (프레임 [1 2 3])
  2. 1 · 2 → 적중
  3. 4 → 부재. LRU: 가장 오래 안 쓴 3 교체 / LFU: 1 · 2 는 2회, 3 은 1회라 3 교체 → [1 2 4], 부재 4
  4. 1 · 2 → 적중
  5. 5 → 부재. LRU: 4 가 가장 오래 / LFU: 4 는 1회 → 4 교체 → [1 2 5], 부재 5
  6. 7 → 부재. LRU: 1 이 가장 오래(2 · 5 가 더 최근) / LFU: 5 가 1회 → 교체, 부재 6
  7. 둘 다 6회

헷갈리는 자리 — LRU 에서 마지막 7 이 들어올 때 누가 나가는지는 답(부재 횟수)에 영향이 없다 — 횟수만 묻는 문제면 교체 대상을 따질 필요 없이 "없으면 부재"만 세면 된다. 그러나 최종 프레임 상태를 묻는 문제라면 LRU 는 [7 2 5], LFU 는 [1 2 7] 로 달라지니 구분해 둔다.

표를 손으로 한 칸씩 채우고 파이썬 시뮬레이션 스크립트로 같은 값을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.

2024-1회 · 10번Java

다음 Java 코드에서 번호가 붙은 부분의 실행 순서를 중복 번호 없이 쓰시오.

class Parent { Parent(int a, int b) { } // ① void getT() { } // ② } class Child extends Parent { Child(int x) { // ③ super(x + 1, x); } void getT(int value) { } // ④ } public class Main { public static void main(String[] args) { // ⑤ Parent p = new Child(3); // ⑥ p.getT(); // ⑦ } }
정답⑤ → ⑥ → ③ → ① → ⑦ → ②

— ⑤ → ⑥ → ③ → ① → ⑦ → ②. main 이 시작되고, 자식 생성자가 부모 생성자를 부른 뒤, getT() 는 부모의 것이 불린다.

원리 — 객체를 만들 때는 자식 생성자에 먼저 들어가지만, 그 첫 줄의 super(…) 가 부모 생성자를 부르므로 실제로 몸통이 먼저 끝나는 것은 부모 쪽이다. 그래서 순서는 "자식 진입 → 부모 완료 → 자식 완료"다. Child 의 getT(int value) 는 인자를 받으니 Parent 의 getT() 와 다른 메서드(오버로딩)이고, p.getT() 는 인자가 없으니 부모 것이다. 번호를 "실행이 그 줄에 도달한 순서"로 적는다.

따라가기

  1. ⑤ main 시작
  2. ⑥ new Child(3) 평가 시작 → ③ Child 생성자 진입 → super(4, 3) → ① Parent 생성자
  3. ⑦ p.getT() 호출 → ② Parent.getT 실행
  4. ④ 는 인자 있는 다른 메서드라 한 번도 안 불린다

헷갈리는 자리 — ① 을 ③ 보다 앞에 두는 것. 부모 생성자가 먼저 "끝나지만" 진입은 자식이 먼저라, 문제가 "실행 순서"를 물으면 ③ → ① 이다. ④ 를 넣어 ⑦ → ④ 로 적는 것 — getT()getT(int) 는 다른 메서드다. 2023년 1회 17번과 같은 함정이다.

각 자리에 출력문을 넣어 JDK 17 로 실행해 순서를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.

2024-1회 · 11번C

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

#include <stdio.h> typedef struct { int balance; double savings; } Account; void withdraw(Account *a, int amount) { a->balance -= amount; } void add_interest(Account *a, double rate) { a->savings *= (1.0 + rate); } int main(void) { Account a = { 10000, 2713.69 }; withdraw(&a, 19); add_interest(&a, 0.03); printf("%d and %.2f", a.balance, a.savings); return 0; }
정답9981 and 2795.10

9981 and 2795.10. 잔액에서 19 를 빼고, 저축액에 3% 이자를 붙여 소수 둘째 자리까지 찍는다.

원리 — 함수에 구조체의 주소(&a)를 넘기면 함수 안에서 a->balance 처럼 원본의 칸을 직접 고칠 수 있다. 값을 넘겼다면 복사본만 바뀌어 main 의 a 는 그대로였을 것이다. a->savings *= (1.0 + rate) 는 "저축액에 1.03 을 곱해 다시 저축액에 넣어라"다. %d 는 정수를 그대로, %.2f 는 실수를 소수 둘째 자리에서 반올림해 찍는다. 문자열 안의 " and " 는 서식이 아니라 그대로 찍히는 글자다.

따라가기

  1. a = {balance 10000, savings 2713.69}
  2. withdraw(&a, 19) → balance = 10000 − 19 = 9981
  3. add_interest(&a, 0.03) → savings = 2713.69 × 1.03 = 2795.1007
  4. %.2f → 2795.10 → 화면 9981 and 2795.10

헷갈리는 자리 — 2795.1 로 적는 것. 서식이 둘째 자리까지라 끝의 0 도 적어야 한다. 이자를 더하기(2713.69 + 0.03)로 착각하는 것 — 곱셈 대입(*=)이다. 답에는 " and " 까지 문제의 출력 그대로 들어간다.

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

2024-1회 · 12번Python

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

words = ["Seoul", "Kyeonggi", "Incheon", "Daejun", "Daegu", "Pusan"] result = "S" for word in words: result += word[1] print(result)
정답Seynaau

— Seynaau. 처음 S 에 각 도시 이름의 둘째 글자를 차례로 이어 붙인다.

원리 — 문자열도 첨자로 글자 하나를 꺼낼 수 있고 첨자는 0 부터라 word[1] 은 둘째 글자다. result += word[1] 은 "지금 result 뒤에 그 글자를 붙여라"다. for 문은 리스트의 도시 이름을 순서대로 하나씩 word 에 넣는다. 결국 답은 "S" + (각 이름의 둘째 글자들)이다.

따라가기

  1. Seoul → e, Kyeonggi → y, Incheon → n
  2. Daejun → a, Daegu → a, Pusan → u
  3. "S" + "eynaau" → Seynaau

헷갈리는 자리 — word[1] 을 첫 글자로 읽어 "SSKIDDP" 를 적는 것. 0 이 첫 글자, 1 이 둘째다. 처음의 "S" 를 빼먹고 eynaau 만 적는 것 — result 의 초기값이 답의 첫 글자다. 대소문자도 그대로 적는다. 문자열은 바꿀 수 없는 값이라 += 는 원래 문자열을 고치는 것이 아니라 새 문자열을 만들어 result 에 다시 담는 것인데, 결과만 보면 "뒤에 붙이기"로 읽어도 된다.

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

2024-1회 · 13번SQL

다음 SQL을 실행한 결과를 쓰시오.

SAMPLE

AB
1a
2b
3c
SELECT B FROM SAMPLE WHERE A IN ( SELECT A FROM SAMPLE WHERE A <= 2 );
정답열 이름 B, 값 a · b (2행)

— 열 B 에 a / b 두 행. 안쪽 SELECT 가 A ≤ 2 인 A 값 {1, 2} 를 만들고, 바깥은 A 가 그 안에 있는 행의 B 를 뽑는다.

원리 — 괄호 안 SELECT(서브쿼리)가 먼저 계산돼 값의 목록이 되고, A IN (목록) 은 "A 가 목록 중 하나와 같다"는 조건이다. 안쪽이 같은 테이블을 읽어도 상관없다 — 먼저 목록을 만들고 그다음 바깥이 그 목록으로 거른다고 두 단계로 읽으면 된다. 결과 열은 SELECT 뒤의 B 하나뿐이다.

따라가기

  1. 안쪽: A <= 2 인 행 → A = 1, 2 → 목록 (1, 2)
  2. 바깥: A IN (1, 2) 인 행 → 첫째 · 둘째 행
  3. 그 행들의 B → a, b

헷갈리는 자리 — 안쪽 SELECT 가 A 를 뽑는다고 답에 A 값 1, 2 를 적는 것. 결과 열은 바깥 SELECT 의 B 다. 조건이 < 2 였다면 a 한 행뿐이다 — 등호를 본다. IN 대신 = (SELECT …) 를 쓰면 서브쿼리가 두 행을 돌려줘 오류가 난다 — 여러 값에는 IN 이다.

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

2024-1회 · 14번테스트

개별 조건식이 다른 조건식에 영향을 받지 않고 전체 결정 결과에 독립적으로 영향을 주도록 설계하는 커버리지는?

정답변경 조건/결정 커버리지 (MC/DC)

— 변경 조건/결정 커버리지(MC/DC, Modified Condition/Decision Coverage). 각 조건이 "혼자서" 결정 결과를 뒤집는 케이스를 요구한다.

원리 — if (A && B) 에서 조건/결정 커버리지는 A · B · 전체가 각각 T/F 를 한 번씩 갖기만 하면 된다. 그런데 (T,T)=T 와 (F,F)=F 두 케이스도 이를 만족하는데, 이때 A 가 결과를 바꾼 건지 B 가 바꾼 건지 알 수 없다. MC/DC 는 "다른 조건은 고정한 채 이 조건만 바꿨을 때 결정이 바뀐다"는 짝을 조건마다 요구한다 — A 는 (T,T)=T 와 (F,T)=F, B 는 (T,T)=T 와 (T,F)=F. 그러면 세 케이스로 각 조건이 독립적으로 결과에 영향을 준다는 것이 증명된다. 다중 조건 커버리지(모든 조합 2ⁿ)보다 훨씬 적은 n+1 개로 되어 항공(DO-178) 같은 안전 필수 분야가 요구한다.

따라가기

  1. "개별 조건식이 다른 조건식에 영향을 받지 않고" → 나머지는 고정
  2. "전체 결정 결과에 독립적으로 영향" → 혼자 뒤집는다 → MC/DC

헷갈리는 자리 — 조건/결정 커버리지로 적는 것. 조건/결정은 "각각 T/F 한 번씩"이고, MC/DC 는 거기에 "독립적으로 영향"이라는 조건이 붙는다. 문제에 "독립적 · 영향"이 있으면 MC/DC 다. 다중 조건은 "모든 조합"이라 또 다르다.

표준 · 교재 정의(ISTQB 용어 · 커버리지 6단계 · 테스트 수준)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2024-1회 · 15번보안

시스템에 깊숙이 은폐되어 관리자(root) 권한을 탈취하고, 로그 삭제 등으로 침입 흔적을 숨기는 악성코드는?

정답루트킷 (Rootkit)

— 루트킷(Rootkit). 관리자(root) 권한을 쥐고 시스템 깊숙이 숨어 흔적을 지우는 악성코드 도구 모음이다.

원리 — root 는 유닉스의 최고 관리자, kit 는 도구 모음이다. 루트킷은 커널이나 시스템 명령을 바꿔치기해 프로세스 목록 · 파일 목록 · 로그에서 자기를 안 보이게 만들고, 뒷문을 열어 공격자가 계속 들어오게 한다. 백신이 시스템 명령을 믿고 돌면 속으므로 잡기 어렵다. "은폐 · 관리자 권한 · 흔적 삭제"가 표지다.

따라가기

  1. 깊숙이 은폐 + root 권한 탈취 + 로그 삭제 → 루트킷

헷갈리는 자리 — 백도어(뒷문)만 적는 것. 루트킷은 뒷문에 은폐 기능까지 갖춘 것이다. 트로이 목마는 들어오는 방법(위장)이고 루트킷은 들어온 뒤 숨는 방법이라 층이 다르다. 커널 수준 루트킷은 운영체제 밑에서 돌아 재설치 말고는 지우기 어렵다.

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

2024-1회 · 16번Java

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

class NumberBox { int calculate(int n) { return n + 1; } } class SquareBox extends NumberBox { @Override int calculate(int n) { return n * n; } } public class Main { public static void main(String[] args) { NumberBox box = new SquareBox(); System.out.print(box.calculate(3)); } }
정답9

— 9. 부모 타입으로 담았어도 실제 객체가 SquareBox 이므로 갈아끼운 calculate(n × n)가 돌아 3 × 3 이다.

원리 — 자식이 부모와 이름 · 매개변수가 같은 메서드를 다시 정의하면(오버라이딩) 그 객체에서는 언제나 자식 판이 돈다. 변수의 겉모양(NumberBox box)은 "무엇을 부를 수 있는가"만 정하고, "어느 판이 도는가"는 new SquareBox() 가 정한다. @Override 는 컴파일러에게 "이건 갈아끼우기다, 부모에 같은 메서드가 없으면 오류를 내라"고 알리는 표시일 뿐 동작을 바꾸지는 않는다.

따라가기

  1. box 의 겉 NumberBox, 속 SquareBox
  2. box.calculate(3) → 속의 판 → 3 × 3 = 9

헷갈리는 자리 — 겉이 NumberBox 니까 n + 1 = 4 라고 적는 것. 필드라면 겉을 따르지만 메서드는 속을 따른다. 이 규칙 하나가 자바 문제 절반의 뼈대라 "필드는 겉, 메서드는 속"으로 외운다. 만약 SquareBox 가 calculate 를 안 만들었다면 부모 것이 돌아 4 가 됐을 것이다.

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

2024-1회 · 17번보안

특정 조직·표적을 겨냥해 장기간에 걸쳐 은밀하고 지속적으로 수행하는 지능형 공격을 뜻하는 용어는? (영문 약자 3글자)

정답APT

— APT. 특정 표적을 노려 오래, 조용히, 끈질기게 파고드는 지능형 지속 공격이다.

원리 — 보통 공격은 아무나 걸리길 바라며 뿌리지만, APT(Advanced Persistent Threat)는 한 조직을 정해 사회공학(표적 이메일)으로 들어가 몇 달씩 잠복하며 권한을 넓히고 자료를 조금씩 빼낸다. Advanced(여러 기법 결합), Persistent(오래 머묾), Threat(위협)이 이름이다. 정부 · 대기업 대상 공격이 대개 이것이고, 발견이 늦다는 것이 특징이다.

따라가기

  1. 특정 표적 + 장기간 + 은밀 · 지속 → APT

헷갈리는 자리 — DDoS(시끄럽고 짧다)나 피싱(한 수단일 뿐)을 적는 것. "장기간 · 지속"이 APT 의 표지이고 약자 세 글자를 답한다. 워터링 홀(2026년 1회 16번)이 APT 의 초기 침투 수단으로 자주 짝지어 나온다.

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

2024-1회 · 18번SQL

다음 SQL문의 실행 결과를 쓰시오.

RESULT

IDKINDSCORE
1A70
2B90
3A50
4C95
SELECT COUNT(*) FROM RESULT WHERE KIND = 'A' AND SCORE >= 80 OR KIND = 'C';
정답1

— 1. ANDOR 보다 먼저 묶이므로 "(KIND = 'A' 이고 SCORE ≥ 80) 또는 KIND = 'C'" 이고, 앞 조건은 없고 뒤 조건은 한 행이다.

원리 — SQL 에서 AND 는 OR 보다 우선순위가 높다. 괄호가 없으면 a AND b OR c(a AND b) OR c 로 읽는다. 그래서 이 조건은 "A 이면서 80점 이상"인 행과 "C 인 행" 둘을 합친 것이다. A 의 점수는 70 과 50 이라 앞쪽은 0 행, C 는 4번 행 하나다. COUNT(*) 는 조건을 통과한 행 수다.

따라가기

  1. KIND = 'A' AND SCORE >= 80 → A 는 70 · 50 → 0 행
  2. OR KIND = 'C' → 4번 행 → 1 행
  3. COUNT(*) → 1

헷갈리는 자리 — 왼쪽부터 묶어 KIND = 'A' AND (SCORE >= 80 OR KIND = 'C') 로 읽으면 0 행이 된다. 반대로 괄호를 (… OR KIND = 'C') 에 넣어 3 행으로 세는 것도 오답이다. AND 먼저, 그다음 OR — 이 우선순위 하나를 묻는 문제다.

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

2024-1회 · 19번C

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

#include <stdio.h> #include <ctype.h> int main(void) { char text[] = "It is 8"; for (int i = 0; text[i] != '\x00'; i++) { if (isupper((unsigned char)text[i])) text[i] = (char)('A' + (text[i] - 'A' + 5) % 26); else if (islower((unsigned char)text[i])) text[i] = (char)('a' + (text[i] - 'a' + 10) % 26); else if (isdigit((unsigned char)text[i])) text[i] = (char)('0' + (text[i] - '0' + 3) % 10); } printf("%s", text); return 0; }
정답Nd sc 1

Nd sc 1. 대문자는 5칸, 소문자는 10칸, 숫자는 3칸 뒤로 미는 자리바꿈(시저 암호)이다.

원리 — 글자는 코드값이라 text[i] - 'A' 는 "A 로부터 몇 번째 글자인가"다. 거기에 밀 칸 수를 더하고 26 으로 나눈 나머지를 취하면 Z 를 넘어도 A 로 돌아온다. 마지막에 'A' + … 로 다시 글자로 만든다. 숫자도 같은 꼴로 '0' 기준 10칸이다. isupper · islower · isdigit 은 글자 종류를 가르는 함수이고, 공백은 셋 다 아니라 그대로 남는다. 세 종류가 밀리는 칸 수가 다르다는 것이 이 문제의 핵심이다.

따라가기

  1. I(대문자): (8 + 5) % 26 = 13 → 'A' + 13 = N
  2. t(소문자): (19 + 10) % 26 = 3 → 'a' + 3 = d
  3. 공백 → 그대로
  4. i: (8 + 10) % 26 = 18 → s, s: (18 + 10) % 26 = 2 → c
  5. 공백 → 그대로, 8(숫자): (8 + 3) % 10 = 1 → 1
  6. 합쳐서 Nd sc 1

헷갈리는 자리 — 대문자와 소문자를 같은 5칸으로 밀어 t 를 y 로 적는 것. 조건문이 셋으로 갈라진 이유가 밀 칸 수가 다르기 때문이다. s 는 18 + 10 = 28 이 26 을 넘어 2 로 돌아온다 — 나머지 연산을 잊으면 알파벳 밖으로 나간다. 공백 두 개도 답에 그대로 있다.

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

2024-1회 · 20번디자인패턴

구체적인 클래스를 지정하지 않고, 서로 관련된 객체들의 군(family)을 생성하기 위한 인터페이스를 제공하는 생성 패턴은?

정답추상 팩토리 (Abstract Factory)

— 추상 팩토리(Abstract Factory). 서로 어울리는 객체 "묶음"을 구체 클래스 이름 없이 만들어 주는 생성 패턴이다.

원리 — 버튼 · 체크박스 · 창을 만드는데 윈도우용과 맥용이 따로 있다고 하자. 클라이언트가 new WinButton() 처럼 구체 클래스를 직접 쓰면 OS 를 바꿀 때 코드를 전부 고쳐야 한다. 추상 팩토리는 createButton() · createCheckbox() 를 가진 팩토리 인터페이스를 두고, WinFactory · MacFactory 가 각각 자기 계열 부품을 만든다. 클라이언트는 팩토리 하나만 받아 부품을 만들므로 팩토리를 바꾸면 계열 전체가 함께 바뀐다 — "관련된 객체들의 군(family)"을 일관되게 만든다는 것이 핵심이다. 그래서 별명이 Kit 다.

따라가기

  1. "구체적인 클래스를 지정하지 않고" → 인터페이스로 만든다
  2. "서로 관련된 객체들의 군(family)을 생성" → 낱개가 아니라 묶음
  3. 생성 패턴 → 추상 팩토리

헷갈리는 자리 — 팩토리 메서드(Factory Method)를 적는 것. 팩토리 메서드는 "객체 하나"를 만드는 메서드를 하위 클래스가 재정의하는 것이고, 추상 팩토리는 "관련 객체 여러 개(군)"를 만드는 팩토리 객체를 갈아끼우는 것이다. "군 · family · 집합 · Kit" 이 보이면 추상 팩토리다.

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

03채점 뒤 할 일

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

코드 8문항 중 C 4 · Java 3 · Python 1 이다. 1번 싱글톤 카운터는 두 참조가 같은 객체라 4, 16번은 @Override 로 바뀐 calculate(3) 이 9 다. 11번은 구조체 포인터로 잔액과 이자를 갱신해 %.2f 로 찍는 문제라 소수 둘째 자리까지 적어야 한다.

10번 실행 순서는 코드에 붙은 번호로 main 5 → new Child(3) 6 → Child 생성자 3 → super 로 Parent 생성자 1 → p.getT() 7 → Parent 의 getT 2 다. Child 의 getT(int) 는 인자가 있어 오버로딩이라 4 는 안 불린다. 2023년 1회 17번과 같은 함정이다.

용어 12문항은 SW공학 4(응집도 순서 · MC/DC · 추상 팩토리 · LRU/LFU) · SQL·DB 4(정규형 · 조인 3종 · IN 서브쿼리 · AND/OR 우선순위) · 네트워크 2(구성도 · OSPF) · 보안 2(루트킷 · APT)다. 18번은 AND 가 OR 보다 먼저 묶여 KIND 가 C 인 한 행만 남아 1 이다.

문항마다 가는 장

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

문항분야가는 장무엇을 묻나
1JavaE06싱글톤 인스턴스 공유 카운터
2CE04삼항 연산자와 시프트 x << 2
3SW공학E15응집도 높은 순서 나열
4CE03문자열 뒤에서 두 칸씩 출력
5네트워크E12구성도 인터페이스와 같은 서브넷 호스트 고르기
6DBE10복합키 릴레이션의 최고 정규형
7네트워크E12링크 상태 OSPF
8DBE10세타 · 동등 · 자연 조인
9OSE16LRU · LFU 페이지 부재 횟수
10JavaE05생성자 super 호출 실행 순서
11CE03구조체 포인터로 잔액 · 이자 갱신
12PythonE07단어마다 둘째 글자 이어 붙이기
13SQLE08IN 서브쿼리 결과 행
14테스트E18MC/DC 커버리지
15보안E14루트킷
16JavaE05@Override 로 바뀐 calculate(3)
17보안E14APT 지능형 지속 공격
18SQLE08AND 가 OR 보다 먼저 — COUNT 결과
19CE03대문자 · 소문자 · 숫자 자리 밀기(시저)
20디자인패턴E17관련 객체 군 생성 — 추상 팩토리

이 회차에서 눈여겨볼 문항

문항왜 갈리나
5번192.168.35.x/24 · 129.200.10.x/22 · 192.168.36.x/24 세 네트워크. 후보 주소를 각 네트워크 범위에 넣어 보고 네트워크 주소 · 브로드캐스트는 뺀다
9번프레임 3개에 1 2 3 1 2 4 1 2 5 7. LRU 도 LFU 도 부재 6회 — 표를 그려 한 줄씩 채운다
18번KIND = 'A' AND SCORE >= 80 이 먼저 묶인다. A 는 70 · 50 이라 없고 C 한 행만 → 1
19번대문자는 +5, 소문자는 +10, 숫자는 +3 을 각각 26 · 26 · 10 으로 나눈 나머지. I→N, t→d, i→s, s→c, 8→1. Nd sc 1

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

04다음

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