2026년 1회 실전 E28

새 출제 기준 첫 회차. Python 3문항, 함수 포인터 %x, FOREIGN KEY 빈칸 5개, 비기능 요구사항. 프로그래밍이 7문항으로 줄었다

왜 이 장을 하나
2026년 1회는 2026년 출제 기준의 첫 시험이라 3회와 가장 가깝다. 프로그래밍이 7문항으로 줄고 SQL·DB 4 · 보안 3 · SW공학 4 로 용어가 늘었다. 1번 오버로딩 vs 오버라이딩, 8번 함수 포인터, 12번 얕은 복사, 18번 FOREIGN KEY 구문이 이 회차에 처음 나온 꼴이다.
다루는 것2026년 1회 20문항 · 복원본
시계150분 · 실제 시험과 같다
끝나면문항마다 가는 장이 표로 나온다

01푸는 법

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

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

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

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

02실전 세트

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

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

2026-1회 · 1번Java

다음 Java 프로그램을 실행했을 때 출력되는 값을 쓰시오.

class A { String f(Object x) { return "1"; } String g() { return f("a"); } } class B extends A { String f(Object x) { return "2"; } String f(String x) { return "3"; } } public class Main { public static void main(String[] args) { A a = new B(); System.out.println(a.g()); } }
정답2

— 2. a.g() 는 A 에 적힌 g() 를 돌리고, 그 안의 f("a") 는 컴파일 때 f(Object) 로 정해진 뒤 실행 때 B 가 덮어쓴 f(Object) 로 간다.

원리 — 자바는 메서드를 두 번 고른다. 첫째, 컴파일 때 "어느 이름 · 어느 매개변수 꼴인가"를 고른다(오버로딩 선택). 둘째, 실행 때 "그 꼴을 가진 메서드 중 실제 객체의 것"을 고른다(오버라이딩). 편지에 비유하면 봉투의 주소(시그니처)는 부칠 때 정해지고, 그 집에 누가 사는지(실제 객체)는 배달할 때 본다. 봉투를 쓰는 곳은 A 안이라 A 가 아는 f(Object) 라고만 적힌다. B 의 f(String) 은 이름만 같을 뿐 다른 봉투라 후보에도 못 든다.

따라가기

  1. A a = new B(); — 겉은 A, 속은 B
  2. a.g() — g 는 A 에만 있으니 A.g 가 돈다
  3. A.g 안의 f("a") — A 클래스 안에서 컴파일됐고 A 가 아는 f 는 f(Object) 하나. 봉투 = f(Object)
  4. 실행 때 속 객체 B 에 f(Object) 가 덮어써져 있으므로 B.f(Object) → 2

헷갈리는 자리 — "a" 는 String 이니 B.f(String) 이 더 잘 맞지 않나? 아니다. 오버로딩 선택은 A 안에서 끝났고 그때 f(String) 은 없었다. 답을 3 으로 적는 것이 이 문제의 함정이다. 2024년 3회 18번(제네릭 T 가 Object 로 지워져 print(Object) 가 골라짐)과 같은 규칙이다.

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

2026-1회 · 2번C

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

#include <stdio.h> double arr1(int p[], int len) { double av = 0; int i; for (i = 0; i < len; i++) { av += (double)p[i]; } return av / len; } double arr2(int *p, int len) { double av = 0; int i; for (i = 0; i < len; i++) { av += (double)(*(p + i)); } return av / len; } int main(void) { int arr[10] = { 80, 20, 50, 55, 45, 95, 55, 10, 40, 80 }; int len = 10; printf("%.2f", arr1(arr, len) + arr2(arr, len)); return 0; }
정답106.00

— 106.00. 두 함수는 같은 배열의 평균 53.0 을 각각 돌려주고, %.2f 가 소수 둘째 자리까지 찍는다.

원리 — 함수 매개변수의 int p[]int *p 는 완전히 같은 것이다. 배열을 넘기면 복사되지 않고 첫 칸 주소만 넘어가므로, 어느 쪽으로 적어도 함수 안의 p 는 포인터다. 따라서 p[i]*(p + i) 도 같은 칸을 읽는다 — 대괄호는 "주소에 i 를 더해 연다"의 다른 표기일 뿐이다. 두 함수는 이름과 표기만 다르고 하는 일이 같아 결과가 같다. (double) 은 정수를 실수로 바꿔 나눗셈에서 소수점이 잘리지 않게 한다.

따라가기

  1. 합: 80 + 20 + 50 + 55 + 45 + 95 + 55 + 10 + 40 + 80 = 530
  2. arr1 = 530 / 10 = 53.0, arr2 = 53.0
  3. 53.0 + 53.0 = 106.0 → %.2f106.00

