정보처리기사 실기 2026년 3회 정답과 해설: 복원 20문항 풀이와 가채점 정답표

정보처리기사 실기 2026년 3회 정답과 해설을 정리했다. 3회 실기를 직접 치고 나서, 수험생들이 복원한 20문항의 답을 하나씩 다시 확인했다. 복원 글에 적힌 답을 그대로 옮기지 않고 코드 8문항은 컴파일해 실행했고, SQL 2문항은 Oracle에서 돌렸고, 서브넷은 계산으로 확인했다(실행 검증은 Claude Code로 했다). 전부 복원 정답과 같았다.

2026-10-26 기준이다. 문항은 정처기감자 두근두근 문제 복원에서 문항마다 공감이 가장 많은 복원을 골랐고, 문제 문장은 짧게 다시 썼다. 20문항 중 17문항은 사이트에서 '확정'으로 표시됐고 6·7·18번은 아직 편집 중이다. 공식 문제와 정답은 공개되지 않으므로 복원이 바뀌면 답도 바뀔 수 있다.

10-26에 복원 번호가 바뀌어 이 글도 새 번호로 고쳤다. C 함수 포인터 16→5번, C 이중 포인터 18→13번, 루트킷 5→16번, SBOM 19→18번, Python 상속 13→19번이다. 5·12·17·19번은 코드도 바뀌었지만 정답은 그대로다.

출제 분포(복원 기준)는 C 3 · Java 3 · Python 2 · SQL 3 · 이론 9문항이다. 아래 정답표로 가채점하고, 헷갈리는 문항은 문항별 해설에서 풀이 표와 자주 나오는 오답을 확인하면 된다.

한눈에

  • 이론은 대부분 예전 기출이 그대로 다시 나왔다. 9문항 중 8문항이 이전 회차와 같은 문제나 같은 개념이다. 특히 2022년 3회에서만 세 문제(경계값 분석, FLSM 서브넷, UML 구성 요소)가 다시 나왔다. 처음 나온 용어는 18번 SBOM 하나다.
  • 서브넷도 나왔다. “1·2회에 서브넷이 나왔으니 3회엔 안 나온다”는 말이 돌았지만 10번에 2022-3 문제가 그대로 나왔다.
  • 코딩은 기본 개념의 동작 원리를 묻는 변형이 많았다. Python 가변 기본 인자(20번), C 구조체 배열 속 함수 포인터(5번)와 이중 포인터(13번), Java 2차원 배열의 행 공유(15번), 자식 필드와 super(14번), 오버로딩과 null(17번).
  • SQL 3문항: LEFT JOIN + IS NULL(1번), ORDER BY 빈칸(3번, 2022-1과 같은 유형), 2단 서브쿼리 AVG + IN + MAX(12번).
2026년 1·2·3회 정보처리기사 실기 이론·SQL 문항 중 예전 기출과 같은 문제·개념의 수를 나타낸 누적 막대 차트. 1회 13문항 중 8개, 2회 13문항 중 9개, 3회 12문항 중 9개.
2020-1부터 2026-2까지 21회차 복원 기출과 대조한 결과. 3회는 이론·SQL 12문항 중 9개가 예전 기출과 같은 문제나 개념이었다

가채점 정답표

번호영역정답비고
1SQL2
2DB 설계① 물리적 ② 개념적 ③ 논리적 설계2026-1·2023-2와 같은 개념
3SQL① ORDER ② score ③ DESC2022-1과 같은 유형
4디자인 패턴Factory Method (보기 ㅅ)2021-3과 같은 개념
5C7코드 순서 논쟁 있음
6암호① IDEA ② Skipjack2022-2와 같은 문제
7테스트경계값 분석 (보기 ㄹ)2022-3과 같은 유형
8접근 통제RBAC2023-3·2025-3과 같은 개념
9C4
10서브넷192.168.1.1272022-3과 같은 문제
11UML① 관계 ② 클래스 ③ 인터페이스2022-3과 같은 문제
12SQL130
13C13
14Java2
15Java3 그리고 1
16보안루트킷 (Rootkit, 보기 ㅅ)2024-1과 같은 개념
17Javaerror
18신기술SBOM처음 나온 용어
19Python48
20Python-2

보기 기호(ㅅ, ㄹ)는 복원자가 기억한 보기 순서를 따른 것이라 실제 시험지와 다를 수 있다.

문항별 정답과 해설

1. SQL — LEFT JOIN과 IS NULL (결과 값)

A

id
1
2
3

B

id
1
SELECT COUNT(*) AS result
FROM A
LEFT JOIN B ON A.id = B.id
WHERE B.id IS NULL;

정답과 해설

정답: 2

LEFT JOIN은 '왼쪽(FROM에 먼저 쓴 A)의 행을 전부 남기고', 오른쪽에 짝이 없으면 오른쪽 칸을 NULL로 채운다.

A.idB.id
11
2NULL
3NULL

WHERE B.id IS NULL → B에 짝이 없는 2, 3 → '2'. “한쪽에만 있는 행 찾기”는 OUTER JOIN + IS NULL이 공식이다. (Oracle 실행 확인)

  • 오답 3: WHERE를 빼고 센 경우. 오답 1: INNER JOIN처럼 짝이 있는 행만 센 경우.
  • 참고: JOIN만 쓰면 INNER JOIN이고, LEFT JOIN은 LEFT OUTER JOIN의 줄임이다.

