컴퓨터시스템기사 실기 08 — 프로그래밍 언어 활용 (C 출력 예측·포인터·구조체·객체지향·스크립트
컴퓨터시스템기사 실기 08 — 프로그래밍 언어 활용 (C 출력 예측·포인터·구조체·객체지향·스크립트)
출제기준 코드: 5-1-1 프로그램 설계서 확인 · 5-1-2 구조적 언어로 애플리케이션 작성 · 5-1-3 오류 식별·수정
/ 5-2 객체지향 언어 활용 / 5-3 스크립트 활용
시험일: 2026-10-25 / 시리즈: 컴퓨터시스템기사 실기 08편
실기 시리즈 여덟 번째 글입니다.
이번 편은 대단원 5 (프로그래밍 언어 활용) 입니다.
이 단원은 두 종류 문제가 나옵니다.
① C 코드 출력 결과 쓰기 (가장 확실한 기출 유형)
② 빈칸 채우기 / 오류 수정 (B형에서 반복)
객체지향과 스크립트는 2026 신 출제기준에서 새로 들어온 항목이라 기출이 없지만, 코드를 읽고 결과를 예측하는 형태로 나올 가능성이 높아서 직접 풀어 본 예제로 대비합니다. (아래에서 "직접 만든 예제"는 기출이 아니라 제가 손으로 검산한 연습용입니다.)
1. 실기 출제 포인트
| 구분 | 형태 | 중요도 |
| C 출력 예측 | 비트 연산, 반복문, 배열 합, 문자열, 정렬 코드 | ⭐⭐⭐ |
| 빈칸 채우기 | 재귀(2진수 변환), 대소문자 변환, scanf 인자 | ⭐⭐⭐ |
| 포인터·배열 | 주소 연산, a[i] ≡ *(a+i), 2차원 배열 |
⭐⭐ |
| 구조체·공용체 | 멤버 접근, 크기 계산(패딩), union 공유 | ⭐⭐ |
| 객체지향 개념 | 캡슐화·상속·다형성·오버로딩/오버라이딩 | ⭐⭐ (신규) |
| 스크립트 | Python/Shell 출력 예측, 파이프·리다이렉션 | ⭐⭐ (신규) |
| 동적 할당 | malloc/free, 누수 | ⭐ |
💡 답안 키워드 박스
후위/전위 증감정수 나눗셈비트 연산(&, ^, |, <<, >>)널 종료 문자포인터 연산패딩공용체캡슐화상속다형성(오버라이딩)인터프리터파이프리다이렉션
2. C 출력 예측 — 규칙부터 (5-1-2) ⭐⭐⭐
2-1. 꼭 확인할 것
| 항목 | 규칙 |
| 전위/후위 증감 | ++i는 증가 후 사용, i++는 사용 후 증가 |
| 정수 나눗셈 | 7/2 = 3, 7%2 = 1, 7/2.0 = 3.5 |
| 비트 연산 | &(AND) |(OR) ^(XOR) ~(NOT) << >> |
| printf 서식 | %d 정수, %c 문자, %s 문자열, %f 실수, %x 16진수 |
| 공백·개행 | printf("%d", x) 에 공백이 없으면 숫자가 붙어서 출력 |
| 문자열 | 끝에 널 문자 \0 자동 추가, %s는 \0까지 출력 |
⚠️ 정렬 코드에서 printf가 어디에 있는지 꼭 보세요.
02편의 41234는 sort 함수 안에서 len(4)을 먼저 찍어서 나온 값입니다.
2-2. 기출 출력 예측 모음
| 출처 | 코드 핵심 | 출력 |
| A 2020-3 | i=24, z=22; a=i&z; b=i^z; printf("%d %d", a, b) |
16 14 |
| A 2020 통합 | for(a=1;a<=15;a++){ if(a%2==0 || a%3==0) continue; printf("%d",a); } |
1571113 |
| A 2021-3 | 배열 {20,40,60,80,100} 의 합을 for로 누적 |
300 |
| A 2021-3 | 2차원 문자 배열 {"ABC","DEF","GHI","JKL"} 에서 printf("%s", a[1]) |
DEF |
| A 2021-1·2025-1 | ct = {95,50,80,35,70} 내림차순 선택 정렬 후 %d로 연속 출력 |
9580705035 |
| A 2022-1 | 버블 정렬 함수 안에서 len 출력 후 main에서 배열 출력 |
41234 |
비트 연산 풀이 (A 2020-3)
24 = 0001 1000
22 = 0001 0110
AND = 0001 0000 = 16
XOR = 0000 1110 = 14 → "16 14"
조건 필터 풀이 (A 2020 통합)
1~15 중 2의 배수 또는 3의 배수는 continue(출력 생략)
남는 수: 1, 5, 7, 11, 13 → 붙여서 "1571113"
2-3. 직접 만든 연습 예제 (기출 아님, 손으로 검산)
① 증감 연산자
int a = 5;
int b = a++; /* b = 5, a = 6 */
int c = ++a; /* a = 7, c = 7 */
printf("%d %d %d", a, b, c); → 7 5 7
② 정수 나눗셈과 연산 순서
int x = 10 / 4 * 2; /* 10/4=2 → 2*2 = 4 */
double y = 10 / 4.0 * 2; /* 2.5 * 2 = 5.0 */
printf("%d %.1f", x, y); → 4 5.0
③ 시프트
printf("%d %d", 1 << 4, 32 >> 2); → 16 8
④ 무한 루프와 break (A 2020 통합 유형)
for ( ; ; ) { /* 빈칸 정답: ;; (조건 생략 = 항상 참) */
scanf("%d", &a);
if (a == 777) break;
}
3. 배열과 포인터 ⭐⭐
a[i] ≡ *(a + i) 배열 이름 = 첫 요소의 주소
p + 1 = p가 가리키는 자료형의 크기(sizeof)만큼 이동
직접 만든 예제
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;
printf("%d %d %d\n", *p, *(p + 2), p[4]); → 10 30 50
p++;
printf("%d", *p); → 20
문자열
char s[] = "ABC";
sizeof(s) = 4 (A,B,C,\0)
strlen(s) = 3 (널 문자 제외)
값 전달 vs 주소 전달 (swap 함수)
void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; } /* 호출: swap(&a, &b) */
swap(int x, int y)처럼 값으로 받으면 원본이 바뀌지 않습니다.
⚠️ 함정: 함수에 배열을 넘기면 포인터가 전달되므로 함수 안의 sizeof(arr) 는 배열 전체 크기가 아니라 포인터 크기(64비트에서 8바이트)입니다. 02편의 sizeof(ct) / sizeof(int) 는 main 안에서 계산했기에 4가 됐습니다.
4. 구조체와 공용체 ⭐⭐
4-1. 구조체 (기출 B 2021-11 Q5)
typedef struct Complex {
double real;
double imag;
} Complex;
int main(void) {
Complex c1, c2;
scanf("%lf %lf", &(①), &(②)); /* 첫 번째 복소수: 실수부, 허수부 */
scanf("%lf %lf", &(③), &(④)); /* 두 번째 복소수 */
complex_add(c1, c2);
}
정답(복원본): c1.real, c2.real, c1.imag, c2.imag
🔎 순서 주의: 코드 흐름대로라면 ①c1.real ②c1.imag ③c2.real ④c2.imag 가 자연스럽습니다.
복원본은 정답 열거 순서가 이와 다르게 적혀 있어 번호 대응이 불분명합니다.
시험장에서는 괄호 번호에 맞춰 "①c1.real ②c1.imag ③c2.real ④c2.imag"처럼 번호와 함께 쓰는 것이 안전합니다.
(또한 원문의complex_add함수는return이 빠져 있었습니다.)
- 멤버 접근: 변수는
.(c1.real), 포인터는->(p->real) scanf의 대상은 주소여야 하므로&필요 (&c1.real)
4-2. 구조체 크기 (패딩) — 직접 만든 예제
struct A { char a; int b; char c; }; /* 1 + (3 패딩) + 4 + 1 + (3 패딩) = 12 */
struct B { char a; char c; int b; }; /* 1 + 1 + (2 패딩) + 4 = 8 */
→ 같은 멤버라도 선언 순서에 따라 크기가 다릅니다. (int 4바이트 정렬 가정)
4-3. 공용체 (union)
union U { int i; double d; char c; };
sizeof(union U) = 8 (가장 큰 멤버 double 크기, 모든 멤버가 같은 메모리 공유)
- 한 번에 하나의 멤버만 유효. 마지막에 쓴 멤버만 의미 있음
- 용도: 같은 메모리를 다른 형식으로 해석 (패킷 헤더 필드, 프로토콜 파싱 — 07편의 헤더 구조와 연결)
5. 오류 식별과 수정 (5-1-3) ⭐⭐⭐
5-1. 재귀로 10진수를 2진수 출력 (B 2019-11 Q11)
void binary(int n) {
if (n > 0) {
binary( (1) ); /* 정답: n/2 */
printf("%d", (2) ); /* 정답: n%2 */
}
}
22 입력 추적: 재귀가 끝까지 내려간 뒤 돌아오면서 출력하므로 아래 자리부터 거꾸로 쌓입니다.
binary(22) → binary(11) → binary(5) → binary(2) → binary(1) → binary(0)(종료)
출력(복귀 순서): 1%2=1, 2%2=0, 5%2=1, 11%2=1, 22%2=0 → 10110
🔎 원문 코드에는
main이binary(n)을 호출하지 않고,void main에서return 0을 쓰는 오류가 있었습니다.
"오류를 찾아 수정하라"가 나오면 이런 항목(호출 누락, 반환형 불일치)도 체크하세요.
5-2. 대소문자 변환 (B 2020-11 Q6)
char ch;
scanf("%c", &ch);
if (ch >= (1) && ch <= (2)) /* 정답: 'a', 'z' */
ch = ch - (1) + (3); /* 정답: 'a' ... 'A' → 소문자를 대문자로 */
printf("%c", ch);
정답: (1) 'a', (2) 'z', (3) 'A'
→ 소문자 ch에서 'a'를 빼 알파벳 순번을 구한 뒤 'A'를 더해 대문자로 변환합니다 (예: 'c' - 'a' + 'A' = 'C').
🔎 원문 코드는 변수명이
ch와c로 섞여 있었습니다.
변수 선언과 사용이 일치하는지 확인하는 것이 오류 식별의 첫 단계입니다.
따옴표는 작은따옴표(문자).
5-3. 오류 식별 체크리스트
□ 변수 선언 이름과 사용 이름 일치 (ch / c)
□ 조건식 괄호, && / || 올바른 사용
□ scanf 형식 지정자와 & (주소 연산자)
□ 함수 return 누락, 반환형 일치
□ 재귀 함수의 종료 조건
□ 배열 인덱스 범위 (0 ~ n-1)
□ 세미콜론, 중괄호 짝
□ = (대입) 과 == (비교) 혼동
6. 메모리 동적 할당 ⭐ (보조)
int *p = (int *)malloc(5 * sizeof(int)); /* 힙에 20바이트 */
if (p == NULL) { /* 할당 실패 처리 */ }
/* 사용 */
free(p);
p = NULL; /* 해제 후 NULL로 (dangling 방지) */
| 함수 | 설명 |
malloc(n) |
n바이트 할당, 초기화 안 함 |
calloc(c, s) |
c×s 바이트 할당, 0으로 초기화 |
realloc(p, n) |
크기 변경 |
free(p) |
해제 |
대표 오류: 메모리 누수(해제 누락), 해제 후 사용(dangling pointer), 이중 해제(double free).
(실기 출제기준 5-1 세세항목에는 직접 명시되지 않아 우선순위는 낮습니다. 개념 정의 문제 정도로 대비하세요.)
7. 객체지향 프로그래밍 (5-2) ⭐⭐ 신규
7-1. 핵심 개념
| 개념 | 설명 |
| 클래스 / 객체(인스턴스) | 설계도 / 설계도로 만든 실체 |
| 캡슐화 | 데이터와 메서드를 묶고 접근 제한으로 정보 은닉 |
| 상속 | 부모 클래스의 속성·기능을 자식이 물려받아 재사용·확장 |
| 다형성 | 같은 메시지(메서드 호출)에 대상 객체에 따라 다르게 동작 |
| 추상화 | 공통 특성만 뽑아 단순화 (추상 클래스, 인터페이스) |
| 비교 | 오버로딩(Overloading) | 오버라이딩(Overriding) |
| 정의 | 같은 이름, 매개변수가 다른 메서드 여러 개 | 부모의 메서드를 자식이 재정의 |
| 관계 | 같은 클래스 안 | 상속 관계 |
| 결정 시점 | 컴파일 시 (정적) | 실행 시 (동적 바인딩) |
접근 제한자: public(어디서나) > protected(자식·같은 패키지) > default(같은 패키지) > private(해당 클래스만). UML에서는 +(public), #(protected), -(private) 로 표기합니다 (프로그램 설계서 확인의 핵심 기호).
7-2. 출력 예측 (직접 만든 예제, 기출 아님)
class Animal { void sound() { System.out.println("..."); } }
class Dog extends Animal { void sound() { System.out.println("멍멍"); } }
public class Main {
public static void main(String[] args) {
Animal x = new Dog(); /* 업캐스팅 */
x.sound(); /* 실제 객체 타입(Dog)의 메서드 호출 */
}
}
→ 멍멍 (오버라이딩 + 동적 바인딩)
class Counter { static int cnt = 0; Counter() { cnt++; } }
/* new Counter(); new Counter(); System.out.println(Counter.cnt); */
→ 2 (static 변수는 모든 객체가 공유)
⚠️ 함정: 변수 타입(Animal)이 아니라 실제 생성된 객체(Dog) 의 오버라이딩된 메서드가 실행됩니다.
필드는 오버라이딩되지 않습니다.
8. 스크립트 언어 (5-3) ⭐⭐ 신규
8-1. 종류와 특징
| 언어 | 용도 |
| Shell (Bash) | 리눅스 운영 자동화, 배치 |
| Python | 자동화, 데이터 처리, 보안 도구 |
| JavaScript | 웹 브라우저·Node.js |
| PowerShell | 윈도우 관리 자동화 |
| Perl / PHP / Ruby | 텍스트 처리 / 웹 서버 / 웹 프레임워크 |
공통 특징: 인터프리터 방식(소스를 한 줄씩 해석·실행, 별도 컴파일 불필요), 동적 타입, 개발 속도 빠름, 실행 속도는 컴파일 언어보다 느림.
(컴파일러는 소스 전체를 목적 코드로 번역 → 실행 빠름. 기출: 고급 언어를 기계어로 변환해 목적 프로그램을 만드는 번역기 = 컴파일러, A 2018-1)
8-2. Python 출력 예측 (직접 만든 예제)
a = [1, 2, 3, 4, 5]
print(a[1:4]) # [2, 3, 4] (끝 인덱스 4는 제외)
print(a[-1]) # 5 (-1은 마지막)
print(sum(x for x in a if x % 2 == 1)) # 9 (1+3+5)
print(7 // 2, 7 % 2, 7 / 2) # 3 1 3.5
print([x * x for x in range(4)]) # [0, 1, 4, 9]
print(list(range(1, 10, 3))) # [1, 4, 7]
⚠️ 파이썬은 /가 항상 실수 나눗셈, 정수 나눗셈은 //. 들여쓰기가 블록을 결정합니다 (중괄호 없음).
8-3. Shell 기본 (직접 만든 예제)
for i in 1 2 3; do echo $((i*i)); done # 1 4 9 (줄바꿈 출력)
x=5
if [ $x -gt 3 ]; then echo big; else echo small; fi # big
echo "a b c" | wc -w # 3 (파이프: 앞 출력 → 뒤 입력)
ls /nonexistent 2>/dev/null; echo $? # 2 (직전 명령 종료 코드, 0이 성공)
| 기호 | 의미 |
| |
파이프 (앞 명령 출력을 뒤 명령 입력으로) |
> / >> |
파일로 출력 (덮어쓰기 / 추가) |
2>&1 |
표준 오류를 표준 출력으로 합침 |
$? |
직전 명령의 종료 코드 |
$1, $@ |
첫 번째 인자, 모든 인자 |
⚠️ 쉘에서 변수 대입은 x=5 (= 양옆에 공백 금지), 사용은 $x.
9. 기출·예상 Q&A 모음
Q1. i=24, z=22; a=i&z; b=i^z; printf("%d %d", a, b); 의 출력은? (A 2020-3)
A. 16 14.
Q2. 1~15 중 2의 배수 또는 3의 배수를 건너뛰고 출력하는 반복문의 결과는? (A 2020 통합)
A. 1571113.
Q3. 배열 {20,40,60,80,100} 누적 합 출력? (A 2021-3)
A. 300.
Q4. 10진수를 2진수로 출력하는 재귀 함수의 빈칸은? (B 2019-11)
A. n/2, n%2 (22 → 10110).
Q5. 소문자를 대문자로 바꾸는 코드의 빈칸은? (B 2020-11)
A. 'a', 'z', 'A'.
Q6. 777을 입력하면 종료하는 무한 루프 for ( ① )의 ①은? (A 2020 통합)
A. ;; (모두 생략 = 항상 참).
Q7. 고급 언어를 기계어로 번역해 목적 프로그램을 생성하는 번역기는? (A 2018-1)
A. 컴파일러 (한 줄씩 해석해 즉시 실행하는 것은 인터프리터).
Q8. 같은 이름, 다른 매개변수로 메서드를 여러 개 정의하는 것은? (예상)
A. 오버로딩 (부모 메서드 재정의는 오버라이딩).
10. ⚠️ 함정 패턴 정리
printf의 공백·개행 유무 — 숫자가 붙어서 출력되는지 확인- 정수 나눗셈과
%의 부호·몫 - 전위/후위 증감의 평가 시점
=와==혼동 (조건식에서의 대입)scanf에&누락 (문자열 배열은&불필요)- sizeof(배열) — 함수 안에서는 포인터 크기
- 구조체 크기 — 단순 합이 아니라 패딩 포함
- union 크기 = 가장 큰 멤버
- 오버로딩 ↔ 오버라이딩, 정적 ↔ 동적 바인딩
- Python
/vs//, 슬라이스 끝 인덱스 제외
11. 💡 실무에서는?
- C의 가장 흔한 보안 결함은 메모리 오류입니다.
gets,strcpy,sprintf처럼 길이를 검사하지 않는 함수는 버퍼 오버플로우의 원인이고,fgets,strncpy,snprintf로 대체합니다. 시험에서 배운 "배열 인덱스 범위"가 실무에서는 취약점 점검 1순위 항목입니다. 개발 단계에서gcc -Wall -Wextra,cppcheck,clang-tidy, 런타임-fsanitize=address(AddressSanitizer)를 쓰면 대부분 걸러집니다. - 구조체 패딩/정렬은 네트워크 패킷·파일 포맷을 구조체로 직접 매핑할 때 문제를 일으킵니다 (
#pragma pack, 엔디안 변환ntohl). 07편의 헤더 필드와 이어지는 지점입니다. - 객체 역직렬화 취약점 (Java
ObjectInputStream, Pythonpickle): 신뢰할 수 없는 데이터를 역직렬화하면 원격 코드 실행이 가능합니다. 객체지향의 "객체 복원"이 공격 표면이 되는 사례입니다. - 쉘 스크립트 방어적 작성: 스크립트 상단에
set -euo pipefail, 변수는 항상"$var"로 인용 (공백·특수문자·명령 주입 방지), 입력값은 검증 후 사용, 비밀번호·토큰 하드코딩 금지(환경 변수·시크릿 매니저). 정적 점검은 ShellCheck가 유용합니다. - Python 운영 스크립트: 가상환경(
venv)으로 의존성 분리,subprocess호출 시shell=True지양(주입 위험), 로깅·예외 처리를 넣어 cron/자동화에서 조용히 실패하지 않게 합니다. - 로그 분석 자동화 한 줄:
grep ERROR app.log | awk '{print $1}' | sort | uniq -c | sort -rn | head— 파이프 개념 그대로입니다.
12. 핵심 정리
✅ 출력 예측 순서: 변수 값 추적 → 연산자 규칙 → printf 서식(공백/개행)
✅ i&z=16, i^z=14 (24, 22) / 1~15 중 2·3의 배수 제외 = 1571113
✅ 증감: i++ (사용 후), ++i (증가 후) / 7/2=3, 7%2=1
✅ a[i] ≡ *(a+i) / 문자열은 \0 종료 / sizeof("ABC" 배열)=4
✅ 값 전달은 원본 불변 → 바꾸려면 포인터 전달
✅ 구조체: . / -> , 크기에 패딩 포함 / union 크기 = 최대 멤버
✅ 재귀 2진수 변환: binary(n/2) → printf(n%2)
✅ 소문자→대문자: ch - 'a' + 'A'
✅ 무한 루프 for(;;) / break로 탈출
✅ malloc(초기화 X) / calloc(0 초기화) / free 후 NULL
✅ 객체지향: 캡슐화·상속·다형성·추상화 / 오버로딩(이름 같고 인자 다름) vs 오버라이딩(재정의)
✅ 컴파일러(전체 번역) vs 인터프리터(한 줄씩 실행) = 스크립트
✅ Python: / 실수, // 정수, 슬라이스 끝 제외 / Shell: 변수 = 양옆 공백 금지, $? 종료 코드
13. 다음 편 예고
다음 편(09편)은 이 시리즈의 마지막 개발자 환경 구축 + 구 범위 보충 입니다.
운영체제 기본 명령어와 작업 우선순위(nice, 스케줄링), 개발도구, 그리고 구 범위에서 반복 출제된 어셈블러·로더·소프트웨어 테스트(블랙박스·화이트박스·순환 복잡도) 까지 한 번에 정리합니다!
궁금한 점은 댓글로 남겨주세요!