헷갈리는 자리 — 106 이나 106.0 으로 적는 것. 서식 문자열이 답의 일부라 소수점 아래 두 자리까지 적어야 한다. 또 "arr2 가 포인터라 다른 값이 나온다"고 넘겨짚는 것 — 표기가 다를 뿐 같은 칸이다. (double) 을 빼면 av 가 double 이라 어차피 실수 나눗셈이지만, av 까지 int 였다면 53 이 아니라 소수점이 잘린 값이 나온다 — 나눗셈은 두 쪽 중 하나만 실수여도 실수로 계산된다.

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

2026-1회 · 3번디자인패턴

① 추상부와 구현부를 분리해 독립적으로 확장할 수 있게 하는 구조 패턴 ② 객체 상태 변화 시 등록된 객체들에게 자동으로 통지하는 행위 패턴

정답① Bridge ② Observer

— ① Bridge(브리지) ② Observer(옵저버). "추상부와 구현부 분리"와 "상태 변화 자동 통지"가 각각의 표지다.

원리 — 브리지는 구조 패턴이다. "도형(원 · 사각형)"과 "그리는 방식(벡터 · 래스터)"처럼 두 축이 있을 때 상속으로 조합하면 클래스가 곱셈으로 늘어난다(원벡터 · 원래스터 · 사각벡터…). 브리지는 추상부(도형)가 구현부(그리기)를 필드로 가리키게 해서 두 축을 따로 확장한다 — 다리로 잇는다. 옵저버는 행위 패턴이다. 주제(Subject)가 관찰자(Observer) 목록을 갖고, 상태가 바뀌면 notify() 로 등록된 모두에게 알린다 — 주제는 관찰자가 누구인지 몰라도 된다. 이벤트 리스너 · 발행/구독이 이것이다.

따라가기

  1. "추상부와 구현부를 분리해 독립적으로 확장 · 구조" → Bridge
  2. "상태 변화 시 등록된 객체들에게 자동 통지 · 행위" → Observer

헷갈리는 자리 — 브리지를 어댑터로 적는 것. 어댑터는 "안 맞는 것을 나중에 맞춤", 브리지는 "처음부터 두 축을 갈라 설계"다. 옵저버를 미디에이터로 적는 것 — 미디에이터는 여러 객체의 대화를 중재자 하나에 모으고, 옵저버는 한 주제의 변화를 여럿에게 뿌린다.

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

2026-1회 · 4번DB

데이터베이스 설계 순서를 나열하시오 (요구사항 분석 / 구현 / 논리적 설계 / 개념적 설계 / 물리적 설계)

정답요구사항 분석 → 개념적 설계 → 논리적 설계 → 물리적 설계 → 구현

— 요구사항 분석 → 개념적 설계 → 논리적 설계 → 물리적 설계 → 구현. 2023년 2회 3번에 구현이 더해진 다섯 단계다.

원리 — 무엇을 담을지 듣고(요구사항), 개체 · 관계 그림을 그리고(개념 — E-R), DBMS 에 맞는 표로 옮기고(논리 — 정규화), 저장 구조를 정하고(물리 — 인덱스 · 파일), 마지막에 실제 DDL 로 만든다(구현). 뒤로 갈수록 특정 DBMS · 하드웨어에 매인다. 앞 단계의 결과물이 뒤 단계의 입력이라 순서를 바꿀 수 없다.

따라가기

  1. 요구사항 분석
  2. 개념적 설계(E-R)
  3. 논리적 설계(표 · 정규화)
  4. 물리적 설계(인덱스 · 저장)
  5. 구현(CREATE TABLE …)

헷갈리는 자리 — 논리와 물리를 바꾸는 것. "정규화"는 논리, "인덱스 · 접근 경로"는 물리다. 보기의 낱말을 그대로 순서만 바꿔 적는다.

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

2026-1회 · 5번SW공학

비기능 요구사항 분류: ① 여러 OS·다양한 포맷 지원 ② 적은 메모리 사용, 터치스크린 등 자원 관련 ③ 1초 이내 응답 등 속도 관련

정답① 운영 요구사항 ② 자원 요구사항 ③ 성능 요구사항

— ① 운영 요구사항 ② 자원 요구사항 ③ 성능 요구사항. "어떤 환경에서 도나 · 무엇을 얼마나 쓰나 · 얼마나 빠르나"로 갈린다.

원리 — 요구사항은 "무엇을 하는가"(기능 요구사항)와 "어떤 조건에서 어떻게"(비기능 요구사항)로 나뉜다. 비기능 요구사항은 다시 여러 갈래다. 성능 요구사항은 응답 시간 · 처리량 · 동시 사용자 같은 속도와 양이다 — "1초 이내 응답". 자원 요구사항은 메모리 · 저장 공간 · CPU · 입력 장치처럼 시스템이 쓰는 자원에 대한 제약이다 — "메모리 적게, 터치스크린 지원". 운영 요구사항은 시스템이 놓일 운영 환경에 대한 것이다 — "여러 OS 에서 돌고 다양한 파일 포맷을 지원". 이 밖에 보안 · 신뢰성 · 사용성 · 이식성 · 유지보수성 요구사항이 같은 묶음에 든다.