2. DB — 설계 단계

다음 설명에 해당하는 데이터베이스 설계 단계를 쓰시오. (보기: 개념적 설계, 논리적 설계, 물리적 설계)

  • ① 운영체제와 DBMS의 특성을 고려해 데이터베이스의 내부 저장 구조, 인덱스, 접근 방법 등을 설계하는 단계
  • ② 요구사항 분석 결과를 바탕으로 특정 DBMS에 독립적인 데이터 모델을 설계하고 E-R 다이어그램으로 표현하는 단계
  • ③ 관계형 데이터베이스의 테이블 구조와 스키마를 설계하는 단계

정답과 해설

정답: ① 물리적 설계 ② 개념적 설계 ③ 논리적 설계

전체 순서는 요구사항 분석 → '개념적' → '논리적' → '물리적' → 구현이다. 이번엔 순서를 섞어서 물었으니 단서 단어로 고른다.

단계하는 일단서 단어
개념적 설계개체·관계 파악, E-R 다이어그램“E-R”, “특정 DBMS에 독립적”
논리적 설계E-R을 관계 스키마(테이블)로 변환, 정규화“테이블 구조”, “스키마”, “관계형 데이터 모델”
물리적 설계저장 구조·인덱스·접근 경로“내부 저장 구조”, “인덱스”, “운영체제·DBMS 특성 고려”
  • 헷갈리는 지점: “DBMS”라는 말이 ①과 ②에 다 나온다. ②는 “DBMS에 '독립적'”이라 개념적 설계고, ①은 “DBMS 특성을 고려한 '저장 구조'”라 물리적 설계다. ③의 테이블 구조와 스키마는 저장 방식이 아니라 논리 구조라서 논리적 설계다.

3. SQL — ORDER BY 빈칸

STUDENT 테이블에서 학생의 이름과 점수를 점수가 높은 순서(내림차순)로 조회하도록 빈칸 ①~③을 채우시오.

STUDENT

idnamescore
1김민수80
2이지은95
3박서준70
4최유진85
SELECT name, score
FROM STUDENT
( ① ) BY ( ② ) ( ③ );

정답과 해설

정답: ① ORDER ② score ③ DESC

  • ORDER BY 칼럼 DESC = 내림차순, ASC(또는 생략) = 오름차순.
  • 조회 결과는 이지은 95 → 최유진 85 → 김민수 80 → 박서준 70 순서다.

소문자로 order score desc라고 써도 되나?

된다.

  • SQL 키워드(ORDER BY, DESC)는 표준 SQL과 Oracle·MySQL·PostgreSQL 모두 대소문자를 구분하지 않는다. order by와 ORDER BY는 같은 문장이다.
  • 따옴표로 감싸지 않은 칼럼 이름도 대소문자를 구분하지 않는다. score와 SCORE는 같은 칼럼이다.
  • 10-26 확정 복원은 ②를 테이블 그대로 소문자 score로 적었고, 대문자 SCORE도 정답으로 인정될 것으로 추정했다. 공식 채점 기준은 공개되지 않는다. 감점 위험은 대소문자보다 철자(DESC → DECS)에 있다.

4. 디자인 패턴

다음 설명에 해당하는 GoF 디자인 패턴을 보기에서 고르시오.

생성 패턴 중 하나로, 객체를 생성하기 위한 인터페이스를 정의하고 '실제로 생성할 객체의 종류는 하위 클래스에서 결정'하도록 한다. 객체 생성 과정을 추상화해 구체적인 생성을 하위 클래스에 위임한다.

보기: ㄱ. Adapter ㄴ. Singleton ㄷ. Template Method ㄹ. Decorator ㅁ. Observer ㅂ. Strategy ㅅ. Factory Method ㅇ. Mediator

정답과 해설

정답: ㅅ. Factory Method (팩토리 메서드)

패턴단서
Factory Method생성할 객체를 하위 클래스가 결정 (생성 패턴)
Template Method알고리즘의 뼈대는 상위 클래스, 일부 단계만 하위 클래스가 구현 (행위 패턴)
Singleton객체를 하나만 생성
Abstract Factory관련 객체들의 제품군을 한꺼번에 생성, 별칭 Kit (2026-2 2번)
Builder복잡한 객체를 단계별로 조립
Prototype기존 객체를 복제해서 생성
  • 함정: 보기에 Template Method가 있다. “하위 클래스”라는 말만 보면 둘 다 맞아 보이지만, “생성 패턴”과 “객체 생성”이 나오면 Factory Method다.

5. C — 구조체 배열 속 함수 포인터 (실행 결과)

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int sub(int a, int b) {
    return a - b;
}

typedef struct {
    int value;
    int (*fn)(int, int);
} Item;

int main(void) {
    Item arr[2] = {{3, add}, {10, sub}};
    Item *p = arr;
    Item *ptr;
    int a, b;

    p++;
    ptr = p;
    a = p->value;

    p--;
    b = p->value;

    printf("%d", ptr->fn(a, b));
    return 0;
}

정답과 해설

정답: 7

