2025년 2회 실전 E26

SQL 작성 · 조회가 0문항인 유일한 회차. 대신 구조체 · 포인터 4문항과 라운드 로빈 · 람다 예외가 나왔다

왜 이 장을 하나
2025년 2회는 SQL 문이 한 문항도 없다. DB 이론 셋(인덱스 · attribute · π 연산)이 그 자리를 채웠고, C 는 4문항 전부 구조체와 포인터다. 13번 라운드 로빈 11.75 는 도착 시간이 다른 프로세스라 간트 차트를 그려야 하고, 9번 람다 예외는 catch 가 돌려주는 7 을 더하는 문제다.
다루는 것2025년 2회 20문항 · 복원본
시계150분 · 실제 시험과 같다
끝나면문항마다 가는 장이 표로 나온다

01푸는 법

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

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

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

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

02실전 세트

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

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

2025-2회 · 1번DB

테이블의 레코드를 빠르게 검색·접근하기 위해 별도로 구성하는 데이터 구조(색인)는?

정답인덱스 (Index)

— 인덱스(Index). 책의 색인처럼 값 → 위치를 따로 적어 두어 찾기를 빠르게 하는 구조다.

원리 — 표에서 어떤 값을 찾으려면 처음부터 끝까지 다 봐야 한다(전체 탐색). 인덱스는 특정 열의 값들을 정렬해 두고 각 값이 어느 행에 있는지 주소를 붙여 둔 별도의 구조(보통 B-트리)다. 찾을 때는 인덱스에서 값을 빠르게 찾아 그 행으로 바로 간다. 대가는 저장 공간과, 행이 바뀔 때마다 인덱스도 고쳐야 하는 쓰기 비용이다. SQL 로는 CREATE INDEX 이름 ON 표(열) 로 만든다.

따라가기

  1. "빠르게 검색 · 접근" + "별도로 구성" + "색인" → 인덱스

헷갈리는 자리 — 뷰(가상 표)나 키와 섞는 것. 뷰는 보이는 창이고 인덱스는 찾기 장치다. 기본키에는 보통 인덱스가 자동으로 생기지만 인덱스 = 키는 아니다.

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

2025-2회 · 2번DB

데이터베이스에서 개체(Entity)의 특성이나 상태를 나타내는 구성 요소는? (영문)

정답attribute (속성)

— attribute(속성). 개체가 가진 특성 하나하나, 표에서는 열이다.

원리 — 개체(entity)는 학생 · 강좌처럼 데이터로 다루는 대상이고, 그 개체를 설명하는 항목(이름 · 학년 · 학과)이 속성(attribute)이다. 표로 옮기면 개체는 표, 속성은 열, 개체 하나의 값들은 행(튜플)이 된다. E-R 다이어그램에서는 개체가 사각형, 속성이 타원, 관계가 마름모다.

따라가기

  1. "개체의 특성 · 상태를 나타내는 구성 요소" → attribute

헷갈리는 자리 — tuple(행)이나 relation(표)을 적는 것. "특성"이면 속성이다. 영문을 물었으니 attribute 철자(t 두 번, 끝은 -ute)를 정확히 적는다. 속성이 가질 수 있는 값의 범위는 domain 이고, 속성이 여러 값을 가지면(다중값 속성) 1NF 를 어기므로 정규화 문제와도 이어진다.

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

2025-2회 · 3번네트워크

SSH 프로토콜이 기본으로 사용하는 포트 번호는?

정답22

— 22. SSH 의 기본 포트다.

원리 — 포트 번호는 한 컴퓨터 안에서 어느 프로그램에게 줄 데이터인지 가르는 문 번호다. 잘 알려진 서비스는 번호가 정해져 있다 — FTP 20 · 21, SSH 22, Telnet 23, SMTP 25, DNS 53, HTTP 80, POP3 110, HTTPS 443. SSH 는 Telnet(23)의 암호화 판이라 바로 옆 번호 22 를 받았다고 외우면 된다. 2023년 1회 7번은 거꾸로 "22번 포트를 쓰는 보안 프로토콜"로 SSH 를 물었다.

따라가기

  1. SSH 기본 포트 → 22

헷갈리는 자리 — 23(Telnet)이나 443(HTTPS)과 섞는 것. 암호화 원격 접속 = SSH = 22. 포트 번호 표는 훈련 T-L-04 에서 일곱 개를 한 번에 확인한다. 답은 숫자 22 만 적고 단위나 프로토콜 이름을 덧붙이지 않는다.

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

2025-2회 · 4번OS

① 실행 시간이 가장 짧은 작업부터 처리하는 비선점 스케줄링 ② 남은 실행 시간이 가장 짧은 작업을 우선하는 선점 스케줄링

정답① SJF ② SRT