따라가기

  1. "여러 OS · 다양한 포맷 지원" → 운영 환경 → 운영 요구사항
  2. "적은 메모리 · 터치스크린" → 쓰는 자원 → 자원 요구사항
  3. "1초 이내 응답" → 속도 → 성능 요구사항

헷갈리는 자리 — ①을 이식성(portability) 요구사항으로 적는 것. 여러 OS 지원은 이식성으로도 읽히지만, 이 문제의 보기 구성(운영 · 자원 · 성능)에서는 운영 요구사항이 정답으로 복원돼 있다. 복원 문제라 실제 보기 문구가 달랐을 수 있으니 "OS · 포맷 = 운영 환경" 으로 묶어 기억한다.

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

2026-1회 · 6번네트워크

HDLC의 프레임 종류 3가지(①②③)와 동작 모드 2가지(④⑤: 균형 모드 / 종국이 허가 없이 응답 가능한 모드)를 쓰시오.

정답① 정보 ② 감독 ③ 비번호 ④ 비동기 균형 모드(ABM) ⑤ 비동기 응답 모드(ARM)

— ① 정보 ② 감독 ③ 비번호 ④ 비동기 균형 모드(ABM) ⑤ 비동기 응답 모드(ARM). 2023년 2회 19번이 그대로 다시 나왔다.

원리 — HDLC 프레임은 데이터를 나르는 정보(I), 제어만 하는 감독(S), 연결 관리용 비번호(U) 셋이다. 모드는 명령권으로 나뉜다 — NRM 은 주국만, ARM 은 종국도 허가 없이 응답, ABM 은 양쪽 대등. 문제가 "균형 모드"라고 하면 ABM, "종국이 허가 없이 응답"이라 하면 ARM 이다.

따라가기

  1. 프레임 → 정보 · 감독 · 비번호
  2. 균형 → ABM, 허가 없이 응답 → ARM

헷갈리는 자리 — NRM 을 ⑤ 에 적는 것. NRM 은 허가를 받아야 응답한다. 같은 문제가 3년 만에 그대로 나온 만큼 프레임 3 · 모드 3 여섯 낱말을 한 줄로 외운다.

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

2026-1회 · 7번보안

기업·기관의 정보보호 관리체계가 기준에 적합한지 정부 지정 인증기관이 심사하여 인증하는 제도는? (영문 약자)

정답ISMS

— ISMS. 정보보호 관리체계가 기준에 맞는지 정부 지정 기관이 심사해 인증하는 제도다.

원리 — 기업이 정보를 지키는 "체계"(정책 · 조직 · 절차 · 통제)를 갖췄는지 한국인터넷진흥원 등 지정 기관이 심사해 인증서를 주는 것이 ISMS(Information Security Management System) 인증이다. 개인정보 보호까지 함께 보면 ISMS-P 다. 일정 규모 이상의 사업자는 의무이고 유효 기간은 3년, 매년 사후 심사를 받는다. 국제 표준은 ISO 27001 이다. "관리체계 · 인증 · 정부 지정 기관"이 표지다.

따라가기

  1. 정보보호 관리체계 + 인증 제도 → ISMS

헷갈리는 자리 — ISO 27001(국제 표준)이나 PIMS(옛 개인정보 인증, 지금은 ISMS-P 로 통합)를 적는 것. 국내 제도의 영문 약자는 ISMS 다.

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

2026-1회 · 8번C

다음 C 프로그램을 실행했을 때 출력되는 값을 쓰시오.

#include <stdio.h> struct fns { int *(*fn)(int *); }; int *dummy(int *d) { return d + 1; } int main(void) { struct fns mine; int n[] = { 16, 32 }; mine.fn = dummy; printf("%x", *mine.fn(n)); return 0; }
정답20

— 20. 함수 포인터로 dummy 를 불러 배열의 둘째 칸 주소를 받고, 그 값 32 를 16진수로 찍는다.

원리int *(*fn)(int *) 는 "int 포인터를 받아 int 포인터를 돌려주는 함수"를 가리키는 포인터다. 구조체 멤버 fn 에 dummy 를 넣으면 mine.fn(n)dummy(n) 과 같다. dummy 는 받은 주소에 1 을 더해 돌려주므로 배열의 다음 칸(&n[1]) 주소다. 앞의 별표가 그 칸을 열어 32 가 나온다. %x 는 값을 16진수로 찍는 서식이라 32 는 0x20, 화면에는 20 이다.

따라가기

  1. n = [16, 32], mine.fn = dummy
  2. mine.fn(n) = dummy(n) → n + 1 → n[1] 의 주소
  3. * → 32
  4. %x → 32 = 2 × 16 + 0 → 20