읽는 법 세 줄:

  • Item *p = arr; → p는 arr[0]을 가리킨다(배열 이름 = 첫 원소의 주소).
  • p++ → '구조체 하나만큼' 이동해 arr[1]을 가리킨다(1바이트가 아니다).
  • p->value는 (*p).value — p가 가리키는 구조체의 멤버다.
줄p가 가리키는 것ptr이 가리키는 것결과
Item *p = arr;arr[0] = {3, add}
p++arr[1] = {10, sub}
ptr = parr[1]arr[1]p에 든 주소를 ptr에 복사
a = p->valuearr[1]arr[1]a = 10
p--arr[0] = {3, add}arr[1] (그대로)
b = p->valuearr[0]arr[1]b = 3
ptr->fn(a, b)arr[1]의 fn = subsub(10, 3) = 7
  • 오답 13 (add(10, 3)): p–를 하면 ptr도 따라서 arr[0]으로 간다고 본 경우. ptr은 p와 '별개의 변수'다. ptr = p 순간 p에 들어 있던 주소(arr[1])를 복사해 둔 것뿐이라 p를 옮겨도 그대로다. 일반 변수 a가 p를 옮겨도 10으로 남는 것과 같다.
  • 오답 −7: a와 b를 바꿔 sub(3, 10)으로 계산한 경우.

“포인터로 받았으니 p를 따라가서 13 아닌가?”

코드의 순서에 달렸다. 네 가지 경우를 직접 실행한 결과:

코드결과
구조체 포인터 ptr = p;를 p-- 전에 저장 (위 코드, 10-26 확정 복원)7
함수 포인터 ptr = p->fn;을 p-- 전에 저장 (10-25까지의 1위 복원)7
ptr = p;를 p-- 뒤에 저장13
Item **ptr = &p; (p 자체를 가리키는 이중 포인터)13

포인터 변수도 대입하는 '순간의 주소를 복사'해 둘 뿐이라, 그 뒤에 p를 옮겨도 따라가지 않는다. 13이 되려면 대입이 p-- 뒤에 있었거나, p 자체의 주소(&p)를 담는 이중 포인터여야 한다. 10-26에 확정된 복원도 p-- 전에 저장하는 코드라 답은 7이다. 다만 이 복원에는 반대 표도 11개 붙어 있어 순서를 다르게 기억하는 응시자가 있다. 실제 시험지의 순서가 다르게 확인되면 답도 달라진다.

  • 구조체 안의 int (*fn)(int, int) 읽는 법: 괄호 안부터 — “fn은 '포인터', 가리키는 것은 int 두 개를 받아 int를 돌려주는 '함수'”. 구조체 포인터로 부를 때는 ptr->fn(a, b).

6. 보안 — 대칭키 암호 알고리즘

괄호에 들어갈 대칭키 암호화 알고리즘을 쓰시오.

  • ① Xuejia Lai와 James Massey가 제시한 암호화 알고리즘으로, PES와 IPES를 거쳐 ( ① )로 명명되었다. 128비트 키로 64비트 평문을 8라운드에 걸쳐 암호화한다.
  • ② ( ② )는 미국 국가안보국(NSA)이 개발한 Clipper 칩에 내장된 블록 암호다. Fortezza 카드에 칩 형태로 구현되었고 주로 음성 암호화에 쓰인다. 64비트 입출력, 80비트 키, 32라운드.

정답과 해설

정답: ① IDEA ② Skipjack

  • 2022년 2회와 같은 문제다.
  • 단서만 기억하면 된다: “Lai·Massey, PES → IPES” → 'IDEA' / “NSA, Clipper 칩, Fortezza” → 'Skipjack'.

자주 나오는 대칭키 블록 암호 정리:

알고리즘단서
DES옛 미국 표준, 64비트 블록, 56비트 키
AESDES 대체, NIST 공모, 128비트 블록, 128/192/256비트 키
SEED한국(KISA) 개발, 128비트 블록
ARIA한국 국가 표준, 학·연·관 공동 개발
IDEALai·Massey, PES → IPES, 128비트 키, 8라운드
SkipjackNSA, Clipper 칩, 80비트 키, 32라운드

7. 테스트 — 블랙박스 기법

입력값의 범위에 따라 처리하는 프로그램의 테스트 데이터와 결과다. 적용된 블랙박스 테스트 기법을 보기에서 골라 기호를 쓰시오.

입력값은 0 이상 100 이하의 정수이고, 세 구간(0 이상 10 미만 / 10 이상 70 미만 / 70 이상 100 이하)으로 나누어 처리한다. 범위를 벗어난 입력값은 오류로 처리한다.

테스트 데이터-1019101169707199100101
테스트 결과오류정상정상정상정상정상정상정상정상정상정상오류

보기: ㄱ. 동치 분할 테스트 ㄴ. 원인-결과 그래프 테스트 ㄷ. 결정 테이블 테스트 ㄹ. 경계값 분석 ㅁ. 오류 예측 테스트 ㅂ. 상태 전이 테스트 ㅅ. 유스케이스 테스트 ㅇ. 비교 테스트

정답과 해설

정답: ㄹ. 경계값 분석 (Boundary Value Analysis)

구간의 경계는 0, 10, 70, 100이다. 테스트 값이 이 '경계와 그 바로 앞뒤'(−1·0·1, 9·10·11, 69·70·71, 99·100·101)에 모여 있다. 경계 근처에서 오류가 많이 난다는 점을 노린 기법이다.

