25-3
아래 Java 프로그램이 컴파일되어 Kim 600을 출력하도록, 빈칸 ( ① )에 들어갈 키워드를 적으시오.
class Account {
String owner;
int balance;
Account(String owner, int balance) {
this.owner = owner;
this.balance = balance;
}
}
class Savings extends Account {
int rate;
Savings(String owner, int balance, int rate) {
( ① )(owner, balance);
this.rate = rate;
}
int interest() {
return balance * rate / 100;
}
}
public class Main {
public static void main(String[] args) {
Savings s = new Savings("Kim", 20000, 3);
System.out.println(s.owner + " " + s.interest());
}
}super
[해설]
자식 생성자에서 부모 생성자를 명시적으로 부를 때는 super(인자)를 쓴다. 이 호출은 생성자 본문의 첫 문장이어야 한다.
Account에는 인자 없는 기본 생성자가 없으므로, super(owner, balance)가 없으면 컴파일 오류가 난다.
- super(owner, balance): 부모 필드 owner="Kim", balance=20000 초기화
- interest(): 20000 × 3 / 100 = 600
25-3
다음 설명에 해당하는 인증 기술을 영문 약어로 적으시오.
- 인터넷 뱅킹 같은 금융 거래에서 로그인·이체 시 추가 인증 수단으로 많이 쓰인다.
- 난수와 해시 함수, 시각 또는 사용 횟수 정보를 조합해 인증할 때마다 새로운 비밀번호를 만든다.
- 만든 비밀번호는 한 번 쓰면 폐기되고 장기간 저장되지 않으므로, 가로채더라도 재사용(재전송) 공격에 쓸 수 없다.
OTP
[해설]
인증할 때마다 새로 만들어져 한 번만 유효한 비밀번호는 OTP(One-Time Password, 일회용 비밀번호)다.
시각을 기준으로 값을 만드는 방식은 TOTP, 사용 횟수를 기준으로 만드는 방식은 HOTP라 한다. 한 번 쓰면 폐기되므로 가로챈 값으로는 재전송 공격을 할 수 없다.
25-3
아래 Java 프로그램이 정상적으로 컴파일되어 Fee:4500을 출력하도록, 빈칸 ( ① )에 들어갈 키워드를 적으시오.
interface Payable {
int fee();
}
class Ticket ( ① ) Payable {
private int count;
Ticket(int count) {
this.count = count;
}
public int fee() {
return count * 1500;
}
}
public class Main {
public static void main(String[] args) {
Payable p = new Ticket(3);
System.out.println("Fee:" + p.fee());
}
}implements
[해설]
클래스가 인터페이스를 구현할 때는 implements를 쓴다. Ticket은 Payable의 추상 메서드 fee()를 재정의해야 객체를 만들 수 있다.
p는 인터페이스 타입이지만 실제 객체는 Ticket이므로 fee()는 3 × 1500 = 4500을 돌려준다.
- extends: 클래스가 클래스를, 인터페이스가 인터페이스를 상속할 때
- implements: 클래스가 인터페이스를 구현할 때(여러 개를 쉼표로 나열 가능)
25-3
테스트 케이스를 작성할 때 포함하는 구성 요소에 관한 설명이다. 빈칸 ①~③에 알맞은 구성 요소를 적으시오.
| 구성 요소 | 내용 |
|---|---|
| ( ① ) | 테스트를 수행하기 전에 갖춰져야 할 환경, 선행되어야 할 다른 테스트와의 종속 관계 등 사전 고려 사항 |
| ( ② ) | 테스트를 실행할 때 투입하는 입력값, 눌러야 할 버튼, 선택 항목 값 등 |
| ( ③ ) | 테스트를 실행한 뒤 나와야 하는 출력 데이터, 화면 결과, 시스템의 동작 등 |
① 테스트 조건
② 테스트 데이터
③ 예상 결과
[해설]
테스트 케이스는 실행 전 조건, 입력, 기대 출력을 갖춰야 합격 여부를 판정할 수 있다.
- 테스트 조건은 수행 전에 갖춰야 할 환경과 선행 테스트와의 종속 관계다(전제 조건이라고도 함).
- 테스트 데이터는 실행할 때 투입하는 입력값·버튼·선택값이다.
- 예상 결과는 실행 후 나와야 할 출력·화면·동작이다(기대 결과라고도 함).
실제 결과가 예상 결과와 다르면 결함으로 기록한다.
25-3
아래 C 프로그램이 출력하는 문자를 적으시오.
#include <stdio.h>
int main(void) {
char msg[] = "SOFTWAREENGINEER";
int n = 0;
while (msg[n])
n++;
printf("%c", msg[n - 4]);
return 0;
}N
[해설]
while 문은 널 문자를 만날 때까지 n을 늘리므로, 반복이 끝나면 n은 문자열 길이 16이다.
인덱스: S0 O1 F2 T3 W4 A5 R6 E7 E8 N9 G10 I11 N12 E13 E14 R15
msg[n − 4] = msg[16 − 4] = msg[12] = N
외우는 요령: msg[n]은 널 문자이고 msg[n − 1]이 마지막 글자 R이다. 거기서 거꾸로 R·E·E·N으로 세면 네 번째가 N이다.
25-3
다음 설명에 해당하는 개방형 표준 기술을 영문으로 적으시오.
- 사용자가 자신의 비밀번호를 넘겨주지 않고도, 다른 웹사이트나 앱이 자기 계정 정보 일부에 접근하도록 권한을 위임할 수 있게 한다.
- 쇼핑몰에 새로 가입하지 않고 포털이나 SNS 계정으로 로그인하는 "소셜 로그인"에 널리 쓰인다.
- 권한을 받은 서비스는 비밀번호 대신 발급받은 액세스 토큰으로 자원에 접근한다.
OAuth
[해설]
비밀번호 대신 액세스 토큰으로 접근 권한을 위임하는 개방형 표준은 OAuth(Open Authorization)다.
사용자가 동의하면 인가 서버가 토큰을 발급하고, 서비스는 이 토큰으로 허용된 범위(Scope)의 자원에만 접근한다.
혼동 주의: OAuth는 본래 인가(권한 위임) 표준이고, 그 위에 사용자 인증을 얹은 것이 OpenID Connect다.
25-3
아래 C 프로그램을 실행했을 때 출력되는 값을 적으시오.
#include <stdio.h>
struct Link {
unsigned int val;
struct Link *nx;
};
int main(void) {
struct Link n1 = {6u, NULL};
struct Link n2 = {3u, NULL};
struct Link n3 = {8u, NULL};
struct Link *cur;
unsigned int acc = 0u;
n1.nx = &n3;
n3.nx = &n2;
for (cur = &n1; cur != NULL; cur = cur->nx)
acc = acc * 4u + cur->val;
acc = (acc ^ 60u) + 20u;
printf("%u", acc);
return 0;
}211
[해설]
for 문은 선언 순서가 아니라 nx 포인터를 따라 n1 → n3 → n2 순으로 방문하므로, val은 6, 8, 3 순으로 읽힌다.
acc = acc × 4 + val
n1: 0 × 4 + 6 = 6
n3: 6 × 4 + 8 = 32
n2: 32 × 4 + 3 = 131
131 XOR 60 = 1000 0011 XOR 0011 1100
= 1011 1111 = 191
191 + 20 = 211
혼동 주의: C의 ^는 거듭제곱이 아니라 비트 XOR이라, 두 비트가 같으면 0, 다르면 1이 된다.
25-3
화이트박스 테스트에서, 판단문 하나에 포함된 개별 조건식 각각이 최소 한 번씩 참과 거짓 값을 모두 가지도록 테스트 케이스를 만드는 기준이 있다. 이때 판단문 전체의 결과가 참·거짓을 모두 거치는지는 따지지 않는다. 이 기준에 해당하는 것을 [보기]에서 골라 기호와 이름을 적으시오.
[보기] ㄱ. 결정 커버리지, ㄴ. 구문 커버리지, ㄷ. 기본 경로 커버리지, ㄹ. 다중 조건 커버리지, ㅁ. 데이터 흐름 테스트, ㅂ. 루프 테스트, ㅅ. 변경 조건/결정 커버리지, ㅇ. 제어 흐름 테스트, ㅈ. 조건 커버리지, ㅊ. 조건/결정 커버리지
ㅈ. 조건 커버리지(Condition Coverage)
[해설]
개별 조건식마다 참·거짓을 한 번씩 만족시키되 판단문 전체 결과는 신경 쓰지 않는 것은 조건 커버리지(Condition Coverage)다.
- 결정 커버리지: 판단문 전체의 결과가 참·거짓을 한 번씩 갖도록 한다.
- 조건/결정 커버리지: 개별 조건과 판단문 전체 결과를 모두 참·거짓으로 만든다.
- 변경 조건/결정 커버리지(MC/DC): 각 개별 조건이 다른 조건과 무관하게 전체 결과를 바꿀 수 있음을 보인다.
- 다중 조건 커버리지: 개별 조건의 참·거짓 조합을 모두 시험한다.
예컨대 if (x > 0 || y > 0)에서 (x=1, y=-1)과 (x=-1, y=1)을 쓰면 두 조건은 각각 참·거짓을 다 갖지만 전체 결과는 둘 다 참이다. 조건 커버리지는 만족해도 결정 커버리지는 만족하지 못하는 사례다.
25-3
[PLAYER]와 [PATTERN] 테이블이 다음과 같을 때, 아래 SQL의 실행 결과를 적으시오.
[PLAYER]
| NAME |
|---|
| KAREN |
| MARK |
| TINA |
| LEO |
[PATTERN]
| PAT |
|---|
| T% |
| %E% |
| %A% |
SELECT COUNT(*) AS TOTAL
FROM PLAYER CROSS JOIN PATTERN
WHERE PLAYER.NAME LIKE PATTERN.PAT;6
[해설]
CROSS JOIN은 4 × 3 = 12개 조합을 만들고, 그중 NAME이 PAT 패턴에 맞는 조합만 센다.
- KAREN: %E%, %A% → 2건
- MARK: %A% → 1건
- TINA: T%, %A% → 2건
- LEO: %E% → 1건
합계는 6이다. %는 0개 이상의 임의 문자이므로 %A%는 위치와 관계없이 A가 들어 있으면 참이다.
25-3
릴레이션 R과 S가 아래와 같을 때, 관계대수 R ÷ S를 수행한 결과를 표로 적으시오.
[R]
| A | B |
|---|---|
| a1 | b1 |
| a2 | b3 |
| a3 | b1 |
| a2 | b1 |
| a1 | b2 |
[S]
| B |
|---|
| b1 |
| b3 |
| A |
|---|
| a2 |
[해설]
R ÷ S는 S의 B 값(b1, b3)을 모두 짝으로 가진 R의 A 값만 남기고, 결과 속성은 R에서 S의 속성을 뺀 A다.
- a1: b1, b2 → b3이 없어 제외
- a2: b3, b1 → 둘 다 있어 포함
- a3: b1 → b3이 없어 제외
결과는 속성 A 하나에 튜플 a2 한 개인 릴레이션이다.
25-3
아래 C 프로그램의 실행 결과를 적으시오.
#include <stdio.h>
struct Card {
int hop;
const char *word;
};
int main(void) {
struct Card deck[] = {{3, "LAMP"}, {1, "SNOW"}, {1, "KITE"}, {2, "RAIN"}};
struct Card *c = deck + 2;
printf("%s", c->word + c->hop * 2);
return 0;
}TE
[해설]
c는 deck + 2, 즉 세 번째 원소 {1, "KITE"}를 가리킨다.
- c->hop * 2 = 1 × 2 = 2
- c->word + 2는 "KITE"의 인덱스 2('T') 위치를 가리키는 포인터
- %s는 그 위치부터 널 문자 전까지 출력한다.
따라서 TE가 출력된다. 포인터에 정수를 더하면 그 자료형 크기만큼 주소가 이동하며, char 포인터는 한 글자씩 이동한다.
25-3
접근 통제 정책에 관한 설명이다. 빈칸 ①~③에 알맞은 정책을 영문 약어로 적으시오.
- ( ① ): 규칙 기반 정책이다. 객체마다 매겨진 비밀 등급과 주체가 가진 보안 허가(인가) 등급을 시스템이 비교해 접근 여부를 정하며, 사용자나 소유자가 임의로 바꿀 수 없다.
- ( ② ): 중앙 관리자가 조직 안의 직무(역할)별로 권한을 묶어 두고, 사용자에게는 역할을 배정해 그 역할에 맞는 자원에만 접근하게 한다.
- ( ③ ): 신분 기반 정책이다. 주체나 그 주체가 속한 그룹의 신원에 따라 접근을 허용하며, 객체의 소유자가 다른 사용자에게 권한을 나눠 줄 수 있다.
① MAC
② RBAC
③ DAC
[해설]
접근 통제 정책은 누가 권한을 정하는지로 나뉘며, 시스템이 강제하면 MAC, 역할을 배정하면 RBAC, 소유자 재량이면 DAC다.
- MAC(Mandatory Access Control, 강제적 접근 통제) — 객체의 비밀 등급과 주체의 인가 등급을 비교하는 규칙 기반이라 사용자가 바꿀 수 없다.
- RBAC(Role-Based Access Control, 역할 기반 접근 통제) — 중앙 관리자가 직무별 권한 묶음을 만들고 사용자에게 역할을 배정한다.
- DAC(Discretionary Access Control, 임의적 접근 통제) — 신분 기반이며 객체 소유자가 다른 사용자에게 권한을 나눠 줄 수 있다.
예시로 외우면 쉽다: MAC은 군사 기밀 등급, RBAC은 부서·직무별 사내 권한, DAC은 리눅스 파일 소유자의 chmod다.
25-3
아래 Java 프로그램을 실행하면 출력되는 값을 적으시오.
public class Main {
public static void main(String[] args) {
int a = 9, b = 6, c;
c = b % 4 == 2 ? 6 : 4;
c = c ^ c >> 1;
c = a < 10 && c > 5 ? a - c : a % c;
System.out.println(c);
}
}4
[해설]
연산자 우선순위에서 시프트(>>)가 XOR(^)보다 먼저 계산되는 점이 핵심이다.
b % 4 = 6 % 4 = 2 → 참이므로 c = 6
c ^ (c >> 1) = 6 ^ 3 = 110 ^ 011 = 101 = 5
9 < 10 && 5 > 5 → 거짓
a % c = 9 % 5 = 4
혼동 주의: c ^ c >> 1을 (c ^ c) >> 1로 읽으면 답이 완전히 달라진다. 5 > 5는 등호가 없어 거짓이다.
25-3
데이터 전송 중 생기는 오류를 다루는 방식에 관한 설명이다. 빈칸 ①~⑤에 알맞은 용어를 [보기]에서 골라 적으시오.
- 오류 제어는 수신 측이 스스로 고치는 ( ① ) 방식과, 송신 측에 다시 보내 달라고 요청하는 ( ② ) 방식으로 나뉜다.
- ( ① ) 방식은 오류를 검출한 뒤 재전송 없이 수신 측에서 바로잡는다. 이 방식의 대표인 ( ③ ) 코드는 검사 비트를 여러 위치에 두어 오류 비트의 위치를 찾아내며, 1비트 오류를 정정할 수 있다.
- ( ② ) 방식은 오류가 확인되면 재전송을 요청한다. 오류 검출에는 ( ④ ) 검사, ( ⑤ ) 등이 쓰인다.
- ( ④ ) 검사는 문자 단위 비트열에 1비트를 덧붙여 1의 개수를 짝수 또는 홀수로 맞추고, 수신 측에서 그 개수로 오류를 가려낸다.
- ( ⑤ )은/는 생성 다항식으로 나눈 나머지를 검사값으로 붙여 보내는 방식으로, 여러 비트가 한꺼번에 깨지는 집단 오류 검출에 강하다.
[보기] BCD, BEC, CRC, FEC, Hamming, MD5, NAK, Parity
① FEC
② BEC
③ Hamming
④ Parity
⑤ CRC
[해설]
오류 제어는 수신 측이 스스로 고치는 FEC(Forward Error Correction, 전진 오류 수정)와 송신 측에 재전송을 요청하는 BEC(Backward Error Correction, 후진 오류 수정)로 나뉜다.
- Hamming(해밍) 코드 — FEC의 대표로, 검사 비트를 여러 위치에 두어 오류 위치를 찾고 1비트 오류를 정정한다.
- Parity(패리티) 검사 — 1비트를 덧붙여 1의 개수를 짝수 또는 홀수로 맞추는 검출 방식이다.
- CRC(Cyclic Redundancy Check, 순환 중복 검사) — 생성 다항식으로 나눈 나머지를 붙여 보내며, 집단 오류 검출에 강하다.
혼동 주의: 패리티는 짝수 개 비트가 동시에 깨지면 놓치므로 집단 오류에는 CRC를 쓴다. 보기의 NAK은 부정 응답 신호, MD5는 해시 함수, BCD는 10진수 표현 코드라 답이 아니다.
25-3
열거형(enum)을 사용한 아래 Java 코드를 실행했을 때 콘솔에 찍히는 문자열을 적으시오.
enum Level {
LOW("green"), MID("yellow"), HIGH("orange"), TOP("red");
private final String tag;
Level(String tag) {
this.tag = tag;
}
public String tag() {
return tag;
}
}
public class Main {
public static void main(String[] args) {
Level lv = Level.values()[Level.LOW.name().length()];
System.out.println(lv.tag());
}
}red
[해설]
Java enum의 name()은 상수 이름 문자열을, values()는 선언 순서대로 담은 배열을 돌려준다.
- Level.LOW.name()은 "LOW"라서 length()는 3이다.
- values()는 [LOW, MID, HIGH, TOP]이므로 인덱스 3은 TOP이다.
- TOP 생성자에 넘긴 tag가 "red"라서 tag()는 red를 돌려준다.
혼동 주의: name()은 "LOW"(상수 이름)이지 "green"(필드 값)이 아니다. 배열 인덱스는 0부터라 3은 네 번째 상수다.
25-3
리눅스(유닉스) 셸에서 다음 작업을 할 때 쓰는 명령어를 각각 적으시오.
- ( ① ): 지금 머물러 있는 디렉터리가 루트(/)부터 어떤 경로에 있는지 전체 경로로 보여 준다.
- ( ② ): 현재 디렉터리 안에 들어 있는 파일과 하위 디렉터리의 목록을 나열한다.
- ( ③ ): 작업 위치를 다른 디렉터리로 옮긴다.
- ( ④ ): 원본 파일을 그대로 둔 채, 같은 내용의 파일을 다른 이름이나 위치에 하나 더 만든다.
① pwd
② ls
③ cd
④ cp
[해설]
리눅스 기본 명령어는 영어 약어에서 나오므로 원래 뜻과 함께 외운다.
- pwd(print working directory) — 현재 디렉터리의 전체 경로를 출력한다.
- ls(list) — 현재 디렉터리의 파일·하위 디렉터리 목록을 나열한다.
- cd(change directory) — 작업 디렉터리를 옮긴다.
- cp(copy) — 원본을 두고 복사본을 만들며, 디렉터리째 복사할 때는 cp -r을 쓴다.
혼동 주의: mv는 이동·이름 변경이라 원본이 남지 않고, rm은 삭제, mkdir은 디렉터리 생성이다.
25-3
[ORD] 테이블에 대해 아래 SQL을 실행했을 때 출력되는 값을 적으시오.
| NO | QTY | PRICE |
|---|---|---|
| 1 | 4 | 100 |
| 2 | NULL | 200 |
| 3 | 7 | NULL |
| 4 | 1 | 300 |
| 5 | 7 | 200 |
| 6 | 2 | NULL |
SELECT COUNT(PRICE)
FROM ORD
WHERE QTY IN (1, 7) OR PRICE IN (200, 500);3
[해설]
WHERE에서 NULL 비교는 UNKNOWN이라 OR의 다른 쪽이 참일 때만 행이 남고, COUNT(칼럼)은 NULL을 세지 않는다.
- NO 1 — QTY 4, PRICE 100이라 제외.
- NO 2 — QTY는 NULL이지만 PRICE 200이 참이라 포함.
- NO 3 — QTY 7이라 포함되지만 PRICE가 NULL.
- NO 4 — QTY 1이라 포함.
- NO 5 — QTY 7이라 포함.
- NO 6 — QTY 2이고 PRICE가 NULL이라 제외.
남은 NO 2·3·4·5 중 PRICE가 NULL인 NO 3을 빼면 3이다. COUNT(*)였다면 4가 나온다.
25-3
온라인 좌석 예약 시스템을 설계하면서, 관련 있는 클래스들을 묶음 단위로 나누고 묶음 사이의 의존 관계를 아래와 같이 UML로 표현하였다. 이 다이어그램의 이름을 적으시오.
- 탭이 달린 폴더 모양의 요소 세 개(Reservation, Fare, Seat)가 그려져 있고, 각 요소 안에는 여러 클래스가 들어 있다.
| 출발 요소 | 연결선 | 도착 요소 |
|---|---|---|
| Reservation | 점선 화살표(의존) | Fare |
| Reservation | 점선 화살표 + «import» 표기 | Seat |
패키지 다이어그램(Package Diagram)
[해설]
탭이 달린 폴더 모양 요소로 관련 클래스를 묶고 그 사이 의존을 점선 화살표로 잇는 것은 UML 패키지 다이어그램(Package Diagram)이다.
«import»는 한 패키지가 다른 패키지의 요소를 가져다 쓰는 의존을 밝히는 스테레오타입이다.
패키지 다이어그램은 시스템의 정적 구조를 보여 주는 구조 다이어그램에 속한다.
혼동 주의: 클래스 다이어그램은 개별 클래스의 속성·연산과 관계를, 컴포넌트 다이어그램은 실행 구성 요소와 인터페이스를 그린다.
25-3
아래 Python 프로그램의 출력 결과를 적으시오.
groups = [
[6, 1, 8],
[2, 9, 4, 5],
[7],
[3, 3, 3, 3, 3]
]
summary = {}
for pos, row in enumerate(groups, start=1):
total = sum(row)
cnt = len(row)
summary[pos] = (total, cnt)
print(summary){1: (15, 3), 2: (20, 4), 3: (7, 1), 4: (15, 5)}
[해설]
enumerate(groups, start=1)은 번호를 0이 아닌 1부터 붙여 (번호, 원소) 쌍을 차례로 넘긴다.
- 1: [6, 1, 8] → 합 15, 개수 3
- 2: [2, 9, 4, 5] → 합 20, 개수 4
- 3: [7] → 합 7, 개수 1
- 4: [3, 3, 3, 3, 3] → 합 15, 개수 5
딕셔너리는 넣은 순서대로 출력되므로 결과는 {1: (15, 3), 2: (20, 4), 3: (7, 1), 4: (15, 5)}다.
25-3
관계형 데이터베이스의 구성 용어에 관한 설명이다. 빈칸 ①~③에 알맞은 용어를 [보기]에서 골라 적으시오.
- ( ① ): 릴레이션의 한 행(Row)으로, 파일 구조의 레코드에 대응한다. 여러 속성값이 모여 하나의 개체를 나타낸다.
- ( ② ): 어느 한 시점에 릴레이션에 실제로 들어 있는 튜플들의 집합이다. 릴레이션 외연(Extension)이라고도 하며, 데이터가 바뀔 때마다 달라진다.
- ( ③ ): 한 릴레이션에 들어 있는 튜플의 개수를 말한다.
[보기] 디그리(Degree), 릴레이션 스키마(Relation Schema), 릴레이션 인스턴스(Relation Instance), 애트리뷰트(Attribute), 카디널리티(Cardinality), 튜플(Tuple)
① 튜플(Tuple)
② 릴레이션 인스턴스(Relation Instance)
③ 카디널리티(Cardinality)
[해설]
관계형 데이터베이스에서 행 하나는 튜플, 특정 시점의 튜플 집합은 릴레이션 인스턴스, 튜플 수는 카디널리티다.
- 튜플(Tuple) — 릴레이션의 한 행으로 파일 구조의 레코드에 해당한다.
- 릴레이션 인스턴스(Relation Instance) — 어느 시점에 실제로 들어 있는 튜플 집합(외연)이라 데이터가 바뀌면 달라진다.
- 카디널리티(Cardinality) — 한 릴레이션에 들어 있는 튜플의 개수다.
혼동 주의: 속성(애트리뷰트)의 개수는 디그리이고, 구조(내포)를 정의해 잘 바뀌지 않는 것은 릴레이션 스키마다.