헷갈리는 자리 — 32 를 그대로 적는 것. 서식이 %d 가 아니라 %x 다. 함수 포인터 선언이 낯설어 d + 1 을 값 17 로 읽는 것 — d 는 주소라 +1 은 한 칸 옆이다. 첫 칸 16 을 16진수로 바꾼 10 도 오답이다(dummy 가 한 칸 옮겼다).

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

2026-1회 · 9번SQL

STUDENT 테이블(총 200명, 학과 3개)에서: ① SELECT COUNT(*) FROM STUDENT;SELECT COUNT(DISTINCT 학과) FROM STUDENT;SELECT COUNT(DISTINCT 학과) FROM STUDENT WHERE 학과='전산과'; 각각의 결과는?

정답① 200 ② 3 ③ 1

— ① 200 ② 3 ③ 1. COUNT(*) 는 전체 행, COUNT(DISTINCT 학과) 는 서로 다른 학과 수, WHERE 로 한 학과만 남기면 그 수는 1 이다.

원리COUNT(*) 는 조건을 통과한 행의 수다(200 명 → 200). DISTINCT 는 중복을 지운다 — 200 행의 학과 값 중 서로 다른 것만 세면 학과 수 3 이다. ③ 은 WHERE 로 전산과 행만 남긴 뒤 그 안의 서로 다른 학과 값을 세니, 전산과 하나뿐이라 1 이다. 행 수(몇 명)와 종류 수(몇 학과)를 나누는 것이 전부다.

따라가기

  1. ① 전체 행 수 → 200
  2. ② 학과의 서로 다른 값 → 3
  3. ③ 전산과 행만 → 학과 값은 전산과 하나 → 1

헷갈리는 자리 — ③ 을 "전산과 학생 수"로 읽고 인원을 적는 것. DISTINCT 학과이므로 종류 수 1 이다. ② 를 200 으로 적는 것 — DISTINCT 가 있다. 세 문항이 COUNT 의 세 가지 쓰임을 정확히 나눠 묻는다. 학과 값에 NULL 인 학생이 있었다면 COUNT(DISTINCT 학과)는 NULL 을 안 세므로 ② 가 달라질 수 있다 — 문제는 그런 행이 없다고 본다.

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

2026-1회 · 10번Python

다음 Python 프로그램을 실행했을 때 출력되는 값을 쓰시오.

lst = list(range(10)) for c in lst[::-2]: print(c, end='A') print()
정답9A7A5A3A1A

— 9A7A5A3A1A. 0~9 리스트를 뒤에서부터 두 칸씩 건너뛰며 꺼내고, 각 값 뒤에 A 를 붙여 한 줄로 찍는다.

원리list(range(10)) 은 [0, 1, …, 9] 다. 슬라이스 [::-2] 는 시작 · 끝을 비우고 스텝을 −2 로 준 것이라 "끝에서 시작해 두 칸씩 거꾸로"다 — 9, 7, 5, 3, 1. print(c, end='A') 는 줄바꿈 대신 A 를 붙이라는 뜻이라 값들이 한 줄에 A 로 이어진다. 마지막 print() 는 빈 줄바꿈 하나를 찍어 줄을 끝낸다.

따라가기

  1. lst[::-2] → [9, 7, 5, 3, 1]
  2. 9 → "9A", 7 → "7A", 5 → "5A", 3 → "3A", 1 → "1A"
  3. 한 줄에 이어 9A7A5A3A1A, 그 뒤 줄바꿈

헷갈리는 자리 — 스텝이 음수인데 앞에서부터 0, 2, 4, … 로 적는 것. 음수 스텝은 시작이 끝이다. 마지막 1 뒤의 A 를 빼먹는 것 — end='A' 는 매 print 마다 붙는다. 마지막 print() 는 글자를 안 찍으므로 답에 들어가지 않는다.

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

2026-1회 · 11번네트워크

두 호스트의 IP 주소와 서브넷 마스크를 보고 각 호스트가 속한 네트워크 주소를 CIDR 표기법으로 쓰시오.

호스트IP 주소서브넷 마스크
a192.168.11.20255.255.254.0
b192.168.12.200255.255.254.0
정답a. 192.168.10.0/23
b. 192.168.12.0/23

— a. 192.168.10.0/23 b. 192.168.12.0/23. 마스크 254 는 셋째 옥텟을 2 씩 묶으므로 11 은 10~11, 12 는 12~13 묶음이다.

원리 — 255.255.254.0 은 앞 23비트가 네트워크 부분(/23)이다. 셋째 옥텟 254 = 1111 1110 이라 묶음 크기가 256 − 254 = 2 — 0~1, 2~3, …, 10~11, 12~13. 네트워크 주소는 묶음의 첫 값에 마지막 옥텟 0 을 붙인 것이고, CIDR 표기는 그 뒤에 /23 을 붙인다. 두 호스트는 이웃한 묶음이라 서로 다른 네트워크다.