기법테스트 값을 고르는 방식이 문제였다면
경계값 분석구간의 경계와 그 바로 옆−1, 0, 1, 9, 10, 11 … ← 이 문제
동등(동치) 분할구간마다 대표값 하나5, 40, 85 … 처럼 구간 안의 값 하나씩 (2026-2 5번)
원인-결과 그래프입력 조건(원인)과 출력(결과)의 논리 관계를 그래프로 그려 테스트 케이스 도출표에 그래프·조건 조합이 나온다
결정 테이블조건 조합 × 동작을 표로 정리조건 Y/N 조합 표가 나온다
상태 전이상태와 이벤트에 따른 전이를 따라감상태 다이어그램이 나온다
오류 예측경험·직관으로 오류가 날 만한 값
비교여러 버전에 같은 입력을 넣고 결과 비교
  • 오답 원인-결과 그래프: “입력 → 결과(오류)” 표라서 원인·결과가 떠오르지만, 원인-결과 그래프는 조건들의 AND·OR 관계를 그래프로 그리는 기법이다. '값이 경계에 몰려 있으면 경계값 분석.'

8. 보안 — 접근 통제

다음 설명에 해당하는 접근 통제 방식을 보기에서 골라 쓰시오.

사용자에게 개별적으로 접근 권한을 부여하면 직책이 바뀔 때마다 권한이 누적되어 관리가 복잡해진다. 이를 해결하기 위해 '직책별로' 필요한 접근 권한을 정해 두고, 사용자는 자신에게 부여된 직책에 따라 자원에 접근하도록 한다.

보기(일부만 복원): MAC, DAC, RBAC, PBAC

정답과 해설

정답: RBAC (Role-Based Access Control, 역할 기반 접근 통제)

단서는 “직책별로 권한을 정해 두고 사람에게는 직책을 준다”다. 권한을 사람이 아니라 역할(Role)에 묶으니, 부서를 옮기면 역할만 바꾸면 되고 권한이 쌓이지 않는다.

방식누가 권한을 정하나단서
DAC (임의적)자원의 소유자가 재량으로“소유자”, “신분(ID)에 따라” — 리눅스 chmod가 이 방식
MAC (강제적)시스템이 보안 등급·레이블로 강제“보안 등급”, “비밀 취급 인가”, “소유자도 못 바꿈”
RBAC (역할 기반)역할에 권한을 묶고 사람에게 역할 부여“직무”, “직책”, “역할”, “부서 이동 시 역할만 변경”
PBAC (정책 기반)관리자가 정한 정책(규칙)으로 요청마다 판단“정책”, 시간·위치 같은 조건
  • 복원자 메모: 실제 보기는 더 있었고, 기호로 답하는지 용어로 답하는지는 아직 확인 중이다.

9. C — 트리 순회와 카운터 (실행 결과)

#include <stdio.h>

typedef struct Node {
    int value;
    struct Node *left;
    struct Node *right;
} Node;

int cnt = 0;

void pre(Node *n) {
    if (!n) return;

    if (++cnt == 3) {
        printf("%d", n->value);
        return;
    }

    pre(n->left);
    pre(n->right);
}

int main(void) {
    Node n4 = {4, NULL, NULL};
    Node n5 = {5, NULL, NULL};
    Node n2 = {2, &n4, &n5};
    Node n3 = {3, NULL, NULL};
    Node n1 = {1, &n2, &n3};

    pre(&n1);
    return 0;
}

정답과 해설

정답: 4

1단계 — 구조체를 트리로 옮겨 그린다. {값, 왼쪽, 오른쪽} 순서이므로 n2 = {2, &n4, &n5}는 “값 2, 왼쪽 n4, 오른쪽 n5″다.

        n1(1)
       /     \
    n2(2)   n3(3)
    /   \
 n4(4)  n5(5)

2단계 — 함수가 언제 세는지 본다. ++cnt가 자식을 부르기 '전에' 있으므로 “자기 자신 → 왼쪽 → 오른쪽” 순서(전위 순회)로 센다. 함수 이름 pre도 전위 순회(preorder)라는 힌트다.

방문cnt출력
n11
n22
n434 출력 후 return
n54
n35
  • if (!n) return;은 “'n이 NULL이면' 끝낸다”는 뜻이다. !n은 n == NULL일 때 참이다(n이 NULL이 아니면 무조건 return이라는 뜻이 아니다).
  • n4에서 return한 뒤에도 n2로 돌아가 n5를 방문한다. 하지만 cnt가 3이 아니라 아무것도 출력하지 않는다.
  • 같은 트리라도 ++cnt가 재귀 호출 '뒤'에 있으면(후위 순회, 2026-2 15번) n4 → n5 → n2 순이라 답은 2가 된다. 세는 줄의 위치가 답을 정한다.

10. 네트워크 — FLSM 서브네팅

192.168.1.0/24 네트워크를 FLSM 방식으로 3개 네트워크에 쓸 수 있도록 나누려 한다. IP Subnet-zero를 적용하며, 첫 번째 네트워크가 192.168.1.0/26일 때, 두 번째 네트워크의 브로드캐스트 주소를 10진수로 쓰시오.

정답과 해설

정답: 192.168.1.127

FLSM(모든 서브넷 크기가 같음) 계산 순서:

단계할 일이 문제
① 서브넷 비트필요한 개수 이상이 되는 2의 거듭제곱3개 → 2² = 4 → 2비트 (2¹ = 2는 부족)
② 프리픽스원래 + 서브넷 비트/24 + 2 = /26 (문제에도 주어짐)
③ 블록 크기2^(32 − 프리픽스)2⁶ = 64
④ 범위0부터 블록 크기씩1번 .0~.63 / 2번 .64~.127 / 3번 .128~.191 / 4번 .192~.255
⑤ 브로드캐스트범위의 마지막 주소192.168.1.127
  • 네트워크 주소는 범위의 첫 주소(.64), 브로드캐스트는 마지막 주소(.127)다. 호스트에 줄 수 있는 건 그 사이(.65~.126)다.
  • Subnet-zero 적용은 첫 서브넷(.0~.63)도 쓴다는 뜻이다. 문제에서 첫 네트워크를 192.168.1.0/26으로 준 것과 같은 말이다.
  • 4개로 나뉘고 그중 3개를 쓴다. 정확히 3등분하는 것이 아니다.
  • 2022년 3회와 같은 문제다.

11. UML — 구성 요소

UML 구성 요소에 대한 설명을 읽고 빈칸 ①~③에 알맞은 용어를 쓰시오.

UML의 기본 구성 요소는 사물(Things), ( ① ), 다이어그램(Diagrams)이다. 사물 중 정적 사물에는 클래스, 인터페이스, 통신, 유스케이스, 컴포넌트, 노드가 있다.

정적 사물 ( ② )는 동일한 속성·연산·관계·의미를 공유하는 객체들의 집합이다. (복원에는 Student 그림이 함께 있다: 속성 - name: String, 연산 + study(): void)

정적 사물 ( ③ )는 객체가 제공하는 서비스나 기능을 명세하는 연산들의 집합으로, 구현 내용은 포함하지 않는다. 표기할 때 스테레오타입 기호 << >>를 쓴다.

정답과 해설

정답: ① 관계 (Relationships) ② 클래스 (Class) ③ 인터페이스 (Interface)

  • ① UML = 사물 + '관계' + 다이어그램.
  • ② “같은 속성·연산을 공유하는 객체들의 '집합'” = 클래스(객체를 찍어 내는 틀). 그림의 -는 private, +는 public이다.
  • ③ “연산들의 집합, '구현은 포함하지 않음'” = 인터페이스. 다이어그램에서는 이름 위에 <<interface>>라고 적어 표시한다. 무엇을 할 수 있는지(메서드 이름·형태)만 정하고, 어떻게 하는지는 구현 클래스가 채운다. Java의 interface가 바로 이것이다.
속성(필드)연산 이름구현(몸통)
클래스있음있음있음
인터페이스(상수만)있음없음
  • 2022년 3회와 같은 문제다.

12. SQL — 2단 서브쿼리 AVG·IN과 MAX (결과 값)

SALES

YEARQUARTERAMOUNT
20231100
20232150
20233130
20234170
20241120
20243200
SELECT MAX(AMOUNT) AS RESULT
FROM SALES
WHERE YEAR = 2023
  AND QUARTER IN (
      SELECT QUARTER
      FROM SALES
      WHERE YEAR = 2023
        AND AMOUNT < (
            SELECT AVG(AMOUNT)
            FROM SALES
            WHERE YEAR = 2023
        )
  );

정답과 해설

정답: 130

가장 안쪽부터 바깥으로 푼다.

  1. 맨 안쪽: 2023년 AVG = (100 + 150 + 130 + 170) ÷ 4 = '137.5'
  2. 가운데: 2023년 중 AMOUNT < 137.5인 분기 → 1분기(100), 3분기(130) → QUARTER '(1, 3)'
  3. 바깥: YEAR = 2023 AND QUARTER IN (1, 3) → 100, 130
  4. 남은 행의 MAX → '130' (Oracle 실행 확인)
  • 오답 200: 바깥의 YEAR = 2023을 놓친 경우. 분기 1·3에 2024년 행(120, 200)까지 들어가 MAX가 200이 된다(실행 확인). 2024년 행은 바깥 조건을 빠뜨리면 답이 바뀌게 만드는 함정 역할을 한다.
  • 오답 170: < 조건을 무시하고 2023년 전체 MAX를 쓴 경우. 서브쿼리 문제는 마지막에 '비교 기호의 방향'을 한 번 더 확인한다.
  • 복원자 메모: 2024년 두 행의 값과 가운데 서브쿼리의 YEAR = 2023은 원문 확인이 필요하다. 가운데 조건을 빼도, 평균을 6행 전체로 구해도 결과는 130으로 같다(실행 확인).

13. C — 이중 포인터와 함수 포인터 (실행 결과)

#include <stdio.h>

typedef struct Node {
    int x;
    int (*fn)(struct Node **);
} Node;

int incr(Node **pp) {
    Node *n = *pp;
    n->x = n->x + 1;
    return n->x;
}

int fn_cnt(Node **pp) {
    Node *p = *pp;

    int a = p->fn(pp);
    int b = p->fn(pp);

    return b;
}

int main(void) {
    Node a = {11, incr};
    Node *p = &a;
    Node **pp = &p;

    printf("%d\n", fn_cnt(pp));

    return 0;
}

정답과 해설

