23-3
아래 C 프로그램의 출력값을 적으시오.
#include <stdio.h>
int g(int n) {
if (n <= 1)
return n;
return g(n - 1) + g(n - 4);
}
int main(void) {
printf("%d", g(8));
return 0;
}-6
[해설]
g는 n이 1 이하이면 n 자신을 그대로 돌려주는 재귀 함수다. 그래서 g(1)=1, g(0)=0, g(-1)=-1, g(-2)=-2처럼 음수도 값 그대로 반환된다.
작은 값부터 차례로 쌓아 올리면 다음과 같다.
g(2) = g(1) + g(-2) = 1 − 2 = −1
g(3) = g(2) + g(-1) = −1 − 1 = −2
g(4) = g(3) + g(0) = −2 + 0 = −2
g(5) = g(4) + g(1) = −2 + 1 = −1
g(6) = g(5) + g(2) = −1 − 1 = −2
g(7) = g(6) + g(3) = −2 − 2 = −4
g(8) = g(7) + g(4) = −4 − 2 = −6
혼동 주의: 종료 조건이 0이나 1을 반환하는 게 아니라 n을 반환하므로, g(-2)를 0으로 계산하면 틀린다.
23-3
관계대수 연산자의 기호를 적으시오.
- Select(선택): ( ① )
- Project(추출): ( ② )
- Join(조인): ( ③ )
- Division(나누기): ( ④ )
① σ
② π
③ ⋈
④ ÷
[해설]
관계대수의 기본 연산자는 그리스 문자와 집합 기호로 나타낸다.
- Select는 σ(시그마)로, 조건에 맞는 튜플(행)을 고르며 수평적 부분집합을 만든다.
- Project는 π(파이)로, 지정한 속성(열)만 뽑으며 수직적 부분집합을 만든다.
- Join은 ⋈로, 공통 속성을 기준으로 두 릴레이션을 하나로 합친다.
- Division은 ÷로, 나누는 릴레이션의 모든 값과 연관된 튜플만 남긴다.
Select는 s에 해당하는 σ, Project는 p에 해당하는 π로 짝지어 외우면 둘을 헷갈리지 않는다.
23-3
테이블 [R1]과 [R2]가 아래와 같을 때, 물음에 답하시오.
(1) 주어진 SQL 문의 실행 결과를 표로 나타낸 것이다. 빈칸 ①~⑤에 알맞은 값을 적으시오.
(2) 위 SQL 문에서 두 결과를 합칠 때 중복 행도 제거하지 않고 모두 남기려면 UNION 자리에 어떤 키워드를 써야 하는지 적으시오.
[R1]
| K | V |
|---|---|
| 6 | p |
| 3 | q |
| 8 | r |
| 3 | s |
[R2]
| K | V |
|---|---|
| 8 | q |
| 5 | p |
| 6 | s |
| 3 | r |
SELECT K FROM R1
UNION
SELECT K FROM R2
ORDER BY K DESC;[실행 결과]
| ( ① ) |
|---|
| ( ② ) |
| ( ③ ) |
| ( ④ ) |
| ( ⑤ ) |
(1)
① K
② 8
③ 6
④ 5
⑤ 3
(2) UNION ALL
[해설]
UNION은 두 SELECT 결과를 합치면서 중복 행을 제거하고, 중복까지 모두 남기려면 UNION ALL을 쓴다.
- 결과 표의 머리글은 조회한 열 이름인 K다.
- R1의 K(6, 3, 8, 3)와 R2의 K(8, 5, 6, 3)를 합쳐 중복을 없애면 3, 5, 6, 8 네 값이 남는다.
- ORDER BY K DESC로 내림차순 정렬하므로 8, 6, 5, 3 순으로 출력된다.
V 열은 SELECT 대상이 아니므로 중복 판단에 영향을 주지 않는다.
23-3
다음 설명에 해당하는 네트워크 기술을 영문 약어로 적으시오.
- 공유기나 방화벽이 내부망의 사설 IP 주소를 외부로 나갈 때 공인 IP 주소로 바꾸고, 돌아오는 응답은 다시 원래 사설 주소로 되돌려 준다.
- 공인 IPv4 주소 하나를 여러 내부 호스트가 나눠 쓸 수 있어 주소 고갈 문제를 덜어 준다.
- 외부에서는 내부 호스트의 실제 주소가 보이지 않아 보안상 이점도 있다.
NAT
[해설]
사설 IP와 공인 IP를 서로 바꿔 주는 기술은 NAT(Network Address Translation, 네트워크 주소 변환)다.
내부 호스트 여러 대가 공인 주소 하나를 함께 쓰므로 IPv4 주소 고갈을 덜어 준다. 외부에는 내부의 실제 주소가 드러나지 않아 보안에도 도움이 된다.
혼동 주의: 포트 번호까지 함께 바꿔 공인 IP 하나를 나눠 쓰는 방식은 PAT(NAPT)라고 하며, NAT의 한 형태다.
23-3
다음 설명에 해당하는 전송 기술을 영문 약어로 적으시오.
- 모든 정보를 헤더 5바이트와 데이터 48바이트, 합계 53바이트의 고정 길이 셀(Cell)로 잘라 보낸다.
- 타임 슬롯을 고정 배정하지 않고, 보낼 데이터가 있는 채널에만 셀을 할당하는 비동기식 시분할 다중화를 쓴다.
- 광대역 종합정보통신망(B-ISDN)의 핵심 전송·교환 방식으로 개발되었다.
ATM
[해설]
53바이트 고정 길이 셀과 비동기식 시분할 다중화를 쓰는 전송 기술은 ATM(Asynchronous Transfer Mode, 비동기 전송 모드)이다. B-ISDN의 핵심 전송·교환 방식으로 개발되었다.
셀 길이가 일정해 하드웨어로 빠르게 교환할 수 있고, 음성·영상·데이터를 한 망에 함께 실을 수 있다.
혼동 주의: 여기서 "비동기"는 각 채널이 정해진 타임 슬롯을 차지하지 않는다는 다중화 방식의 뜻이다.
23-3
아래 Java 프로그램을 컴파일하면 오류가 한 곳에서 발생한다. 오류가 나는 행의 번호를 적으시오.
1 | class Counter {
2 | private int count;
3 | public Counter(int start) {
4 | count = start;
5 | }
6 | public void up() {
7 | count++;
8 | }
9 | public static int peek() {
10 | return count;
11 | }
12 | }
13 |
14 | public class Main {
15 | public static void main(String[] args) {
16 | Counter c = new Counter(3);
17 | c.up();
18 | }
19 | }10
[해설]
10행의 static 메서드 peek()가 인스턴스 변수 count를 참조해서 컴파일 오류가 난다.
static 메서드는 객체 없이 클래스 이름으로 호출되므로, 어느 객체의 count인지 정할 수 없다. javac는 "non-static variable count cannot be referenced from a static context"를 낸다.
peek()에서 static을 빼거나 count를 static 필드로 바꾸면 해결된다. 7행의 count++는 인스턴스 메서드 안이므로 문제없다.
23-3
접근통제 정책에 관한 설명이다. 빈칸 ①~③에 알맞은 정책을 영문 약어로 적으시오.
- ( ① ): 신분 기반 정책이다. 객체의 소유자가 주체나 그 주체가 속한 그룹의 신원을 보고 접근 허용 여부를 스스로 정한다.
- ( ② ): 규칙 기반 정책이다. 객체에 매겨진 보안 등급과 주체가 가진 비밀 취급 인가 수준을 시스템이 비교해 접근을 강제로 허용·차단한다.
- ( ③ ): 중앙 관리자가 조직 안의 직무(역할)별로 권한을 묶어 두고, 사용자에게는 역할을 배정하는 방식으로 접근을 제한한다.
① DAC
② MAC
③ RBAC
[해설]
소유자가 신분을 기준으로 권한을 주는 것은 DAC(Discretionary Access Control, 임의적 접근통제)다. 구현이 쉽고 유연하지만 권한이 쉽게 퍼질 수 있다.
보안 등급과 인가 수준을 시스템이 비교하는 것은 MAC(Mandatory Access Control, 강제적 접근통제)다. 정책이 고정적이며 군사·정부 시스템에 주로 쓰인다.
역할 단위로 권한을 관리하는 것은 RBAC(Role-Based Access Control, 역할 기반 접근통제)다. 인사 이동 시 역할만 바꾸면 되어 관리가 쉽다.
23-3
아래 Python 프로그램에 한 줄로 "2023 exam pass"를 입력했더니 [실행 결과]처럼 출력되었다. 빈칸에 들어갈 메서드 이름을 적으시오.
year, kind, res = input().______()
print(res)
print(kind)
print(year)[실행 결과]
pass
exam
2023split
[해설]
입력 한 줄을 공백 기준으로 나눠 리스트로 만드는 메서드는 split이다.
input()은 "2023 exam pass"를 문자열 하나로 받고, split()이 이를 ['2023', 'exam', 'pass']로 쪼갠다. 원소가 셋이라 세 변수에 차례로 언패킹된다.
print는 호출마다 줄을 바꾸므로 res, kind, year가 한 줄씩 찍힌다. 인자 없는 split()은 연속된 공백도 하나로 본다.
23-3
아래 표는 클라우드 서비스 유형별로 각 계층을 누가 관리하는지 나타낸 것이다(기업 = 이용 기업이 직접 관리, 제공자 = 클라우드 사업자가 제공). 빈칸 ①~③에 알맞은 유형을 [보기]에서 골라 적으시오.
| 계층 | 온프레미스 | ( ① ) | ( ② ) | ( ③ ) |
|---|---|---|---|---|
| 애플리케이션 | 기업 | 기업 | 기업 | 제공자 |
| 데이터 | 기업 | 기업 | 기업 | 제공자 |
| 런타임 | 기업 | 기업 | 제공자 | 제공자 |
| 미들웨어 | 기업 | 기업 | 제공자 | 제공자 |
| 운영체제 | 기업 | 기업 | 제공자 | 제공자 |
| 가상화 | 기업 | 제공자 | 제공자 | 제공자 |
| 서버 | 기업 | 제공자 | 제공자 | 제공자 |
| 스토리지 | 기업 | 제공자 | 제공자 | 제공자 |
| 네트워크 | 기업 | 제공자 | 제공자 | 제공자 |
- ( ① ): 서버·스토리지·네트워크 같은 기반 자원을 빌려주고, 운영체제부터 위는 이용자가 올린다.
- ( ② ): 인프라 구축·관리 부담 없이 애플리케이션을 개발·실행·배포할 수 있는 플랫폼 환경을 제공한다.
- ( ③ ): 완성된 소프트웨어와 그 데이터를 서비스 형태로 제공해, 이용자는 접속해서 쓰기만 한다.
[보기] IaaS, PaaS, SaaS
① IaaS
② PaaS
③ SaaS
[해설]
클라우드 유형은 제공자가 어느 계층까지 관리해 주느냐로 구분한다.
- IaaS — 가상화·서버·스토리지·네트워크까지만 제공하고 운영체제부터는 이용 기업이 관리한다.
- PaaS — 운영체제·미들웨어·런타임까지 제공해 이용자는 애플리케이션과 데이터만 다룬다.
- SaaS — 애플리케이션과 데이터까지 모든 계층을 제공해 이용자는 접속해서 쓰기만 한다.
표에서 "제공자" 칸이 오른쪽으로 갈수록 늘어나므로 IaaS → PaaS → SaaS 순으로 이용자의 관리 범위가 줄어든다.
23-3
다음은 온라인 판매 시스템의 설계 모델 일부를 말로 옮긴 것이다. 이 UML 다이어그램의 명칭을 적으시오.
- 이름표 탭이 달린 폴더 모양의 요소 세 개가 있다: [주문], [할인정책], [상품목록].
- [주문]에서 [할인정책]으로 점선 화살표가 그어져 있다(의존).
- [주문]에서 [상품목록]으로 점선 화살표가 그어져 있고, 화살표 위에 «import» 스테레오타입이 붙어 있다.
- 각 요소는 관련된 클래스들을 하나로 묶은 단위이며, 그림은 이 묶음들 사이의 의존 관계만 보여 준다.
패키지 다이어그램(Package Diagram)
[해설]
여러 클래스를 묶은 폴더 모양 요소와 그 사이의 «import»·의존 관계를 그린 것은 패키지 다이어그램(Package Diagram)이다.
패키지 다이어그램은 UML의 구조 다이어그램에 속하며, 시스템을 모듈 단위로 나누고 의존 방향을 점검할 때 쓴다.
- 클래스 다이어그램: 클래스의 속성·연산과 클래스 간 관계
- 컴포넌트 다이어그램: 실행 가능한 구성요소와 인터페이스
- 배치 다이어그램: 노드(하드웨어)와 산출물의 물리적 배치
23-3
아래 Java 프로그램을 실행하면 출력되는 문자열을 적으시오.
class Machine {
void run() {
System.out.print("P");
stop();
}
void stop() {
System.out.print("Q");
halt();
}
void halt() {
System.out.print("R");
}
}
class Robot extends Machine {
void run() {
super.stop();
System.out.print("S");
this.halt();
}
void halt() {
System.out.print("T");
}
}
public class Main {
public static void main(String[] args) {
Machine m = new Robot();
m.halt();
m.run();
}
}TQTST
[해설]
변수 m의 선언 타입은 Machine이지만 실제 객체는 Robot이므로, 오버라이딩된 메서드는 Robot 쪽이 호출된다.
- m.halt(): Robot.halt() → "T"
- m.run(): Robot.run() 실행 → super.stop()으로 Machine.stop()의 "Q"
- Machine.stop() 안의 halt()도 동적 바인딩으로 Robot.halt() → "T"
- 이어서 "S", this.halt()로 다시 "T"
따라서 출력은 TQTST다. super로 부모 메서드를 불러도, 그 안에서 호출하는 다른 메서드는 여전히 자식의 재정의본이 실행된다.
23-3
C 언어에서 구조체를 가리키는 포인터 변수로 그 구조체의 멤버에 곧바로 접근할 때 쓰는 연산자 기호를 적으시오. (예: 포인터 sp로 멤버 age에 접근)
->
[해설]
구조체 포인터로 멤버에 접근하는 연산자는 화살표 연산자 ->다. sp->age처럼 쓴다.
sp->age는 (*sp).age와 같은 뜻이다. 역참조 *보다 멤버 연산자 .의 우선순위가 높아 괄호가 꼭 필요하므로, 이를 줄여 쓴 것이 ->다.
구조체 변수 자체로 접근할 때는 점(.) 연산자를 쓴다.
23-3
아래 Java 프로그램을 실행했을 때 출력값을 적으시오.
public class Main {
static int mul(int n) {
if (n <= 1) {
return 1;
}
return n * mul(n - 1);
}
public static void main(String[] args) {
int total = mul(5) + mul(3);
System.out.println(total);
}
}126
[해설]
mul은 n이 1 이하가 될 때까지 자기 자신을 호출하는 재귀 팩토리얼이다.
- mul(5) = 5×4×3×2×1 = 120
- mul(3) = 3×2×1 = 6
두 값을 더한 126이 출력된다. 종료 조건(n <= 1)이 없으면 호출이 끝없이 쌓여 StackOverflowError가 난다.
23-3
[학생] 테이블의 기본키는 학번이고, [대출] 테이블의 학번은 [학생]의 학번을 참조하는 외래키다. 아래와 같이 데이터가 들어 있을 때 위반된 무결성 제약조건을 적으시오.
[학생]
| 학번 | 이름 |
|---|---|
| S11 | 강서윤 |
| S12 | 류지호 |
| S14 | 남궁현 |
[대출]
| 학번 | 도서 | 권수 |
|---|---|---|
| S12 | 자료구조 | 2 |
| S13 | 운영체제 | 1 |
| S12 | 네트워크 | 3 |
( ) 무결성 제약조건
참조
[해설]
[대출]의 학번 S13은 [학생]에 없는 값을 가리키므로 참조 무결성이 깨졌다.
참조 무결성은 외래키 값이 NULL이거나 참조되는 테이블의 기본키 값 중 하나여야 한다는 규칙이다.
기본키의 NOT NULL·유일성은 개체 무결성, 값의 형식·범위는 도메인 무결성에 해당한다.
23-3
리눅스에서 파일 report.log의 권한을 아래 조건대로 바꾸려 한다. 빈칸 ①에는 명령어를, ②에는 권한을 8진수로 적으시오.
- 소유자(user): 읽기, 쓰기, 실행
- 그룹(group): 읽기, 실행
- 그 밖의 사용자(other): 실행
( ① ) ( ② ) report.log
① chmod
② 751
[해설]
파일 권한을 바꾸는 명령어는 chmod(change mode)다.
8진수 표기에서 읽기(r)=4, 쓰기(w)=2, 실행(x)=1을 더해 한 자리씩 만든다.
- 소유자 rwx: 4+2+1 = 7
- 그룹 r-x: 4+1 = 5
- 기타 --x: 1
순서대로 이어 붙이면 751이다. 소유자를 바꾸는 chown, 그룹을 바꾸는 chgrp와 헷갈리지 않도록 한다.
23-3
아래 C 프로그램이 출력하는 내용을 적으시오.
#include <stdio.h>
int main(void) {
const char *word = "DRAGON";
const char *q = word + 1;
printf("%s\n", word);
printf("%s\n", q + 2);
printf("%c\n", q[-1]);
printf("%c\n", *(q + 3));
printf("%c\n", *q - 1);
return 0;
}DRAGON
GON
D
O
Q
[해설]
word는 "DRAGON"의 0번 글자를, q는 word + 1이므로 1번 글자 'R'을 가리킨다. 인덱스는 D=0, R=1, A=2, G=3, O=4, N=5다.
- %s와 word: 처음부터 널 문자까지 → DRAGON
- %s와 q + 2: 1+2=3번 칸부터 → GON
- q[-1]: 1−1=0번 문자 → D
- *(q + 3): 1+3=4번 문자 → O
- *q - 1: 역참조가 먼저라 'R'(82)에서 1을 뺀 81 → Q
포인터 기준이 word가 아니라 q라는 점, 그리고 *(q + 3)은 주소를 옮긴 뒤 읽고 *q - 1은 읽은 문자 코드를 계산한다는 차이가 핵심이다.
23-3
다음 설명에 해당하는 기술을 영문 명칭으로 적으시오.
- 사용자가 자신의 아이디·비밀번호를 넘겨주지 않고도, 제3의 서비스가 자신의 정보나 기능 일부에 접근하도록 허락할 수 있게 해 주는 개방형 권한 위임 표준이다.
- "구글 계정으로 계속하기", "카카오로 시작하기"처럼 외부 계정으로 가입·로그인할 때 쓰이며, 인증이 끝나면 비밀번호 대신 접근 토큰(Access Token)이 발급된다.
OAuth
[해설]
비밀번호 대신 토큰으로 접근 권한을 넘겨주는 개방형 표준은 OAuth(Open Authorization)다.
- 권한 위임: 사용자가 동의하면 인가 서버가 접근 토큰(Access Token)을 발급한다.
- 제3의 서비스는 비밀번호를 모른 채 그 토큰으로 허락된 범위(Scope)의 자원만 쓴다.
혼동 주의: OAuth는 본래 인가(권한 위임) 규약이고, 로그인용 신원 확인(인증)은 그 위에 얹은 OpenID Connect가 맡는다.
23-3
아래 C 프로그램의 실행 결과를 적으시오.
#include <stdio.h>
int divisor_sum(int x) {
int s = 0;
for (int d = 1; d < x; d++)
if (x % d == 0)
s += d;
return s;
}
int main(void) {
int total = 0, cnt = 0;
for (int v = 500; v >= 2; v--) {
if (divisor_sum(v) == v) {
total += v;
cnt++;
}
}
printf("%d %d", cnt, total);
return 0;
}3 530
[해설]
divisor_sum은 자기 자신을 뺀 약수(진약수)의 합을 돌려주므로, main은 진약수의 합이 자신과 같은 완전수를 500에서 2까지 찾는다.
- 6 = 1+2+3
- 28 = 1+2+4+7+14
- 496 = 1+2+4+8+16+31+62+124+248
500 이하 완전수는 이 셋뿐이고, 거꾸로 세어도 개수와 합은 같다.
cnt = 3, total = 6+28+496 = 530
출력 = 3 530
23-3
다음 물음에 해당하는 테스트 기법을 [보기]에서 골라 각각 기호로 적으시오.
(1) 아래 설명에 해당하는 기법
- 입력 조건을 같은 결과를 낼 것으로 예상되는 값들의 묶음(유효 그룹·무효 그룹)으로 나눈다.
- 각 묶음에서 대표값을 하나씩 뽑아 테스트 케이스로 삼고, 미리 정한 기대 결과와 실제 결과가 일치하는지 확인한다.
(2) 점수(0~100점)가 60점 이상이면 "합격", 미만이면 "불합격"을 출력하는 프로그램을 아래 데이터로 시험할 때 적용한 기법
| 입력값 | -1 | 0 | 59 | 60 | 100 | 101 |
|---|---|---|---|---|---|---|
| 기대 결과 | 오류 | 불합격 | 불합격 | 합격 | 합격 | 오류 |
[보기] ㉠ 결정 테이블 ㉡ 경계값 분석 ㉢ 동등 분석 ㉣ 동등 분할 ㉤ 동등 커버리지 ㉥ 비교 검사 ㉦ 상태 전이 ㉧ 원인-결과 그래프
(1) ㉣
(2) ㉡
[해설]
입력 영역을 동등한 그룹으로 나누고 그룹별 대표값을 시험하는 것은 동등 분할(Equivalence Partitioning), 기호 ㉣이다. 동치 분할이라고도 한다.
(2)의 데이터는 유효 범위 양 끝(0, 100)과 판정이 바뀌는 지점(59, 60), 범위 바로 바깥(-1, 101)만 골랐으므로 경계값 분석(Boundary Value Analysis), 기호 ㉡이다.
- 원인-결과 그래프: 입력(원인)과 출력(결과)의 논리 관계를 그래프로 그려 케이스를 뽑는다.
- 결정 테이블: 조건 조합별 동작을 표로 정리해 시험한다.
- 상태 전이: 상태와 이벤트에 따른 전이를 시험한다.
- 비교 검사: 같은 입력을 여러 버전에 넣어 결과를 비교한다.
동등 분석, 동등 커버리지는 표준 기법 이름이 아닌 오답 보기다.
23-3
라우팅 프로토콜에 관한 다음 물음에 답하시오.
(1) 아래 설명에 해당하는 라우팅 프로토콜을 영문 약어로 적으시오.
- 하나의 자율 시스템(AS) 안에서 쓰이는 내부 게이트웨이 프로토콜(IGP)이며, 거리 벡터(Distance Vector) 알고리즘을 따른다.
- 경로 비용을 거쳐 가는 라우터 수(홉)로 계산하며, 최대 홉 수가 제한되어 있어 대규모 망에는 맞지 않는다.
- 라우팅 정보를 전송 계층의 UDP로 주고받는다.
(2) 목적지까지의 거리(비용)와 방향(다음 홉)만 라우팅 테이블에 기록하는 거리 벡터 방식의 프로토콜을 [보기]에서 모두 골라 적으시오.
[보기] BGP, IGRP, IS-IS, OSPF, RIP
(1) RIP
(2)
IGRP
RIP
[해설]
홉 수를 비용으로 쓰는 거리 벡터 방식 IGP는 RIP(Routing Information Protocol)이다.
- RIP — 최대 15홉까지만 유효하고 16홉은 도달 불가로 보며, UDP 520번 포트로 라우팅 테이블을 주기적으로 교환한다.
- IGRP — 시스코가 만든 거리 벡터 방식으로, 홉 수 대신 대역폭·지연 등을 조합한 복합 메트릭을 쓴다.
혼동 주의: OSPF·IS-IS는 링크 상태 방식, BGP는 AS 사이에서 쓰는 경로 벡터 방식이다.