따라가기

  1. 마스크 254 → /23, 셋째 옥텟 묶음 2
  2. a: 11 → 10~11 → 192.168.10.0/23
  3. b: 12 → 12~13 → 192.168.12.0/23

헷갈리는 자리 — a 를 192.168.11.0/23 으로 적는 것. 11 은 묶음의 시작이 아니라 끝이다 — 짝수에서 시작하는 2 묶음이라는 것을 표로 확인한다. /23 을 빼먹으면 "CIDR 표기"라는 요구를 못 채운다.

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

2026-1회 · 12번Python

다음 Python 프로그램을 실행했을 때 출력되는 값을 쓰시오.

def f(a): m = [[x] for x in a] b = m[:] for i in range(len(b) - 1): b[i + 1] += b[i] return sum(len(x) for x in m) print(f([1, 2, 3, 4]))
정답10

— 10. b = m[:] 는 겉 리스트만 새로 만들고 안쪽 리스트는 공유하므로, b 를 통해 늘린 안쪽 리스트가 m 에서도 보여 길이 합이 1 + 2 + 3 + 4 다.

원리m = [[x] for x in a] 는 [[1], [2], [3], [4]] 다. m[:] 는 얕은 복사 — 바깥 상자는 새로 만들지만 그 안의 네 리스트는 원래 것을 그대로 가리킨다. 그래서 b[i + 1] += b[i] 는 안쪽 리스트를 제자리에서 늘리는 것이고(리스트의 += 는 새 리스트를 만들지 않고 이어 붙인다), 그 안쪽 리스트는 m 도 같이 들고 있다. 결국 m 의 안쪽 리스트들이 [1], [2, 1], [3, 2, 1], [4, 3, 2, 1] 로 커진다. 완전히 떼어 놓으려면 copy.deepcopy 가 필요하다.

따라가기

  1. i = 0: b[1] += b[0] → [2] + [1] → [2, 1]
  2. i = 1: b[2] += b[1] → [3, 2, 1]
  3. i = 2: b[3] += b[2] → [4, 3, 2, 1]
  4. m 의 길이들 1 + 2 + 3 + 4 = 10

헷갈리는 자리 — [:] 를 완전 복사로 보고 m 이 안 바뀌었다며 4 를 적는 것. 얕은 복사는 안쪽을 공유한다. 반대로 b[i + 1] = b[i + 1] + b[i] 였다면 새 리스트가 만들어져 b 만 바뀌고 답은 4 였다 — += 와 = 의 차이까지가 이 문제다.

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

2026-1회 · 13번SQL

다음 두 테이블과 SQL문을 보고 반환되는 값을 쓰시오.

employee 테이블

dep_id
10
20
20

dept 테이블

dept_idbudget
10100
20300
30200
SELECT COUNT(*) FROM employee e JOIN dept d ON e.dep_id = d.dept_id WHERE d.budget > ( SELECT AVG(budget) FROM dept );
정답2

— 2. 예산 평균 200 보다 큰 부서는 20(300)뿐이고, 그 부서 직원이 두 명이다.

원리 — 서브쿼리 SELECT AVG(budget) FROM dept 는 하나의 값(200)을 돌려주고, 바깥 조건은 d.budget > 200 이 된다. JOIN … ON e.dep_id = d.dept_id 는 직원 행마다 부서 정보를 붙인다 — 직원이 세 행이니 조인 결과도 세 행이고, 그중 부서 예산이 200 을 넘는 행만 센다. 부서 30 은 직원이 없어 조인에 아예 안 나온다.

따라가기

  1. AVG(budget) = (100 + 300 + 200) / 3 = 200
  2. 조인: 직원 10 → 예산 100, 직원 20 → 300, 직원 20 → 300
  3. budget > 200 → 두 행 → 2

헷갈리는 자리 — 부서 수로 세어 1(부서 20 하나)을 적는 것. COUNT(*) 는 조인된 직원 행을 센다. 200 을 "이상"으로 보고 부서 30 까지 넣는 것 — > 는 초과이고, 30 은 직원이 없어 어차피 0 행이다.

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

2026-1회 · 14번Python

다음 Python 프로그램에 HumanDev를 입력했을 때 출력되는 값을 쓰시오.

i = input() x = [] for word in i.split(): x.append(word) y = ''.join(x) z = ''.join(c for c in y[::-1] if c not in 'ong') print(z)
정답veDamuH

— veDamuH. 입력 HumanDev 를 뒤집어 veDnamuH 로 만든 뒤 o · n · g 를 빼면 n 하나가 빠진다.

원리i.split() 은 공백으로 나누는데 "HumanDev" 엔 공백이 없어 조각이 하나뿐이고, ''.join(x) 로 다시 붙여도 그대로다. y[::-1] 은 문자열 뒤집기. ''.join(c for c in … if c not in 'ong') 은 글자를 하나씩 보며 o · n · g 중 하나가 아닌 것만 모아 붙인다. 대소문자를 구분하므로 대문자 D · H 는 그대로 남는다.