정답: 13

pp ──> p ──> a {x: 11, fn: incr}
  • *pp는 p, **pp는 구조체 a 자체다. incr 안의 Node *n = *pp;는 n이 '원래 구조체 a를 가리키게' 할 뿐, 복사본을 만들지 않는다.
  • p->fn(pp)는 a.fn, 즉 incr(pp)를 부른다.
호출a.x반환
처음11
첫 번째 p->fn(pp)12a = 12
두 번째 p->fn(pp)13b = 13

return b → '13'.

  • 오답 12: 매번 11에서 시작한다고 본 경우. 포인터로 원본을 고치므로 값이 누적된다.

14. Java — 자식 필드와 super (실행 결과)

public class Main {
    static class Parent {
        int a = 1;

        int meth() {
            return a;
        }
    }

    static class Child extends Parent {
        int a = 1;

        int meth() {
            return a + super.a;
        }
    }

    public static void main(String[] args) {
        Parent obj = new Child();
        System.out.println(obj.meth());
    }
}

정답과 해설

정답: 2

  • '메서드는 실제 객체 기준'(동적 바인딩)이다. 변수 타입은 Parent지만 실제 객체는 Child라서 Child.meth()가 불린다.
  • Child.meth() 안의 a는 Child의 a(1), super.a는 Parent의 a(1) → 1 + 1 = '2'.
  • Child의 meth()에는 @Override가 없지만 이름과 매개변수가 부모와 같으니 오버라이딩이다. @Override는 “오버라이딩이 맞는지 컴파일러가 검사해 달라”는 표시일 뿐 동작을 바꾸지 않는다.
  • 오답 1: 변수 타입(Parent)을 보고 Parent.meth()가 불린다고 본 경우.

Java 바인딩 규칙 세 줄:

무엇기준정해지는 때
오버라이딩된 메서드실제 객체 (@Override 표시가 없어도 같다)실행 시
필드 (obj.a)변수 타입컴파일 시
오버로딩 중 어느 것인자의 선언 타입컴파일 시

그래서 obj.a를 직접 출력했다면 Parent의 a가 나왔을 것이다(여기선 값이 둘 다 1이라 같다).

15. Java — 2차원 배열의 행 공유 (실행 결과)

public class Main {
    public static void main(String[] args) {
        int[][] a = {{0}, {1}, {2}};
        int[][] b = new int[3][];

        for (int i = 0; i < a.length; i++) {
            b[i] = a[i];
        }

        a[1] = new int[]{9};
        b[2][0] = 3;

        System.out.println(a[2][0] + " 그리고 " + b[1][0]);
    }
}

정답과 해설

정답: 3 그리고 1

핵심: Java의 2차원 배열은 “행 배열들의 주소를 담은 배열”이다. a[0], a[1], a[2] 칸에는 값이 아니라 각 행(1차원 배열) 객체의 '주소'가 들어 있다.

① b[i] = a[i] — 주소를 복사한다

a ─┬─ [0] ──> 행X {0} <── [0] ─┬─ b
   ├─ [1] ──> 행Y {1} <── [1] ─┤
   └─ [2] ──> 행Z {2} <── [2] ─┘

a와 b는 서로 다른 배열이지만 '같은 행 객체 세 개'를 가리킨다. “b[1]이 a[1]이라는 칸을 따라간다”가 아니라, 복사하는 '순간' a[1]에 들어 있던 주소(행Y)를 b[1]에 적어 둔 것이다.

② a[1] = new int[]{9} — a의 칸만 갈아끼운다

a[1] ──> 행W {9}    (새로 만든 행)
b[1] ──> 행Y {1}    (그대로)

a[1] 칸에 새 행의 주소를 넣었을 뿐이다. b[1] 칸에는 여전히 행Y의 주소가 들어 있다. 그래서 'b[1][0] = 1'.

③ b[2][0] = 3 — 공유 중인 행 안을 고친다

b[2]가 가리키는 행Z 안의 값을 바꿨다. a[2]도 같은 행Z를 가리키므로 'a[2][0] = 3'.

연산종류다른 쪽에 보이나
a[1] = 새 배열칸에 든 주소를 갈아끼움안 보인다 (b[1]은 옛 행)
b[2][0] = 3가리키는 행 안을 수정보인다 (a[2]도 같은 행)
  • 오답 3 그리고 9: 갈아끼우기도 공유된다고 본 경우. 반대로 코드가 a[1][0] = 9(행 안을 수정)였다면 b[1][0]도 9가 됐을 것이다.
  • 오답 2 그리고 1: 아무것도 공유하지 않는다고 본 경우(깊은 복사처럼).
  • Python의 b = a[:](얕은 복사)나 [[0]*3]*3도 정확히 같은 원리다. 2026-1에 Python 얕은 복사가 처음 나왔는데, 이번엔 같은 원리를 Java로 물었다.

16. 보안 — 용어

다음 설명의 괄호 안에 공통으로 들어갈 보안 용어를 보기에서 고르시오.

공격자가 시스템에 침입한 뒤 '자신의 존재를 숨기면서' 시스템에 대한 접근 권한을 유지하기 위해 사용하는 도구 모음을 ( )이라고 한다. ( )은 백도어, 트로이 목마 등을 포함할 수 있으며, 원격 접근이나 사용 흔적 삭제 등 공격자가 지속적으로 시스템을 이용하는 데 필요한 기능을 제공한다. 또한 탐지하기 어려운 시스템의 깊은 레벨에서 작동하며, 정상적인 시스템 기능을 변조해 자신의 존재와 악성 프로그램의 실행을 숨긴다.