— ① SJF ② SRT. 같은 "짧은 것 먼저"인데 한 번 잡으면 안 뺏기는 것이 SJF, 더 짧은 것이 오면 뺏기는 것이 SRT 다.

원리 — CPU 스케줄링은 비선점(한 번 CPU 를 잡으면 끝날 때까지 안 뺏김)과 선점(더 급한 것이 오면 뺏김)으로 나뉜다. SJF(Shortest Job First)는 대기 중인 것 가운데 실행 시간이 가장 짧은 것을 고르고, 시작하면 끝까지 돈다 — 비선점. SRT(Shortest Remaining Time)는 SJF 의 선점판이다 — 실행 중에 "남은 시간"보다 짧은 프로세스가 도착하면 CPU 를 넘긴다. 둘 다 평균 대기 시간이 짧다는 장점이 있지만 긴 작업이 계속 밀리는 기아(starvation)가 생길 수 있다.

따라가기

  1. "실행 시간이 가장 짧은 작업부터 · 비선점" → SJF
  2. "남은 실행 시간이 가장 짧은 · 선점" → SRT

헷갈리는 자리 — 비선점 · 선점 묶음을 통째로 외운다. 비선점: FCFS · SJF · HRN. 선점: SRT · RR · 다단계 큐 · 다단계 피드백 큐. "남은(Remaining)"이라는 말이 붙으면 실행 도중에도 비교한다는 뜻이라 선점이다.