따라가기

  1. x = ["HumanDev"], y = "HumanDev"
  2. y[::-1] → "veDnamuH"
  3. o · n · g 제거 → n 하나 빠짐 → veDamuH

헷갈리는 자리 — 뒤집기 전에 글자를 빼거나, 'ong' 을 한 덩어리 문자열로 보고 "ong" 이 없으니 아무것도 안 뺀다고 보는 것 — c not in 'ong' 은 글자 하나가 그 세 글자 중 하나인지다. 대문자 H 는 안 빠진다는 것도 확인한다.

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

2026-1회 · 15번테스트

통합 테스트: ① 하향식에서 미완성 하위 모듈을 대신하는 것 ② 상향식에서 상위 모듈을 대신해 호출하는 것

정답① 스텁(Stub) ② 드라이버(Driver)

— ① 스텁(Stub) ② 드라이버(Driver). 2023-2-07 과 같은 문제다.

원리 — 통합 테스트에서 아직 없는 모듈의 자리를 채우는 가짜를 테스트 하네스라 한다. 하향식은 위에서 아래로 내려가니 "아직 안 만든 아래"가 비어 있다 — 위 모듈이 호출하면 미리 정한 값을 돌려주는 가짜 하위가 스텁이다. 상향식은 아래에서 위로 올라가니 "아직 안 만든 위"가 비어 있다 — 아래 모듈을 호출해 검사를 시작해 주는 가짜 상위가 드라이버다. 스텁은 "불려서 답하는 것", 드라이버는 "부르는 것"이다. 실무의 목(mock) 객체가 스텁의 확장이고, JUnit 테스트 메서드가 드라이버 역할이다.

따라가기

  1. "하향식 · 미완성 하위 모듈 대신" → 스텁
  2. "상향식 · 상위 모듈 대신 호출" → 드라이버

헷갈리는 자리 — 방향과 짝을 바꾸는 것. "하향식 → 하위가 없다 → 스텁", "상향식 → 상위가 없다 → 드라이버". 하 · 하, 상 · 상으로 첫 글자가 맞아떨어진다.

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

2026-1회 · 16번보안

표적이 자주 방문하는 웹사이트를 미리 감염시켜 놓고, 방문 시 악성코드에 감염시키는 공격 기법은? (사자가 물웅덩이에서 사냥감을 기다리는 것에서 유래)

정답워터링 홀 (Watering Hole)

— 워터링 홀(Watering Hole). 표적이 자주 가는 사이트를 미리 감염시켜 놓고 방문하기를 기다리는 공격이다.

원리 — 표적 조직에 직접 침입하기 어려우면 그 사람들이 늘 들르는 사이트(협회 · 커뮤니티)를 먼저 해킹해 악성코드를 심는다. 표적이 평소처럼 방문하는 순간 감염된다 — 사자가 물웅덩이 옆에 숨어 물 마시러 오는 사냥감을 기다리는 데서 이름이 왔다. 사용자가 이상한 링크를 누른 것도 아니라 눈치채기 어렵고, APT 의 초기 침투 수단으로 자주 쓰인다.

따라가기

  1. 표적이 자주 방문하는 사이트를 미리 감염 + 방문 시 감염 → 워터링 홀

헷갈리는 자리 — 피싱(가짜 사이트로 유인)이나 파밍(DNS 조작)과 섞는 것. 워터링 홀은 "진짜 사이트를 감염"시키고 유인 메일이 없다는 것이 다르다.

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

2026-1회 · 17번Java

다음 Java 프로그램을 실행했을 때 출력되는 값을 쓰시오.

public class Main { public static void main(String[] args) { int x1 = 9; int x2 = 2; String x3 = "3"; System.out.println(x1 + x2 + "2" + x3); } }
정답1123

— 1123. 왼쪽부터 계산해 9 + 2 = 11 이 먼저 정수로 더해지고, 그다음부터는 문자열 붙이기라 "11" + "2" + "3" 이다.

원리+ 는 두 쪽이 모두 숫자면 덧셈이고, 한쪽이라도 문자열이면 붙이기다. 그리고 왼쪽에서 오른쪽으로 하나씩 계산한다. x1 + x2 는 둘 다 int 라 11(덧셈), 그 결과 11 과 "2" 는 한쪽이 문자열이라 "112"(붙이기), 이어서 "112" + "3" → "1123". 문자열이 한 번 끼어든 뒤부터는 되돌아가지 않는다. 괄호가 없으니 순서를 바꿔 읽을 여지가 없다.

따라가기

  1. 9 + 2 → 11 (정수)
  2. 11 + "2" → "112"
  3. "112" + "3" → 1123