보기: ㄱ. Adware ㄴ. Virus ㄷ. Spyware ㄹ. Keylogger ㅁ. Ransomware ㅂ. Worm ㅅ. Rootkit ㅇ. Trace Route

정답과 해설

정답: ㅅ. Rootkit (루트킷)

  • 단서: “관리자 권한(root) 유지” + “존재를 '숨김'” + “깊은 레벨에서 작동”.
  • 백도어(몰래 다시 들어오는 뒷문)와 트로이 목마(정상 프로그램으로 위장)는 루트킷이 품을 수 있는 것들이다. 루트킷은 이것들을 숨겨 주는 도구다.
보기하는 일
Adware광고를 띄운다
Virus다른 파일에 붙어 감염시킨다 (혼자 퍼지지 못함)
Spyware몰래 정보를 수집한다
Keylogger키 입력을 기록한다
Ransomware파일을 암호화하고 몸값을 요구한다
Worm스스로 복제해 네트워크로 퍼진다
Rootkit침입 흔적과 악성코드를 숨기고 권한을 유지한다 ← 정답
Trace Route악성코드가 아니라 네트워크 경로를 추적하는 명령(tracert, traceroute)

17. Java — 오버로딩과 NullPointerException (실행 결과)

public class Main {
    static String convert(int value) {
        Integer num = value;
        return num.toString();
    }

    static String convert(double value) {
        Double num = null;

        if (value > 1) {
            num = value * 2;
        }

        return num.toString();
    }

    public static void main(String[] args) {
        try {
            System.out.println(convert(1.0));
        } catch (Exception e) {
            System.out.println("error");
        }
    }
}

정답과 해설

정답: error (실행 확인)

단계일어나는 일
convert(1.0)인자 1.0이 double이라 오버로딩 중 convert(double)이 골라진다 (컴파일 때 결정)
Double num = null래퍼 클래스 Double 변수라 null을 담을 수 있다
value > 1double 1.0과 int 1을 비교 → 1.0 > 1은 거짓 (같을 뿐 크지 않다)
num아무것도 대입되지 않아 null 그대로
num.toString()null에 메서드를 부름 → NullPointerException
catch (Exception e)NullPointerException도 Exception의 하위 클래스라 잡힌다 → error 출력

“null”이 출력되는 것 아닌가?

아니다. 두 경우를 구분해야 한다.

코드결과
System.out.println(num) (num이 null)null 출력 — println이 null을 받으면 글자 “null”을 찍는다
String.valueOf(num)"null" — null이면 글자 “null”을 돌려준다
num.toString() (이 문제)예외 발생 — null에는 부를 메서드가 없다. println까지 가지도 못한다

이 문제는 convert 안에서 num.toString()을 '직접' 부르므로, 값을 돌려주기 전에 예외가 난다.

1.0 > 1은 자료형이 달라서 에러 아닌가?

아니다. 숫자끼리 비교할 때 int 1이 double 1.0으로 자동 변환되어 정상 비교된다. 결과가 거짓일 뿐이다. 에러가 난 진짜 이유는 비교가 거짓이라 num이 null로 남았기 때문이다.

  • 변형: convert(2.0)이면 2.0 × 2 = 4.0, convert(1)이면 정수라 convert(int)가 골라져 1이 출력된다(실행 확인). 어느 convert가 불릴지는 14번 표의 “오버로딩은 인자의 선언 타입, 컴파일 시” 규칙 그대로다.

18. 신기술 — 용어

다음 설명에 해당하는 용어를 보기에서 골라 쓰시오.

소프트웨어를 구성하는 오픈소스, 라이브러리 등의 구성 요소와 의존 관계를 기록한 메타데이터 목록이다. 소프트웨어의 구성 정보를 확인하고 취약점을 파악·관리하는 데 활용되며, 미국 연방정부에 소프트웨어를 공급할 때 제공을 요구하는 목록으로 언급된다.

보기: IAM, ZTA, SBOM, Privacy Sandbox, Cyber Resilience, RASP, Data Leakage Prevention, Cyber Kill Chain, Attack Surface

정답과 해설

정답: SBOM (Software Bill of Materials, 소프트웨어 자재 명세서)

  • 제조업의 BOM(자재 명세서)을 소프트웨어에 적용한 것이다. “이 프로그램에 어떤 라이브러리 몇 버전이 들어 있나”의 목록이다.
  • 2020년 SolarWinds 공급망 공격 뒤 2021년 5월 미국 행정명령(EO 14028)이 연방정부에 납품하는 소프트웨어에 SBOM 제공을 요구하기 시작했다. 같은 해 말 Log4j 취약점 사태 때 “우리 서비스에 Log4j가 들어 있나?”를 바로 답하지 못한 곳이 많아 필요성이 더 널리 알려졌다.
  • 표준 형식으로 SPDX, CycloneDX가 있다. 실무로 치면 npm ls나 pip freeze 결과에 버전·라이선스를 붙여 정리한 것이다.
  • 이번 회차에서 유일하게 처음 나온 용어다. 단서는 “구성 요소와 의존 관계의 '목록'” + “'미국 연방정부' 공급 시 요구”.