표준 · 교재 정의(운영체제 · 리눅스 명령 · 웹 · 클라우드 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-2회 · 5번Java

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

public class Main { static void change(String[] words, String label) { words[0] = label; label = "Z"; } public static void main(String[] args) { String[] words = { "A" }; String label = "B"; change(words, label); System.out.print(words[0] + label); } }
정답BB

— BB. 배열은 주소가 넘어가 words[0] 이 B 로 바뀌지만, String 변수 label 은 복사본이라 함수 안의 "Z" 대입이 main 에 안 보인다.

원리 — 자바는 값을 넘긴다. 배열 변수 words 의 "값"은 배열이 놓인 자리(참조)라, 함수 안의 words 도 같은 배열을 가리켜 words[0] = label 이 원본 배열을 고친다. label 도 참조를 복사해 받지만 label = "Z" 는 "함수 안의 label 이 다른 문자열을 가리키게" 할 뿐, main 의 label 이 가리키는 곳은 그대로다. 문자열은 바꿀 수 없는(불변) 객체라 내용을 고치는 길도 없다. "칸 안의 값을 고치면 밖에 보이고, 변수 자체를 새것으로 바꾸면 안 보인다"가 규칙이다.

따라가기

  1. change(words, "B"): words[0] = "B" → 원본 배열 바뀜
  2. label = "Z" → 함수 안 변수만 바뀜
  3. main: words[0] "B" + label "B" → BB

헷갈리는 자리 — BZ 로 적는 것. 매개변수에 새 객체를 대입한 것은 호출한 쪽에 안 돌아간다. AB 로 적는 것 — 배열 칸 대입은 원본에 닿는다. 배열 · 객체의 칸 고치기(보임)와 변수 갈아끼우기(안 보임)를 나눈다.

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

2025-2회 · 6번네트워크

호스트 주소가 223.13.234.132이고 서브넷 마스크가 255.255.255.192일 때, ① 네트워크 주소의 마지막 옥텟과 ② 사용 가능한 호스트 수를 쓰시오.

항목
호스트 주소223.13.234.132
서브넷 마스크255.255.255.192
네트워크 주소223.13.234.①
사용 가능한 호스트②개
정답① 128 ② 62

— ① 128 ② 62. 마스크 192 는 마지막 옥텟을 64 씩 묶으므로 132 는 128~191 묶음이고, 64 개 중 네트워크 · 브로드캐스트를 뺀 62 개를 호스트에 쓴다.

원리 — 마지막 옥텟 마스크 192 = 1100 0000 → 호스트 비트 6개 → 묶음 크기 256 − 192 = 64. 묶음은 0~63, 64~127, 128~191, 192~255 이고 132 는 셋째 묶음이라 네트워크 주소의 마지막 옥텟은 128, 브로드캐스트는 191 이다. 사용 가능한 호스트 수는 2⁶ − 2 = 62 (첫 주소는 네트워크, 끝 주소는 브로드캐스트라 뺀다). 서브넷 계산은 늘 "마스크 → 묶음 크기 → 내 주소가 든 묶음 → 양 끝 빼기" 네 걸음이다.

따라가기

  1. 255.255.255.192 → /26, 묶음 64
  2. 132 → 128~191 → 네트워크 .128
  3. 64 − 2 = 62

헷갈리는 자리 — 호스트 수를 64 로 적는 것(양 끝을 빼지 않음). 네트워크 주소를 132 가 든 묶음의 시작이 아니라 0 으로 적는 것. 두 칸 다 맞아야 5점이다.

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

2025-2회 · 7번디자인패턴

실제 객체에 대한 접근을 제어하기 위해 대리 객체를 두는 구조 패턴은?

정답프록시 (Proxy)

— 프록시(Proxy). 2023-1-11 과 같은 문제다 — 실제 객체 앞에 대리 객체를 두어 접근을 제어한다.

원리 — 프록시는 실제 객체(RealSubject)와 같은 인터페이스(Subject)를 구현한다. 클라이언트는 프록시를 실제 객체인 줄 알고 부르고, 프록시가 중간에서 "접근 허용 여부 · 생성 시점 · 원격 전달 · 캐시 · 로그"를 처리한 뒤 실제 객체를 호출한다. 종류로 가상 프록시(무거운 객체를 필요할 때 생성), 보호 프록시(권한 검사), 원격 프록시(네트워크 너머 객체를 지역 객체처럼), 스마트 참조(참조 횟수 세기)가 있다. 접근 제어 코드를 실제 객체 밖으로 빼는 것이 이 패턴의 값어치다.

따라가기

  1. "실제 객체에 대한 접근을 제어" → 문지기
  2. "대리 객체를 두는 구조 패턴" → 프록시

헷갈리는 자리 — 데코레이터로 적는 것. 구조가 거의 같아서(같은 인터페이스로 감싼다) 목적으로 구분한다 — 데코레이터는 "기능 추가", 프록시는 "접근 제어". 문제 문장에 "접근 제어 · 대리"가 있으면 프록시다.

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

2025-2회 · 8번웹기술

웹 페이지 전체를 새로 고치지 않고 필요한 데이터만 서버와 비동기적으로 주고받아 화면 일부를 갱신하는 기술은?

정답AJAX

— AJAX. 2023-1-04 와 같은 문제다 — 페이지 전체 대신 필요한 데이터만 비동기로 받아 화면 일부를 갱신한다.

원리 — 브라우저가 서버에 문서를 요청하면 기본 동작은 "새 문서로 화면 전체 교체"다. AJAX 는 자바스크립트가 XMLHttpRequest 나 fetch 로 백그라운드 요청을 보내고, JSON · XML 로 온 응답을 받아 DOM 의 일부만 바꾼다. 비동기라서 응답을 기다리는 동안 화면이 멈추지 않는다. 결과로 페이지 깜빡임이 없고 전송량이 줄며, 한 페이지 안에서 앱처럼 움직이는 SPA(단일 페이지 애플리케이션)의 바탕이 됐다.

따라가기

  1. "전체를 새로 고치지 않고" → 부분 갱신
  2. "필요한 데이터만 비동기적으로" → Asynchronous + 데이터 교환
  3. AJAX

헷갈리는 자리 — 웹소켓(WebSocket)과 섞는 것. 웹소켓은 서버와 "항상 열린 양방향 통로"를 만들고, AJAX 는 필요할 때마다 "요청 – 응답"을 한 번씩 한다. 문제에 "비동기 · 부분 갱신 · XML" 이 나오면 AJAX 다.

표준 · 교재 정의(운영체제 · 리눅스 명령 · 웹 · 클라우드 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.

2025-2회 · 9번Java

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

public class Main { interface Operation { int apply(int value) throws Exception; } static int run(Operation operation) { try { return operation.apply(3); } catch (Exception e) { return 7; } } public static void main(String[] args) { Operation first = value -> { if (value > 2) { throw new Exception(); } return value * 2; }; System.out.print(run(first) + run(value -> value + 9)); } }
정답19

— 19. 첫 람다는 3 > 2 라 예외를 던져 catch 가 7 을 돌려주고, 둘째 람다는 3 + 9 = 12 다.

원리 — 람다 value -> {…} 는 인터페이스 Operation 의 유일한 메서드 apply 를 그 자리에서 구현한 것이다. run 은 apply(3) 을 try 안에서 부르고, 예외가 나면 catch 에서 7 을 돌려준다. 첫 람다는 value 가 2 보다 크면 throw new Exception() 이라 3 을 넣으면 예외다 — return 까지 못 간다. 둘째 람다 value -> value + 9 는 한 줄이라 중괄호 없이 값이 곧 결과다. 두 run 의 결과를 더한다.

따라가기

  1. run(first): apply(3) → 3 > 2 → 예외 → catch → 7
  2. run(둘째): apply(3) → 3 + 9 = 12
  3. 7 + 12 = 19

헷갈리는 자리 — 첫 람다를 3 × 2 = 6 으로 계산해 18 을 적는 것. 조건이 참이라 return 줄은 안 돈다. 또 throws Exception 이 인터페이스에 있어야 람다 안에서 checked 예외를 던질 수 있다는 것 — 없으면 컴파일 오류라, 빈칸 문제로도 나올 수 있는 자리다.

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

2025-2회 · 10번Java

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

public class Main { static class Parent { int value(int n) { return n + 2; } static String tag() { return "P"; } } static class Child extends Parent { int value(int n) { return n + 3; } static String tag() { return "C"; } } public static void main(String[] args) { Parent ref = new Child(); System.out.print(ref.value(2) + ref.tag()); } }
정답5P

— 5P. 인스턴스 메서드 value 는 자식 판(n + 3)이 돌아 5 이고, static 메서드 tag 는 변수의 겉모양 Parent 를 따라 P 다.

원리 — 오버라이딩은 인스턴스 메서드에만 일어난다. static 메서드는 객체가 아니라 클래스에 붙어 있어서 ref.tag() 라고 써도 실제로는 Parent.tag() 로 컴파일된다(변수의 선언 타입). 자식이 같은 이름의 static 메서드를 만들어도 그것은 "숨기기"일 뿐 갈아끼우기가 아니다. 그래서 같은 객체에서 value 는 속(Child)을, tag 는 겉(Parent)을 따른다. 필드가 겉을 따르는 것과 같은 편이다.

따라가기

  1. ref.value(2) → Child.value → 2 + 3 = 5
  2. ref.tag() → static → Parent.tag → "P"
  3. 5 + "P" → 문자열 결합 → 5P

헷갈리는 자리 — 5C 로 적는 것. static 은 오버라이딩되지 않는다. 겉을 따르는 것 두 가지(필드 · static 메서드)와 속을 따르는 것 한 가지(인스턴스 메서드)로 정리해 둔다. 숫자와 문자열의 + 는 결합이라 5P 이지 덧셈이 아니다.

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

2025-2회 · 11번테스트

다음 제어 흐름 그래프가 분기 커버리지를 만족하도록 테스트 경로 두 개를 쓰시오.

제어 흐름도(그림을 표로 옮김)

노드내용다음
1POINTER = FALSE2
2X > K ?YES → 3, NO → 4
3POINTER = TRUE4
4X = X + 25
5CALL SUB(X, POINTER, RESULT)6
6RESULT > 1 ?YES → 1, NO → 7
7PRINT RESULT
정답1234561, 124567 (또는 1234567, 124561)

— 1234561 과 124567 (또는 1234567 과 124561). 2023-1-19 와 같은 흐름도다.

원리 — 분기 커버리지는 각 결정의 참 · 거짓 갈래를 모두 한 번 이상 밟아야 한다. 결정은 2번(X > K)과 6번(RESULT > 1) 둘이니 갈래는 2Y · 2N · 6Y · 6N 넷이다. 경로 하나는 2 에서 한쪽, 6 에서 한쪽만 밟으니 최소 두 경로가 필요하고, 두 경로가 2 에서 서로 다른 쪽, 6 에서 서로 다른 쪽을 밟으면 넷이 다 덮인다. 2Y 는 3 을 거치므로 1-2-3-4-5-6, 2N 은 3 을 건너뛰어 1-2-4-5-6 이다. 6Y 는 1 로 돌아가고 6N 은 7 로 끝난다.

따라가기

  1. 2Y+6Y: 1234561
  2. 2N+6N: 124567
  3. 또는 2Y+6N: 1234567 과 2N+6Y: 124561

헷갈리는 자리 — 문장 커버리지와 헷갈려 "모든 노드를 한 번씩" 밟는 1234567 하나로 끝내는 것. 노드는 다 밟았지만 2N · 6Y 갈래를 안 밟아 분기 커버리지는 미달이다. 갈래를 세는 것이지 노드를 세는 것이 아니다.

제어 흐름 표의 분기(2 · 6번 노드)를 참 · 거짓으로 나눠 경로를 손으로 세었다. 복원 출처 grandlife.co.kr(2026-09-14) — 그림은 표로 옮겼다.

2025-2회 · 12번C

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

#include <stdio.h> #define SIZE 3 typedef struct { int data[SIZE]; int front; int rear; } Queue; void enqueue(Queue *queue, int value) { queue->data[queue->rear] = value; queue->rear = (queue->rear + 1) % SIZE; } int dequeue(Queue *queue) { int value = queue->data[queue->front]; queue->front = (queue->front + 1) % SIZE; return value; } int main(void) { Queue queue = { {0}, 0, 0 }; enqueue(&queue, 1); enqueue(&queue, 2); dequeue(&queue); enqueue(&queue, 3); int first = dequeue(&queue); int second = dequeue(&queue); printf("%d 그리고 %d", first, second); return 0; }
정답2 그리고 3

2 그리고 3. 크기 3 짜리 원형 큐에 1 · 2 를 넣고 하나 빼고 3 을 넣은 뒤 두 번 꺼내면 2 와 3 이다.

원리 — 큐는 줄서기다. 뒤(rear)로 들어가 앞(front)으로 나온다. 원형 큐는 칸이 끝에 닿으면 % SIZE 로 첫 칸으로 돌아와 다시 쓴다. enqueue 는 rear 칸에 넣고 rear 를 한 칸 앞으로(3 이면 0 으로), dequeue 는 front 칸을 읽고 front 를 한 칸 앞으로 옮긴다. 값은 지우지 않아도 front 가 지나갔으니 없는 것과 같다. 넣은 순서대로 나온다(FIFO)는 것만 지키면 칸 번호는 회전판으로 따라가면 된다.

따라가기 — data[3], front = 0, rear = 0.

  1. enqueue 1 → data[0] = 1, rear = 1. enqueue 2 → data[1] = 2, rear = 2
  2. dequeue → data[0] = 1 을 꺼냄(버림), front = 1
  3. enqueue 3 → data[2] = 3, rear = (2 + 1) % 3 = 0
  4. first = dequeue → data[1] = 2, front = 2
  5. second = dequeue → data[2] = 3, front = 0

헷갈리는 자리 — 첫 dequeue 의 결과 1 을 first 로 적는 것. 그 값은 변수에 안 담고 버렸다. 스택으로 착각해 3 · 2 로 적는 것도 흔하다. 출력에 " 그리고 " 글자가 그대로 들어간다.

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

2025-2회 · 13번OS

시간 할당량이 4ms인 라운드로빈 방식으로 다음 프로세스를 스케줄링할 때 평균 대기시간을 구하시오. 문맥 교환 시간은 무시한다.

프로세스도착 시간(ms)실행 시간(ms)
P108
P214
P329
P435
정답11.75ms

— 11.75ms. 할당량 4 로 돌리면 P1 12 · P2 3 · P3 15 · P4 17, 합 47 ÷ 4 = 11.75 다.

원리 — 라운드로빈(RR)은 준비 큐를 순서대로 돌며 각 프로세스에 시간 할당량(quantum)만큼만 CPU 를 주고, 안 끝났으면 큐의 맨 뒤로 보낸다. 표를 그리는 규칙은 두 가지다 — ① 한 프로세스가 할당량을 다 쓴 시점에 새로 도착한 프로세스가 있으면 그것을 먼저 큐 뒤에 넣고, 그다음에 방금 돌던 프로세스를 넣는다. ② 대기 시간 = 끝난 시각 − 도착 시각 − 실행 시간. 즉 "큐에 들어와서 끝날 때까지 CPU 를 안 쓴 시간"이다.

따라가기

  1. 0~4 P1(남 4). 이 사이 P2 · P3 · P4 도착 → 큐 [P2 P3 P4 P1]
  2. 4~8 P2 끝 · 8~12 P3(남 5) · 12~16 P4(남 1) · 16~20 P1 끝
  3. 20~24 P3(남 1) · 24~25 P4 끝 · 25~26 P3 끝
  4. 대기: P1 = 20−0−8 = 12, P2 = 8−1−4 = 3, P3 = 26−2−9 = 15, P4 = 25−3−5 = 17
  5. 합 47 ÷ 4 = 11.75ms

헷갈리는 자리 — 1단계에서 P1 을 도착한 P2 · P3 · P4 보다 앞에 다시 넣는 것. 할당량이 끝난 프로세스는 "그 시각까지 도착한 것들 뒤"로 간다. 이 순서를 바꾸면 평균이 달라진다. 그리고 문맥 교환 시간은 문제에서 무시한다고 했으니 더하지 않는다.

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

2025-2회 · 14번C

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

#include <stdio.h> struct Pair { int x; int y; }; int main(void) { struct Pair values[] = { {1, 2}, {3, 4}, {5, 6} }; struct Pair *pointer = values; struct Pair **doublePointer = &pointer; (*doublePointer)[1] = (*doublePointer)[2]; printf("%d 그리고 %d", values[1].x, values[1].y); return 0; }
정답5 그리고 6

5 그리고 6. 이중 포인터를 풀면 values 그 자체라, 셋째 원소를 둘째 원소에 통째로 복사한 것이다.

원리pointer = values 는 배열 첫 칸의 주소, doublePointer = &pointer 는 그 쪽지의 주소다. *doublePointer 는 쪽지 pointer 를 다시 꺼낸 것이므로 values 첫 칸 주소와 같고, 거기에 [1] 을 붙이면 values[1], [2] 를 붙이면 values[2] 다. 구조체는 = 로 통째 복사가 되므로 values[1] = values[2] 는 x 와 y 를 한꺼번에 덮어쓴다. 별표가 두 개라도 "쪽지를 따라 원래 배열로 돌아온다"는 것이 전부다.

따라가기

  1. values = [{1,2}, {3,4}, {5,6}]
  2. (*doublePointer) = pointer = values
  3. values[1] = values[2] → values = [{1,2}, {5,6}, {5,6}]
  4. values[1].x = 5, values[1].y = 6 → 5 그리고 6

헷갈리는 자리 — 대입 방향을 거꾸로 읽어 values[2] 가 바뀌었다고 보는 것(3 그리고 4). 왼쪽이 바뀐다. 이중 포인터를 보고 값이 아니라 주소가 복사됐다고 넘겨짚는 것 — 대괄호가 붙는 순간 구조체 값이다.

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

2025-2회 · 15번Java

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

public class Main { static class Box { int value; Box(int value) { this.value = value; } } public static void main(String[] args) { Box a = new Box(1); Box b = new Box(2); Box c = new Box(3); Box[] boxes = { a, b, c }; Box temp = boxes[0]; boxes[0] = boxes[2]; boxes[2] = temp; boxes[1].value = boxes[0].value; System.out.print(a.value + "a" + b.value + "b" + c.value); } }
정답1a3b3

— 1a3b3. 배열 칸을 맞바꿔도 객체 a · b · c 자체는 그대로이고, boxes[1].value = … 만 객체 b 의 값을 3 으로 고친다.

원리 — 배열 boxes 에는 객체가 들어 있는 것이 아니라 객체를 가리키는 참조가 들어 있다. boxes[0]boxes[2] 를 맞바꾸는 것은 참조의 자리만 바꾸는 것이라 a · b · c 어느 객체의 value 도 안 변한다. 반면 boxes[1].value = boxes[0].value 는 boxes[1] 이 가리키는 객체(b)의 칸을 고치는 것이라 b.value 가 바뀐다. 마지막 출력은 배열이 아니라 변수 a · b · c 로 찍으므로 객체의 값을 본다. "참조를 옮기는 것"과 "객체의 칸을 고치는 것"을 나눈다.

따라가기

  1. boxes = [a, b, c] (값 1, 2, 3)
  2. temp = a; boxes[0] = c; boxes[2] = a → boxes = [c, b, a]
  3. boxes[1].value = boxes[0].value → b.value = c.value = 3
  4. a.value 1, b.value 3, c.value 3 → 1a3b3

헷갈리는 자리 — 배열을 맞바꿨으니 a 와 c 의 값도 바뀌었다고 보고 3a3b1 로 적는 것. 참조 자리 바꾸기는 객체를 안 건드린다. boxes[1] 이 b 라는 것을 놓치고 다른 객체를 고치는 것 — 자리 1 은 교환에 끼지 않았다.

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

2025-2회 · 16번C

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

#include <stdio.h> struct Node { int value; struct Node *next; }; int main(void) { struct Node a = { 1, NULL }; struct Node b = { 2, NULL }; struct Node c = { 3, NULL }; a.next = &b; b.next = &c; c.next = NULL; c.next = &a; a.next = &b; b.next = NULL; struct Node *head = &c; printf("%d %d %d", head->value, head->next->value, head->next->next->value); return 0; }
정답3 1 2

3 1 2. 마지막에 남은 화살표는 c → a → b → NULL 이고 머리가 c 다.

원리 — 연결 리스트의 순서는 오직 next 가 정하고, 같은 next 에 여러 번 대입하면 마지막 대입만 남는다. 코드가 화살표를 여섯 번 바꾸지만 노드마다 마지막 줄만 보면 된다: a.next 는 마지막에 &b, b.next 는 NULL, c.next 는 &a. 머리(head)를 c 로 잡았으니 c 에서 출발해 화살표를 따라간다. 노드가 선언된 순서(a · b · c)는 아무 상관이 없다.

따라가기

  1. a.next: &b → (다시) &b. 최종 b
  2. b.next: &c → NULL. 최종 NULL
  3. c.next: NULL → &a. 최종 a
  4. head = c: c(3) → a(1) → b(2) → NULL → 3 1 2

헷갈리는 자리 — 앞의 세 줄(a → b → c)만 보고 1 2 3 으로 적는 것. 뒤의 세 줄이 덮어쓴다. head->next->next->value 까지만 찍으므로 b.next 가 NULL 이어도 오류가 없다 — 네 번째를 찍었다면 NULL 을 따라가 죽는다.

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

2025-2회 · 17번Python

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

numbers = [1, 2, 3] doubled = {number: number * 2 for number in numbers} saved = set(doubled.values()) numbers[0] = 99 doubled[2] = 7 saved.add(99) print(len(saved & set(doubled.values())))
정답2

— 2. saved 는 만들 때의 값 {2, 4, 6} 을 복사한 것이라 나중의 변경이 안 따라오고, 마지막 값들 {2, 7, 6} 과의 교집합은 {2, 6} 이다.

원리 — 딕셔너리 컴프리헨션 {number: number * 2 for …} 는 {1: 2, 2: 4, 3: 6} 을 만든다. set(doubled.values()) 는 그 순간의 값들을 새 집합에 복사해 담는다 — 나중에 doubled 를 고쳐도 saved 는 모른다. numbers[0] = 99 는 이미 만들어진 딕셔너리와 무관하다. doubled[2] = 7 은 키 2 의 값을 4 에서 7 로 바꾼다. & 는 두 집합에 모두 있는 원소만 남기는 교집합이다.

따라가기

  1. doubled = {1: 2, 2: 4, 3: 6}, saved = {2, 4, 6}
  2. numbers[0] = 99 → 영향 없음
  3. doubled[2] = 7 → 값들 {2, 7, 6}
  4. saved.add(99) → {2, 4, 6, 99}
  5. {2, 4, 6, 99} & {2, 7, 6} = {2, 6} → len 2

헷갈리는 자리 — saved 가 doubled 를 계속 바라본다고 보고 {2, 7, 6, 99} 로 계산해 3 을 적는 것. set(…) 은 그 순간 복사다. numbers 를 바꾸면 doubled 도 바뀐다고 보는 것 — 컴프리헨션은 이미 끝났다.

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

2025-2회 · 18번C

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

#include <stdio.h> #include <stdlib.h> struct Node { char value; struct Node *next; }; struct Node *make_list(const char *text) { struct Node *head = NULL; while (*text) { struct Node *node = malloc(sizeof(struct Node)); node->value = *text++; node->next = head; head = node; } return head; } int main(void) { struct Node *current = make_list("BEST"); while (current) { putchar(current->value); struct Node *old = current; current = current->next; free(old); } return 0; }
정답TSEB

— TSEB. 글자를 하나씩 리스트 맨 앞에 끼우면 순서가 뒤집혀, 앞에서부터 찍으면 거꾸로 나온다.

원리make_list 는 문자열을 한 글자씩 읽으며 새 노드를 만들고 node->next = head; head = node 로 맨 앞에 끼운다. 첫 글자 B 가 제일 안쪽에, 마지막 글자 T 가 맨 앞에 서므로 리스트는 T → S → E → B 다. *text++ 는 "지금 글자를 읽고 나서 한 칸 옆으로"이고, while (*text) 는 끝표(0)를 만나면 멈춘다. main 은 머리부터 화살표를 따라가며 글자를 찍고 지나온 노드를 free 로 돌려준다 — 출력에는 영향이 없다.

따라가기

  1. B → 리스트 [B]
  2. E → [E, B], S → [S, E, B], T → [T, S, E, B]
  3. 머리부터 찍기: T S E B → TSEB

헷갈리는 자리 — 리스트를 "만든 순서대로" 보고 BEST 를 적는 것. 뒤에 붙이는 코드였다면 node->next = NULL 과 꼬리 포인터가 있어야 한다. 앞에 끼우기는 늘 뒤집힌다. free 뒤에 current 를 쓰지 않도록 미리 old 에 빼 두는 것도 눈여겨본다.

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

2025-2회 · 19번보안

TCP 3-way handshake의 절차적 취약점을 이용해, SYN 요청만 대량으로 보내고 ACK를 보내지 않아 서버의 연결 대기 큐를 고갈시키는 DoS 공격은?

정답SYN 플러딩 (SYN Flooding)

— SYN 플러딩(SYN Flooding). 연결 요청(SYN)만 잔뜩 보내고 마지막 확인(ACK)을 안 보내 서버의 대기 자리를 꽉 채우는 DoS 공격이다.

원리 — TCP 는 연결할 때 3-way handshake 를 한다: 클라이언트 SYN → 서버 SYN+ACK → 클라이언트 ACK. 서버는 SYN 을 받으면 "반쯤 열린" 상태로 자리를 잡아 두고 ACK 를 기다린다. 공격자가 출발지를 위조한 SYN 을 수천 개 보내고 ACK 를 안 보내면 서버의 대기 큐가 반쯤 열린 연결로 가득 차 진짜 손님의 SYN 을 못 받는다. 막는 방법으로 SYN 쿠키(자리를 미리 잡지 않고 계산으로 대신)가 있다. "3-way handshake · SYN 만 · ACK 안 옴 · 큐 고갈"이 표지다.

따라가기

  1. SYN 대량 + ACK 없음 + 연결 대기 큐 고갈 → SYN 플러딩

헷갈리는 자리 — UDP 플러딩이나 스머핑과 섞는 것. TCP 의 handshake 를 이용하면 SYN 플러딩이다. "절차적 취약점"이라는 말이 3단계 연결 절차를 가리킨다.

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

2025-2회 · 20번DB

다음 employee 릴레이션에 관계대수의 프로젝트 연산 π를 적용해 직급 열을 추출한 결과 릴레이션을 테이블 형태로 쓰시오.

employee

사번이름직급
101김하늘부장
102이바다대리
103박노을과장
104최새벽차장
105정구름대리
π 직급 (employee)
정답직급
부장
대리
과장
차장

— 열 직급 하나에 부장 · 대리 · 과장 · 차장 네 행. π 는 열을 뽑고 중복 행을 지운다.

원리 — 관계대수의 π(프로젝트)는 지정한 열만 남기는 연산이다. 결과도 릴레이션이라 같은 행은 하나만 남는다 — 관계형 모델에서 릴레이션은 집합이라 중복 튜플이 없기 때문이다. 대리가 두 행(102 · 105)이지만 결과에는 한 번이다. SQL 의 SELECT 직급 FROM employee 는 중복을 남기지만 SELECT DISTINCT 직급 이 π 와 같다.

따라가기

  1. 직급 열만 → 부장, 대리, 과장, 차장, 대리
  2. 중복 제거 → 부장, 대리, 과장, 차장 (4행)

헷갈리는 자리 — 대리를 두 번 적어 5 행으로 만드는 것. 관계대수 결과는 집합이다. 열 이름 직급을 표 머리에 적는 것도 "테이블 형태" 요구의 일부다.

표를 놓고 연산 규칙대로 손으로 계산했고 sqlite 3.49 로 같은 결과를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.

03채점 뒤 할 일

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

코드 9문항 중 C 4 · Java 4 · Python 1 이다. C 넷은 원형 큐(12번) · 이중 포인터 구조체 배열(14번) · next 다시 잇기(16번) · 앞에 끼우는 리스트(18번)로 전부 E03 이다. 16번은 마지막 대입 뒤의 모양만 남는다는 것을 그림으로 확인해야 3 1 2 가 나온다.

Java 는 5번 배열은 참조 · String 은 값(BB), 10번 인스턴스 메서드는 자식 · static 은 참조형(5P), 15번 참조 배열 교환 뒤 원본 객체 값(1a3b3), 9번 람다에서 던진 예외를 catch 가 7 로 바꿔 7 + 12 = 19 다. static 은 오버라이딩되지 않는다는 10번 규칙이 이 회차의 새 얼굴이다.

용어 11문항은 SW공학 4(SJF/SRT · 프록시 · 분기 커버리지 경로 · 라운드 로빈) · DB 3 · 네트워크 2(SSH 22 · /26 서브넷) · 보안 1(SYN 플러딩) · AJAX 다. 20번 π 직급은 중복을 지운 네 행을 표로 적는다.

문항마다 가는 장

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

문항분야가는 장무엇을 묻나
1DBE10인덱스 정의
2DBE10attribute
3네트워크E11SSH 포트 22
4OSE16SJF 와 SRT
5JavaE06배열은 참조 · String 은 값 — 매개변수
6네트워크E12/26 네트워크 주소와 호스트 수
7디자인패턴E17프록시 패턴
8웹기술E16AJAX
9JavaE06람다 예외 catch 반환값 합
10JavaE05인스턴스 오버라이딩 · static 은 참조형
11테스트E18분기 커버리지 경로 2개
12CE03원형 큐 enqueue · dequeue
13OSE16라운드 로빈 4ms 평균 대기
14CE03이중 포인터로 구조체 배열 원소 복사
15JavaE06참조 배열 교환 뒤 원본 객체 값
16CE03next 다시 잇기 뒤 순회
17PythonE07딕셔너리 값 집합 교집합 길이
18CE03앞에 끼우는 리스트 — 역순 출력
19보안E14SYN 플러딩
20DBE10π 직급 — 중복 제거 결과

이 회차에서 눈여겨볼 문항

문항왜 갈리나
9번first 는 3 > 2 라 예외 → catch 가 7. 두 번째 람다는 3 + 9 = 12. 합 19
10번ref.value(2) 는 Child 것 5, ref.tag() 는 static 이라 참조형 Parent 의 P. 5P
13번할당량 4ms, 도착 0 · 1 · 2 · 3. 간트 차트를 그리면 대기 시간 합 47 ÷ 4 = 11.75ms
16번c → a → b 로 잇고 b.next = NULL. head 가 c 라 3 1 2

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

04다음

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