헷갈리는 자리 — 전부 문자열로 보고 9223 을 적는 것(첫 덧셈은 정수). 전부 숫자로 보고 16 을 적는 것("2" 와 "3" 은 문자열). "2" + x1 + x2 였다면 "292" 가 되듯 순서가 답을 바꾼다. 괄호로 x1 + (x2 + "2") 라고 묶으면 안쪽이 먼저 붙기라 "9223" 이 된다 — 괄호 유무도 본다.

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

2026-1회 · 18번SQL

다음 조건을 만족하도록 PLAYER 테이블의 외래키 제약 조건을 완성하시오.

외래키 제약 조건의 이름은 TEAM_TF이다.
PLAYER 테이블의 TEAM_ID가 외래키다.
TEAM 테이블의 TEAM_ID2를 참조한다.

CREATE TABLE PLAYER ( PLAYER_ID CHAR(7) NOT NULL, PLAYER_NAME VARCHAR2(20) NOT NULL, TEAM_ID CHAR(3) NOT NULL, PRIMARY KEY (PLAYER_ID), ① TEAM_TF ② KEY (③) ④ TEAM (⑤) );
정답① CONSTRAINT ② FOREIGN ③ TEAM_ID ④ REFERENCES ⑤ TEAM_ID2

— ① CONSTRAINT ② FOREIGN ③ TEAM_ID ④ REFERENCES ⑤ TEAM_ID2. 이름 붙은 외래키 제약을 적는 정해진 꼴이다.

원리 — 외래키는 "이 열의 값은 저 테이블의 저 열에 있는 값이어야 한다"는 약속이다. 테이블을 만들 때 적는 꼴은 CONSTRAINT 제약이름 FOREIGN KEY (내 열) REFERENCES 상대테이블(상대 열) 이다. CONSTRAINT 이름은 나중에 지울 때(ALTER TABLE … DROP CONSTRAINT 이름) 부르기 위해 붙인다. 문제가 준 조건 셋 — 이름 TEAM_TF, 내 열 TEAM_ID, 상대 TEAM 의 TEAM_ID2 — 을 그 자리에 넣으면 된다.

따라가기

  1. 제약 이름을 붙이는 낱말 → CONSTRAINT TEAM_TF
  2. 외래키 선언 → FOREIGN KEY (TEAM_ID)
  3. 참조 대상 → REFERENCES TEAM (TEAM_ID2)

헷갈리는 자리 — ⑤ 에 TEAM_ID 를 적는 것. 상대 테이블의 열 이름은 TEAM_ID2 라고 문제가 못 박았다. ④ 에 REFERENCE(단수)를 적는 것 — REFERENCES 다. PRIMARY KEY 처럼 FOREIGN KEY 도 두 낱말이라 ② 는 FOREIGN 하나다.

답의 SQL 을 sqlite 3.49 에서 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 열 이름이 실제와 다를 수 있다.

2026-1회 · 19번보안

원본 파일을 가리키는 바로가기(링크) 파일을 악용하여, 링크를 조작해 공격자가 의도한 파일에 접근하게 만드는 공격은? (보기 선택형)

정답심볼릭 링크 공격 (Symbolic Link Attack)

— 심볼릭 링크 공격(Symbolic Link Attack). 바로가기 파일이 가리키는 곳을 바꿔 프로그램이 엉뚱한 파일을 읽거나 쓰게 만드는 공격이다.

원리 — 심볼릭 링크는 다른 파일을 가리키는 바로가기다. 권한 높은 프로그램이 임시 파일 이름으로 무언가를 쓸 때, 공격자가 먼저 그 이름의 링크를 만들어 /etc/passwd 같은 중요 파일을 가리키게 해 두면 프로그램은 링크를 따라가 그 파일을 덮어쓴다. 검사 시점과 사용 시점 사이의 틈(경쟁 조건, TOCTOU)을 이용하는 것이다. 막으려면 임시 파일을 안전한 방식으로 만들고 링크를 따라가지 않게 한다.

따라가기

  1. 바로가기(링크) 조작 + 의도한 파일에 접근 → 심볼릭 링크 공격

헷갈리는 자리 — 경로 조작(path traversal, ../ 로 상위 폴더 접근)과 섞는 것. 그것은 입력 문자열로 경로를 바꾸는 것이고, 심볼릭 링크 공격은 파일 시스템의 링크를 바꾼다. 보기 선택형이면 낱말 그대로 고른다.

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

2026-1회 · 20번SW공학

응집도 3종: ① 다수의 관련 기능이 순서에 따라 차례대로 수행됨 ② 동일한 입출력 데이터를 사용하는 기능들이 모임 ③ 단일 기능만 수행

정답① 절차적 응집도 ② 교환(통신)적 응집도 ③ 기능적 응집도

— ① 절차적 응집도 ② 교환(통신)적 응집도 ③ 기능적 응집도. "순서대로 · 같은 자료 · 단일 기능"이 열쇠말이다.