나머지 보기도 신기술 단골이라 한 줄씩 정리한다.

보기뜻
IAM사용자 신원과 접근 권한 관리
ZTA제로 트러스트 아키텍처 — “아무도 믿지 않고 매번 검증”
Privacy Sandbox서드파티 쿠키 없이 광고를 하려는 구글의 개인정보 보호 기술 묶음
Cyber Resilience공격을 받아도 업무를 이어 가고 빨리 복구하는 능력
RASP실행 중인 애플리케이션 안에서 공격을 탐지·차단하는 자가 보호 기술
Data Leakage Prevention중요 데이터가 밖으로 새는 것을 탐지·차단 (DLP)
Cyber Kill Chain공격을 정찰부터 목표 달성까지 단계로 나눈 모델
Attack Surface공격자가 노릴 수 있는 진입점 전체 (공격 표면)

19. Python — 상속과 리스트 칸 수정 (실행 결과)

class NumberList:
    def __init__(self):
        self.data = [3, 5, 7, 9, 11]

    def change(self, index, value):
        if 0 <= index < len(self.data):
            self.data[index] = value


class Calculator(NumberList):
    def total(self):
        total = sum(self.data)
        return total

    def increase(self):
        for i in range(len(self.data)):
            self.data[i] += 1


calculator = Calculator()
calculator.change(2, 15)
calculator.increase()
print(calculator.total(), end="")

정답과 해설

정답: 48

줄일어나는 일calculator.data
Calculator()Calculator에 __init__이 없으므로 부모 NumberList의 __init__ 실행[3, 5, 7, 9, 11]
change(2, 15)0 ≤ 2 < 5라 조건 통과 → 인덱스 2(세 번째 칸)를 15로 수정[3, 5, 15, 9, 11]
increase()모든 칸에 1씩 더함[4, 6, 16, 10, 12]
total()합계4 + 6 + 16 + 10 + 12 = 48
  • 오답 40: change를 놓친 경우 ([4, 6, 8, 10, 12]).
  • 오답 43: increase를 놓친 경우 (3 + 5 + 15 + 9 + 11).
  • 오답 50: 인덱스를 1부터 세어 두 번째 칸(5)을 15로 바꾼 경우 ([4, 16, 8, 10, 12]). 파이썬 인덱스는 0부터다.
  • end=""는 줄바꿈 없이 출력하라는 뜻이라 답에는 영향이 없다.
  • 부모에 정의된 change와 자식에 정의된 increase가 같은 self.data를 고친다. 메서드가 어느 클래스에 있든 self는 calculator 객체 하나다.

20. Python — 가변 기본 인자 (실행 결과)

def f(x=[1]):
    x.append(x[-1] + 2)
    return x[-1]

print(max(f(), f()) - min(f(), f()))

정답과 해설

정답: -2

핵심: 기본값 [1]은 함수를 정의하는 순간(def 줄이 실행될 때) 딱 한 번 만들어진다. 인자 없이 f()를 부를 때마다 새 [1]을 만드는 게 아니라, 그때 만든 '같은 리스트 하나'를 계속 쓴다. 그래서 append로 늘린 내용이 다음 호출에 남는다.

함수의 인자는 왼쪽부터 계산되므로 호출 순서는 이렇다.

호출x (호출 후)x[-1] + 2반환
max의 첫 f()[1, 3]1 + 23
max의 둘째 f()[1, 3, 5]3 + 25
min의 첫 f()[1, 3, 5, 7]5 + 27
min의 둘째 f()[1, 3, 5, 7, 9]7 + 29

max(3, 5) − min(7, 9) = 5 − 7 = '−2'.

  • 오답 0: 부를 때마다 [1]에서 새로 시작한다고 본 경우 — 매번 3이 나와 3 − 3 = 0.
  • 직접 확인하는 법: 함수 정의 뒤에 print(f.__defaults__)를 찍어 보면 ([1],), f()를 두 번 부른 뒤 다시 찍으면 ([1, 3, 5],)로 기본값 자체가 늘어나 있다(실행 확인).
  • 실무에서는 이 동작이 버그의 원인이 되어서 def f(x=None): 다음에 if x is None: x = [1]처럼 쓴다. 시험은 이 함정을 그대로 낸 것이다.
  • 같은 원리: 기본값이 정수(def f(n=0))처럼 바뀌지 않는 값이면 n += 1은 새 값을 만들 뿐이라 누적되지 않는다. '리스트·딕셔너리처럼 안을 고칠 수 있는 기본값만' 누적된다.

마치며

복원은 아직 진행 중이고, 5번처럼 코드 순서를 두고 의견이 갈리는 문항도 있다. 복원이 바뀌면 이 글도 고친다. 정리하고 나서 가장 크게 남은 숫자는 이것이다. 이론 9문항 중 8문항이 예전 기출과 같은 문제나 개념이었다. 시험 전 이틀 동안 21회차 420문항을 분류하고 공부 순서를 다시 짠 과정은 정보처리기사 실기 2026년 3회 후기에 따로 적었다. 다음 시험을 준비한다면 이론 노트를 처음부터 읽는 대신 무엇부터 해야 할까?

댓글 남기기