24-2
아래 Python 프로그램을 실행한 결과를 적으시오.
def count(text, pat):
hit = 0
for i in range(len(text) - len(pat) + 1):
if text[i:i + len(pat)] == pat:
hit += 1
return hit
word = "xyzxyxxyzyx"
a = count(word, "xy")
b = count(word, "yx")
print(f"xy={a}", f"yx={b}", sep=", ")xy=3, yx=2
[해설]
count는 text를 앞에서부터 pat 길이만큼 잘라(슬라이싱) pat과 같을 때마다 1씩 센다. 겹치는 위치도 모두 센다.
- word = x y z x y x x y z y x (인덱스 0~10)
- "xy": 인덱스 0, 3, 6 → 3번
- "yx": 인덱스 4, 9 → 2번
print는 두 인자를 sep=", "로 이어 찍으므로 xy=3, yx=2가 출력된다.
24-2
다음 설명에 해당하는 암호 알고리즘을 적으시오.
- 안전성과 속도에 한계가 드러난 DES를 대신하기 위해 미국 NIST가 공모를 거쳐 표준으로 채택하였다.
- 대칭 키 방식의 블록 암호로 블록 크기는 128비트이며, 키 길이는 128·192·256비트 중에서 고른다.
AES
[해설]
DES를 대체하려고 NIST가 공모를 거쳐 채택한 대칭 키 블록 암호는 AES(Advanced Encryption Standard)이다. 원래 이름은 Rijndael이다.
블록은 128비트로 고정이다. 키 길이 128·192·256비트에 따라 라운드 수가 10·12·14회로 달라진다.
혼동 주의: DES는 64비트 블록·56비트 키이고, SEED·ARIA는 국내에서 개발한 128비트 블록 암호다.
24-2
[회원]과 [가입신청] 테이블의 구조가 아래와 같다. 각 상황에 맞는 SQL 문이 되도록 빈칸 ①~④에 들어갈 키워드를 적으시오.
| 테이블 | 컬럼 |
|---|---|
| 회원 | 회원번호(PK), 이름, 등급, 지역 |
| 가입신청 | 회원번호(PK), 이름, 지역, 연락처 |
(1) 새 가입신청 한 건을 [가입신청]에 넣는다.
INSERT INTO 가입신청(회원번호, 이름, 지역, 연락처)
( ① ) (7031, '윤서진', '부산', '010-5521');(2) [가입신청]의 행을 조회해 그 결과를 [회원]에 등급 '일반'으로 한꺼번에 넣는다.
INSERT INTO 회원(회원번호, 이름, 등급, 지역)
( ② ) 회원번호, 이름, '일반', 지역 FROM 가입신청;(3) 처리가 끝난 신청 건을 [가입신청]에서 지운다.
DELETE ( ③ ) 가입신청 WHERE 회원번호 = 7031;(4) 지역이 '부산'인 회원의 등급을 '우수'로 바꾼다.
UPDATE 회원 ( ④ ) 등급 = '우수' WHERE 지역 = '부산';① VALUES
② SELECT
③ FROM
④ SET
[해설]
값을 직접 넣는 INSERT는 VALUES 뒤에 괄호로 값을 나열한다.
조회 결과를 통째로 넣을 때는 VALUES 대신 SELECT 문을 이어 쓴다. 이때 SELECT 목록의 개수·순서가 INSERT 컬럼 목록과 맞아야 하며, '일반' 같은 상수도 넣을 수 있다.
- DELETE FROM 테이블 WHERE 조건: 조건에 맞는 행 삭제
- UPDATE 테이블 SET 컬럼 = 값 WHERE 조건: 조건에 맞는 행 수정
DELETE와 UPDATE에서 WHERE를 빠뜨리면 테이블의 모든 행이 대상이 되므로 주의한다.
24-2
다음 설명에 해당하는 결합도를 빈칸에 알맞은 영문 단어로 적으시오.
호출하는 모듈이 플래그 같은 제어용 값을 넘겨, 호출된 모듈 안에서 어떤 처리 흐름을 탈지 결정하게 하는 결합 형태이다.
( ) Coupling
Control
[해설]
제어 신호를 넘겨 상대 모듈의 내부 논리 흐름을 좌우하는 것은 제어 결합도(Control Coupling)이다.
호출하는 쪽이 호출되는 쪽의 내부 처리를 알아야 하므로 정보 은닉이 깨진다. 하위 모듈이 상위 모듈에 제어 신호를 보내 상위의 처리를 좌우하는 경우를 권리 전도 현상이라 한다.
결합도는 약한 순서로 자료 → 스탬프 → 제어 → 외부 → 공통 → 내용이다.
24-2
아래 C 프로그램이 출력하는 값을 적으시오.
#include <stdio.h>
int main(void) {
int m[3][4] = {{2, 4, 6, 8}, {1, 3, 5, 7}, {9, 10, 11, 12}};
int *row[2] = {m[2], m[0]};
printf("%d", row[0][3] + *(row[1] + 1) - **row + *row[1]);
return 0;
}9
[해설]
row는 포인터 배열로, row[0]은 m[2] 행의 시작, row[1]은 m[0] 행의 시작을 가리킨다.
- row[0][3] = m[2][3] = 12
- *(row[1] + 1) = m[0][1] = 4
- **row = *row[0] = m[2][0] = 9
- *row[1] = m[0][0] = 2
12 + 4 − 9 + 2 = 9다. **row는 row[0][0]과 같다는 점이 핵심이다.
24-2
아래 표는 라우터 A~F 사이의 연결과 각 링크에 매겨진 비용이다. RIP로 경로를 정할 때, 라우터 A에서 F까지 가는 경로를 순서대로 적으시오.
| 링크 | 비용 |
|---|---|
| A — B | 2 |
| A — D | 1 |
| B — D | 2 |
| C — D | 2 |
| C — E | 1 |
| C — F | 5 |
| E — F | 2 |
A → ( ) → … → F
A → D → C → F
[해설]
RIP는 거리 벡터 라우팅 프로토콜이다. 링크 비용이 아니라 홉 수(거쳐 가는 링크 수)가 가장 적은 경로를 고른다.
- A → D → C → F는 3홉으로 가장 짧다.
- A → D → C → E → F는 비용 합이 6으로 더 작지만 4홉이다.
- A → B → D → C → F는 4홉이다.
혼동 주의: 비용 합으로 고르는 OSPF였다면 A → D → C → E → F가 선택된다. RIP의 최대 홉 수는 15이고, 16홉은 도달 불가로 본다.
24-2
아래 Java 프로그램을 실행하면 출력되는 내용을 적으시오.
interface Picker {
int pick(int[] v, boolean hit);
}
class ThreePicker implements Picker {
public int pick(int[] v, boolean hit) {
int s = 0;
for (int n : v) {
boolean three = (n % 3 == 0);
if (three == hit)
s += n;
}
return s;
}
}
public class Main {
public static void main(String[] args) {
int[] v = {2, 3, 5, 6, 9, 10, 12, 14};
Picker p = new ThreePicker();
System.out.print(p.pick(v, true) + " / " + p.pick(v, false));
}
}30 / 31
[해설]
인터페이스 Picker를 구현한 ThreePicker의 pick은, 원소가 3의 배수인지(three)가 hit와 같을 때만 더한다.
- pick(v, true): 3의 배수 3, 6, 9, 12의 합 = 30
- pick(v, false): 나머지 2, 5, 10, 14의 합 = 31
인터페이스 타입 변수 p로 호출해도 실제 객체의 메서드가 실행된다. 출력은 30 / 31이다.
24-2
빈칸에 공통으로 들어갈 응집도의 종류를 적으시오.
- ( ) 응집도는 모듈 안의 한 활동이 만들어 낸 출력 자료를 다음 활동이 입력으로 받아 쓰는 형태이다.
- ( ) 응집도에서는 앞 단계의 결과가 뒤 단계로 이어지므로 구성 요소 사이에 데이터 의존이 생기고, 요소들이 논리적으로 긴밀하게 묶인다.
순차적 응집도(Sequential Cohesion)
[해설]
앞 기능의 출력이 다음 기능의 입력이 되는 것은 순차적 응집도(Sequential Cohesion)이다.
- 교환적(통신적): 같은 입력이나 출력을 쓰는 기능들이 모임
- 절차적: 정해진 순서대로 수행되지만 데이터를 주고받지는 않음
- 기능적: 모든 요소가 단 하나의 기능을 위해 존재함
응집도는 강한 순서로 기능적 → 순차적 → 교환적 → 절차적 → 시간적 → 논리적 → 우연적이며, 강할수록 좋다.
24-2
아래 C 프로그램의 출력값을 적으시오.
#include <stdio.h>
struct link {
int v;
struct link *nx;
};
int main(void) {
struct link x = {3, NULL};
struct link y = {6, NULL};
struct link z = {9, NULL};
struct link *head = &z;
z.nx = &x;
x.nx = &y;
printf("%d", head->nx->nx->v * head->nx->v);
return 0;
}18
[해설]
구조체 link는 자기와 같은 타입을 가리키는 포인터 nx를 가진 자기 참조 구조체다.
- 연결 순서: head → z(9) → x(3) → y(6)
- head->nx->v = x.v = 3
- head->nx->nx->v = y.v = 6
6 × 3 = 18이 출력된다. 선언 순서(x, y, z)가 아니라 nx로 이은 순서를 따라가야 한다.
24-2
아래 [도서] 릴레이션에서 카디널리티(Cardinality)와 차수(Degree)를 각각 구하시오.
| 도서코드 | 제목 | 저자 | 출간연도 |
|---|---|---|---|
| B-301 | 바다의 문법 | 류하준 | 2019 |
| B-302 | 작은 정원 | 정다솜 | 2021 |
| B-305 | 겨울 기차 | 류하준 | 2020 |
| B-308 | 숫자의 숲 | 남궁선 | 2023 |
| B-311 | 오후의 지도 | 배시우 | 2022 |
(1) 카디널리티
(2) 차수
(1) 5
(2) 4
[해설]
카디널리티는 튜플(행)의 개수로, 제목 행을 뺀 데이터 행이 5개이므로 5다.
차수는 속성(열)의 개수로, 도서코드·제목·저자·출간연도 4개이므로 4다.
제목 행(스키마)은 튜플에 포함하지 않는다. 저자 값이 겹치는 행이 있어도 튜플은 각각 센다.
24-2
아래 C 프로그램이 출력하는 정수를 적으시오.
#include <stdio.h>
void exchange(int x, int y) {
int keep = x;
x = y;
y = keep;
}
int main(void) {
int x = 4, y = 9;
exchange(x, y);
switch (y) {
case 4:
x += 10;
case 9:
x *= 3;
case 12:
x -= 2;
break;
default:
x = 0;
}
printf("%d", x + y);
return 0;
}19
[해설]
exchange는 값을 복사받아(값에 의한 호출) 자기 지역 변수만 바꾸므로 main의 x, y는 4, 9 그대로다.
- switch(y)에서 y = 9 → case 9로 진입, x = 4 × 3 = 12
- break가 없어 case 12로 이어짐(fall-through), x = 12 − 2 = 10
- break를 만나 default는 실행하지 않음
x + y = 10 + 9 = 19다.
24-2
다음 설명에 해당하는 GoF 디자인 패턴의 이름을 적으시오.
- 배열·리스트 같은 집합 객체가 속을 어떻게 구현했는지 드러내지 않은 채, 담긴 원소를 하나씩 차례로 꺼내 볼 수 있게 한다.
- 순회하는 동안 지금 위치를 기억하는 방식이 커서와 닮아 커서(Cursor) 패턴이라고도 부른다.
Iterator(반복자)
[해설]
내부 구조를 숨긴 채 원소를 순차 접근하게 하는 행위 패턴은 Iterator(반복자) 패턴이다.
보통 hasNext()로 다음 원소가 있는지 묻고 next()로 꺼낸다. Java의 for-each 문도 이 패턴을 이용한다.
- Composite: 부분-전체를 트리로 구성해 같은 방식으로 다룸
- Visitor: 자료구조는 두고 처리 기능을 따로 분리
- Observer: 상태 변화를 여러 객체에 자동 통지
24-2
아래 Java 프로그램이 출력하는 문자열을 적으시오.
public class Main {
static String keep(String s, int i, boolean[] used) {
if (i == s.length()) return "";
char c = s.charAt(i);
if (used[c]) return keep(s, i + 1, used);
used[c] = true;
String rest = keep(s, i + 1, used);
return rest + c;
}
public static void main(String[] args) {
boolean[] used = new boolean[128];
System.out.println(keep("mississippi", 0, used));
}
}psim
[해설]
keep은 앞에서부터 문자를 보며, 처음 나온 문자만 used에 표시하고 이미 나온 문자는 건너뛴다.
- "mississippi"에서 처음 나오는 문자: m(0), i(1), s(2), p(8)
- 각 호출은 rest + c, 즉 뒤쪽 결과 뒤에 자기 문자를 붙여 돌려준다.
- p → "p", s → "ps", i → "psi", m → "psim"
재귀가 되돌아오면서 순서가 뒤집히므로 출력은 psim이다.
24-2
다음 설명이 가리키는 데이터 모델링 기법의 이름을 적으시오.
- 이미 정규화를 마친 모델에서, 조회 성능을 높이고 운영을 단순하게 만들 목적으로 테이블이나 컬럼을 일부러 중복시키거나 합치고 쪼갠다.
- 정규화 규칙을 의도적으로 완화하지만 정규화를 부정하는 것은 아니며, 정규화된 설계를 기본으로 두고 필요한 곳에만 골라 적용한다.
반정규화(De-Normalization)
[해설]
정규화된 모델을 성능을 위해 의도적으로 되돌리는 기법은 반정규화(De-Normalization)이다. 비정규화·역정규화라고도 한다.
- 테이블 병합·분할: 자주 함께 조회되는 테이블을 합치거나, 큰 테이블을 수평·수직으로 나눈다.
- 중복 테이블 추가: 집계·이력용 테이블을 따로 둔다.
- 중복 컬럼 추가: 조인을 줄이려고 다른 테이블의 컬럼이나 파생 값을 복사해 둔다.
조회는 빨라지지만 데이터 중복으로 일관성·무결성이 흔들릴 수 있으므로, 성능 문제가 확인된 곳에만 적용한다.
24-2
아래 C 프로그램의 실행 결과를 적으시오.
#include <stdio.h>
void put(char *to, const char *from) {
for (; *from != '\0'; from++, to++)
*to = *from;
*to = '\0';
}
int main(void) {
char buf[32] = "keyboard";
int acc = 0;
put(buf, "moon");
for (int i = 0; buf[i] != '\0'; i++)
acc += i * 2;
printf("%d %c", acc, buf[5]);
return 0;
}12 a
[해설]
put은 포인터를 한 칸씩 옮기며 "moon"을 buf 앞부분에 덮어쓰고, 끝에 '\0'을 넣는다.
- 복사 전 buf: k e y b o a r d
- 복사 후 buf: m o o n \0 a r d (인덱스 4가 널 문자)
for는 널 문자 전까지인 i = 0~3만 돌아 acc = 0 + 2 + 4 + 6 = 12다. 널 뒤의 buf[5]에는 원래 문자 'a'가 그대로 남아 있어 출력은 12 a다.
24-2
다음 설명에 해당하는 보안 프로토콜을 적으시오.
- 인터넷 같은 공용망 위에 가상의 사설망(VPN)을 구성할 때 널리 쓰인다.
- 네트워크 계층(3계층)에서 동작하며, 무결성과 출발지 인증을 제공하는 AH 헤더와 데이터를 암호화해 기밀성을 지키는 ESP를 사용한다.
IPSec
[해설]
3계층에서 AH·ESP로 IP 패킷을 보호하는 VPN 프로토콜은 IPSec(IP Security)이다.
- AH(Authentication Header): 무결성·인증 제공, 암호화는 하지 않음
- ESP(Encapsulating Security Payload): 암호화로 기밀성 제공, 인증도 선택 가능
- IKE(Internet Key Exchange): 통신 양측의 키를 교환·관리
동작 모드는 페이로드만 보호하는 전송 모드와 IP 패킷 전체를 감싸 보호하는 터널 모드로 나뉜다.
24-2
아래 Java 프로그램이 콘솔에 찍는 문자열을 적으시오.
public class Main {
static void same(int[] p, int[] q) {
System.out.print(p == q ? "Y" : "-");
}
public static void main(String[] args) {
int[] x = {5, 7, 9};
int[] y = {5, 7, 9};
int[] z = x;
same(x, y);
same(x, z);
same(y, new int[]{5, 7, 9});
z[0] = 8;
System.out.print(x[0]);
}
}-Y-8
[해설]
배열 변수에 쓰는 == 는 원소 값이 아니라 참조(주소)가 같은지를 비교한다.
- same(x, y)는 내용은 같아도 따로 만든 두 객체라 "-"를 찍는다.
- same(x, z)는 z = x로 같은 객체를 가리켜 "Y"를 찍는다.
- same(y, new int[]{5, 7, 9})는 새로 만든 객체와 비교하므로 "-"를 찍는다.
- z[0] = 8은 같은 배열을 가리키는 x[0]도 바꾸므로 8이 찍힌다.
최종 출력은 -Y-8이다. 원소 값끼리 비교하려면 Arrays.equals(x, y)를 쓴다.
24-2
패킷 교환 방식의 두 가지 형태에 대한 설명이다. 빈칸 ①, ②에 알맞은 방식을 적으시오.
- ( ① ): 데이터를 보내기 전에 송신 측과 수신 측 사이에 논리적 경로를 먼저 정해 두고, 모든 패킷이 그 경로를 따라 순서대로 전달되는 연결형 방식
- ( ② ): 경로를 미리 정하지 않고, 목적지 정보를 담은 헤더를 붙인 패킷을 하나하나 독립적으로 보내는 비연결형 방식으로, 도착 순서가 바뀔 수 있다
① 가상 회선(Virtual Circuit) 방식
② 데이터그램(Datagram) 방식
[해설]
패킷 교환은 경로를 미리 정하는지에 따라 가상 회선 방식과 데이터그램 방식으로 나뉜다.
- 가상 회선(Virtual Circuit) 방식은 논리 경로를 먼저 정하는 연결형이라 순서가 보장되지만 연결 설정 부담이 있다.
- 데이터그램(Datagram) 방식은 패킷마다 경로를 따로 정하는 비연결형이라 경로 장애에 유연하지만 수신 측이 순서를 다시 맞춰야 한다.
외우는 요령: 연결형은 가상 회선, 비연결형은 데이터그램으로 짝지어 기억한다.
24-2
아래 Python 프로그램을 실행했을 때 출력값을 적으시오.
def piece(s, n):
parts = s.split("R")
return parts[n]
word = "PROGRAMMER"
print(piece(word, 2))AMME
[해설]
split("R")은 문자 R을 기준으로 문자열을 나눠 리스트로 돌려주며, 구분자 R 자체는 빠진다.
- "PROGRAMMER" → ['P', 'OG', 'AMME', '']
- 끝이 R로 끝나 마지막 원소는 빈 문자열이다.
parts[2]는 세 번째 원소이므로 AMME가 출력된다.
24-2
네 프로세스가 아래와 같이 도착해 CPU 사용을 요청한다. SRT(Shortest Remaining Time) 스케줄링을 적용했을 때 평균 대기시간을 구하시오.
| 구분 | P1 | P2 | P3 | P4 |
|---|---|---|---|---|
| 도착 시간 | 0 | 1 | 2 | 3 |
| 실행 시간 | 8 | 4 | 9 | 5 |
6.5
[해설]
SRT는 새 프로세스가 도착할 때마다 남은 실행 시간이 가장 짧은 프로세스에 CPU를 넘기는 선점형 방식이다.
- 0~1: P1 실행(남은 7)
- 1~5: P2 도착, 4 < 7이라 선점해 끝까지 실행
- 5~10: 남은 시간 P1 7, P3 9, P4 5 → P4 실행
- 10~17: P1, 17~26: P3
대기시간 = 종료 − 도착 − 실행이므로 P1 = 17−0−8 = 9, P2 = 0, P3 = 26−2−9 = 15, P4 = 10−3−5 = 2다.
평균은 로 6.5다.