원리 — 응집도 7단계는 모듈 안의 것들이 "왜 같이 있는가"로 구분한다. 우연적(이유 없음) < 논리적(비슷해서, 플래그로 골라 씀) < 시간적(같은 시점) < 절차적(순서대로 실행) < 교환적(같은 입출력 자료) < 순차적(앞 출력 = 뒤 입력) < 기능적(한 가지 일). 절차적은 "A 다음 B 를 한다"는 순서만 있고 자료 연결은 없다. 교환적은 같은 자료를 여럿이 다룬다 — 예: 같은 고객 레코드로 이름도 찍고 주소도 찍는다. 기능적은 모듈 전체가 오직 한 가지 목적(제곱근 계산)만 한다 — 가장 좋다.

따라가기

  1. "관련 기능이 순서에 따라 차례대로" → 순서만 → 절차적
  2. "동일한 입출력 데이터를 사용하는 기능들" → 자료 공유 → 교환적
  3. "단일 기능만 수행" → 기능적

헷갈리는 자리 — ①을 순차적으로 적는 것. 순차적은 "출력이 다음 입력"이라는 자료 연결이 있어야 한다. 순서만 있으면 절차적이다. 그리고 교환적은 "통신적(Communicational)"이라고도 부르니 둘 다 정답 처리된다. ②를 시간적으로 적는 실수도 있다 — 시간적은 "같은 때"이지 "같은 자료"가 아니다. 자료라는 말이 보이면 교환적 아니면 순차적 둘 중 하나다.

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

03채점 뒤 할 일

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

코드 7문항 중 C 2 · Java 2 · Python 3 이다. 1번은 B 의 f(Object) 가 오버라이딩이고 f(String) 은 오버로딩이라 g() 안의 f("a") 는 A 에서 컴파일된 f(Object) 로 묶여 2 다. 8번은 함수 포인터 멤버가 d + 1 을 돌려줘 32 를 %x 로 찍으면 20. 12번은 m[:] 가 겉만 복사라 안쪽 리스트가 함께 커져 10 이다.

SQL·DB 는 9번 COUNT(*) · COUNT(DISTINCT) 세 값, 13번 AVG 서브쿼리 조인 건수 2, 18번 CONSTRAINT · FOREIGN · TEAM_ID · REFERENCES · TEAM_ID2 다섯 칸, 4번 설계 5단계다. 18번은 칸마다 점수가 있어 구문 순서만 알면 채운다.

용어는 SW공학 4(Bridge/Observer · 비기능 요구사항 3칸 · 스텁/드라이버 · 응집도 3칸) · 보안 3(ISMS · 워터링 홀 · 심볼릭 링크) · 네트워크 2(HDLC 5칸 · /23 CIDR)다. 5번 비기능 요구사항의 운영 · 자원 · 성능은 이 회차에 처음 나온 낱말이라 E16 표에 넣어 두었다.

문항마다 가는 장

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

문항분야가는 장무엇을 묻나
1JavaE05Object 매개변수 오버라이딩 vs String 오버로딩
2CE02배열 평균 두 번 — p[] 와 *(p + i)
3디자인패턴E17Bridge 와 Observer
4DBE10DB 설계 5단계 순서
5SW공학E16비기능 요구사항 — 운영 · 자원 · 성능
6네트워크E11HDLC 프레임 3종과 모드 2종
7보안E13ISMS 인증
8CE03함수 포인터 멤버로 d + 1 — %x 출력
9SQLE08COUNT(*) 와 COUNT(DISTINCT)
10PythonE07[::-2] 역순 스텝과 end='A'
11네트워크E12/23 네트워크 주소 CIDR
12PythonE07얕은 복사 m[:] 와 안쪽 리스트 공유
13SQLE08AVG 서브쿼리보다 큰 예산 조인 건수
14PythonE07split · join · 역순 · 글자 빼기
15테스트E18스텁과 드라이버
16보안E14워터링 홀
17JavaE06int + int + "2" + String 결합 순서
18SQLE09FOREIGN KEY 제약 구문 빈칸 5개
19보안E14심볼릭 링크 공격
20SW공학E15절차적 · 교환적 · 기능적 응집도

이 회차에서 눈여겨볼 문항

문항왜 갈리나
1번g() 는 A 에 있고 f("a") 는 f(Object) 로 묶인다. 실행 때 B 의 f(Object) 가 골라져 2. f(String) 은 오버로딩이라 안 불린다
8번mine.fn(n) 은 n + 1 이라 32 를 가리킨다. %x 는 16진수라 20
12번b = m[:] 뒤 b[i + 1] += b[i] 는 안쪽 리스트를 제자리에서 늘린다. m 의 길이 합 1 + 2 + 3 + 4 = 10
17번9 + 2 = 11 이 먼저, 그다음 "2" 가 붙어 문자열 112, 마지막 "3" → 1123

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

04다음

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