정보처리기사 실기에서 프로그래밍 문제는 전체 20문항 중 4~6문항을 차지합니다. C언어, Java, Python 세 가지 언어에서 번갈아 출제되는데요. 코드를 직접 짜는 게 아니라 "이 코드를 실행하면 결과가 뭐야?"를 묻는 코드 추적 문제가 대부분입니다. 언어 자체를 깊이 배울 필요는 없고, 시험에 자주 나오는 패턴만 잡으면 충분히 점수를 챙길 수 있어요.
📌 프로그래밍 출제 비중 & 유형
✔ 코드 추적 — 코드 실행 결과 출력값 쓰기 (가장 많음)
✔ 빈칸 채우기 — 코드 일부가 비워져 있고 올바른 키워드/값 작성
✔ 오류 찾기 — 잘못된 코드 줄 찾아 수정
언어별로 C → 포인터·재귀, Java → 상속·오버라이딩, Python → 리스트·람다가 단골 출제 테마입니다.
✔ 코드 추적 — 코드 실행 결과 출력값 쓰기 (가장 많음)
✔ 빈칸 채우기 — 코드 일부가 비워져 있고 올바른 키워드/값 작성
✔ 오류 찾기 — 잘못된 코드 줄 찾아 수정
언어별로 C → 포인터·재귀, Java → 상속·오버라이딩, Python → 리스트·람다가 단골 출제 테마입니다.
C 언어
C언어 문제에서 가장 많이 나오는 건 포인터와 재귀함수입니다. 이 두 가지만 완벽히 잡아도 C언어 문제의 70%는 풀 수 있어요.
① 기본 출력과 연산자
#include <stdio.h>
int main() {
int a = 10, b = 3;
printf("%d\n", a / b); // 정수 나눗셈 → 3
printf("%d\n", a % b); // 나머지 → 1
printf("%d\n", a++); // 출력 후 증가 → 10
printf("%d\n", ++b); // 증가 후 출력 → 4
return 0;
}
🔍 코드 추적
a / b → 10 ÷ 3 = 3 (소수점 버림)a % b → 10 mod 3 = 1a++ → 현재 a(10) 출력 후 a가 11이 됨 → 10++b → b를 먼저 4로 만든 뒤 출력 → 4
💡 후위(a++) vs 전위(++a) 헷갈릴 때
후위(a++) — "나 먼저 쓰고 나서 올라갈게" → 현재 값 출력 후 증가
전위(++a) — "올라가고 나서 쓸게" → 먼저 증가 후 출력
후위(a++) — "나 먼저 쓰고 나서 올라갈게" → 현재 값 출력 후 증가
전위(++a) — "올라가고 나서 쓸게" → 먼저 증가 후 출력
② 포인터 — C언어 최빈출 주제
포인터는 변수의 메모리 주소를 저장하는 변수입니다. &는 주소 가져오기, *는 주소가 가리키는 값 가져오기입니다.
#include <stdio.h>
int main() {
int a = 10;
int *p = &a; // p는 a의 주소를 저장
printf("%d\n", a); // 10
printf("%d\n", *p); // p가 가리키는 값 → 10
*p = 20; // p가 가리키는 곳(a)의 값을 20으로 변경
printf("%d\n", a); // a도 20으로 바뀜 → 20
return 0;
}
🔍 메모리 구조로 이해하기
0x100 (a)
10
0x104 (p)
0x100
*p = 20을 하면 0x100 위치(= a)의 값이 20으로 바뀝니다.
③ 배열과 포인터
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *p = arr; // 배열 이름 = 첫 번째 원소의 주소
printf("%d\n", *p); // 10
printf("%d\n", *(p+1)); // 20 (주소+1 칸 이동)
printf("%d\n", *(p+2)); // 30
printf("%d\n", p[3]); // 40 (p[n] == *(p+n))
p++; // p가 arr[1]을 가리킴
printf("%d\n", *p); // 20
return 0;
}
🎯 배열 포인터 핵심 공식
배열 이름(arr)은 그 자체가 첫 번째 원소(&arr[0])의 주소입니다.
arr[i] == *(arr + i) == *(p + i) == p[i]배열 이름(arr)은 그 자체가 첫 번째 원소(&arr[0])의 주소입니다.
④ 재귀 함수 — 두 번째 단골 주제
재귀는 함수가 자기 자신을 호출하는 것입니다. 시험에서는 팩토리얼, 피보나치, 거듭제곱 형태로 자주 나옵니다.
#include <stdio.h>
int factorial(int n) {
if (n <= 1) return 1; // 종료 조건 (base case)
return n * factorial(n - 1); // 자기 자신 호출
}
int main() {
printf("%d\n", factorial(5)); // ?
return 0;
}
🔍 호출 스택 추적 (factorial(5))
factorial(5) = 5 × factorial(4)factorial(4) = 4 × factorial(3)
factorial(3) = 3 × factorial(2)
factorial(2) = 2 × factorial(1)
factorial(1) = 1 ← 여기서 멈춤
↑ 거슬러 올라가며 계산
2×1=2 → 3×2=6 → 4×6=24 → 5×24=120
// 피보나치 수열 (자주 출제!)
int fib(int n) {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
}
// fib(5) = fib(4)+fib(3) = 3+2 = 5
// fib(0)=0, fib(1)=1, fib(2)=1, fib(3)=2, fib(4)=3, fib(5)=5
⑤ 구조체
#include <stdio.h>
struct Student {
char name[20];
int score;
};
int main() {
struct Student s = {"홍길동", 95};
printf("%s\n", s.name); // 홍길동
printf("%d\n", s.score); // 95
struct Student *p = &s;
printf("%s\n", p->name); // 포인터로 접근할 때는 ->
return 0;
}
💡 . vs -> 구분법
구조체 변수로 접근 →
구조체 포인터로 접근 →
구조체 변수로 접근 →
s.name (점 연산자)구조체 포인터로 접근 →
p->name (화살표 연산자)
Java
Java 문제에서는 클래스·상속·오버라이딩이 압도적으로 자주 나옵니다. 코드를 보고 어떤 메서드가 실행될지, 출력값이 뭔지를 추적하는 패턴이 반복됩니다.
① 클래스와 생성자
class Animal {
String name;
int age;
// 생성자
Animal(String name, int age) {
this.name = name; // this = 현재 객체
this.age = age;
}
void speak() {
System.out.println(name + "이(가) 소리를 냅니다.");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Animal("강아지", 3);
a.speak(); // 강아지이(가) 소리를 냅니다.
System.out.println(a.age); // 3
}
}
② 상속 + 오버라이딩 — 최빈출!
오버라이딩은 부모 클래스의 메서드를 자식 클래스에서 같은 이름으로 재정의하는 것입니다. 실기에서 "출력값은?" 형태로 단골 출제됩니다.
class Animal {
void speak() {
System.out.println("...");
}
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("멍멍!"); // 오버라이딩
}
}
class Cat extends Animal {
@Override
void speak() {
System.out.println("야옹~"); // 오버라이딩
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog(); // 다형성 — Animal 타입으로 Dog 객체 생성
a.speak(); // ?
Animal b = new Cat();
b.speak(); // ?
}
}
🔍 코드 추적
Animal a = new Dog() — 타입은 Animal이지만 실제 객체는 Doga.speak() → 실제 객체(Dog)의 speak() 실행 → 멍멍!b.speak() → 실제 객체(Cat)의 speak() 실행 → 야옹~이것이 다형성(Polymorphism)입니다. 변수 타입이 아니라 실제 객체 타입의 메서드가 실행됩니다.
③ 오버로딩 vs 오버라이딩 구분
| 구분 | 오버로딩(Overloading) | 오버라이딩(Overriding) |
|---|---|---|
| 정의 | 같은 이름, 매개변수가 다른 메서드 여러 개 | 부모 메서드를 자식이 재정의 |
| 위치 | 같은 클래스 안 | 부모·자식 클래스 간 |
| 반환 타입 | 달라도 됨 | 같아야 함 |
| 예시 | add(int a), add(int a, int b) | @Override void speak() |
④ 인터페이스와 추상 클래스
interface Flyable {
void fly(); // 구현 없음, 반드시 오버라이딩 필요
}
abstract class Vehicle {
abstract void move(); // 추상 메서드 — 반드시 오버라이딩
void stop() { // 일반 메서드 — 그대로 상속 가능
System.out.println("정지");
}
}
class Airplane extends Vehicle implements Flyable {
@Override
public void move() { System.out.println("활주로 이동"); }
@Override
public void fly() { System.out.println("비행 중"); }
}
public class Main {
public static void main(String[] args) {
Airplane ap = new Airplane();
ap.move(); // 활주로 이동
ap.fly(); // 비행 중
ap.stop(); // 정지 (Vehicle에서 상속)
}
}
🎯 인터페이스 vs 추상 클래스 차이
| 인터페이스 | 추상 클래스 | |
|---|---|---|
| 다중 구현 | ✅ 여러 개 implements 가능 | ❌ 단일 extends만 |
| 일반 메서드 | default 메서드만 가능 | ✅ 일반 메서드 포함 가능 |
| 생성자 | ❌ 없음 | ✅ 있음 |
⑤ static과 인스턴스 변수
class Counter {
static int count = 0; // 모든 객체가 공유
int id;
Counter() {
count++;
id = count;
}
}
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println(Counter.count); // ?
System.out.println(c1.id); // ?
System.out.println(c3.id); // ?
}
}
🔍 코드 추적
c1 생성: count++ → count=1, c1.id=1c2 생성: count++ → count=2, c2.id=2
c3 생성: count++ → count=3, c3.id=3
Counter.count → 3c1.id → 1c3.id → 3
Python
Python은 문법이 간결해서 비교적 읽기 쉽습니다. 시험에서는 리스트 조작, 슬라이싱, 반복문, 함수가 주로 나와요. 최근에는 람다식과 리스트 컴프리헨션도 출제됩니다.
① 리스트와 슬라이싱
a = [1, 2, 3, 4, 5]
print(a[0]) # 1 (첫 번째)
print(a[-1]) # 5 (마지막)
print(a[1:3]) # [2, 3] (인덱스 1 이상, 3 미만)
print(a[::2]) # [1, 3, 5] (2칸씩 건너뜀)
print(a[::-1]) # [5, 4, 3, 2, 1] (역순)
a.append(6) # 끝에 추가 → [1,2,3,4,5,6]
a.insert(0, 0) # 0번 위치에 0 삽입 → [0,1,2,3,4,5,6]
a.pop() # 마지막 제거 → [0,1,2,3,4,5]
a.remove(3) # 값 3 제거 → [0,1,2,4,5]
💡 슬라이싱 공식
start부터 end-1까지, step 간격으로 가져옵니다.
생략하면 → start=0, end=끝, step=1
a[start:end:step]start부터 end-1까지, step 간격으로 가져옵니다.
생략하면 → start=0, end=끝, step=1
② 반복문과 조건문
# for문 — range
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i, end=' ')
# 출력: 1 2 3 4 5
# 리스트 순회
fruits = ['사과', '바나나', '포도']
for fruit in fruits:
print(fruit)
# enumerate — 인덱스와 값 동시에
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 사과
# 1 바나나
# 2 포도
③ 함수와 기본값 매개변수
def greet(name, greeting='안녕하세요'):
print(f"{greeting}, {name}!")
greet('홍길동') # 안녕하세요, 홍길동!
greet('이순신', '반갑습니다') # 반갑습니다, 이순신!
④ 람다(lambda)와 map/filter
# 람다 — 이름 없는 함수
square = lambda x: x ** 2
print(square(5)) # 25
# map — 리스트 각 원소에 함수 적용
nums = [1, 2, 3, 4, 5]
result = list(map(lambda x: x * 2, nums))
print(result) # [2, 4, 6, 8, 10]
# filter — 조건에 맞는 원소만 추출
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # [2, 4]
⑤ 리스트 컴프리헨션 — 최근 출제 증가
# 기본 형태: [표현식 for 변수 in 이터러블 if 조건]
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 조건 포함
even_sq = [x**2 for x in range(1, 11) if x % 2 == 0]
print(even_sq) # [4, 16, 36, 64, 100]
🔍 리스트 컴프리헨션 추적
[x**2 for x in range(1, 6)]x=1: 1² = 1
x=2: 2² = 4
x=3: 3² = 9
x=4: 4² = 16
x=5: 5² = 25
결과 → [1, 4, 9, 16, 25]
⑥ 딕셔너리
student = {'이름': '홍길동', '성적': 90, '학과': '컴공'}
print(student['이름']) # 홍길동
print(student.get('학년', 1)) # 키가 없으면 기본값 1 반환
student['학년'] = 3 # 추가
del student['학과'] # 삭제
for key, value in student.items():
print(f"{key}: {value}")
🧩 실전 문제 풀어보기
📝 문제 1 — C언어
아래 코드의 출력 결과를 쓰시오.
아래 코드의 출력 결과를 쓰시오.
#include <stdio.h>
int func(int n) {
if (n == 0) return 0;
return n + func(n - 1);
}
int main() {
printf("%d\n", func(5));
}
🔍 풀이
func(5) = 5 + func(4)func(4) = 4 + func(3)
func(3) = 3 + func(2)
func(2) = 2 + func(1)
func(1) = 1 + func(0)
func(0) = 0 ← 종료
1+0=1 → 2+1=3 → 3+3=6 → 4+6=10 → 5+10= 15
📝 문제 2 — Java
아래 코드의 출력 결과를 쓰시오.
아래 코드의 출력 결과를 쓰시오.
class A {
int x = 10;
void print() { System.out.println("A: " + x); }
}
class B extends A {
int x = 20;
@Override
void print() { System.out.println("B: " + x); }
}
public class Main {
public static void main(String[] args) {
A obj = new B();
obj.print();
System.out.println(obj.x);
}
}
🔍 풀이
A obj = new B() — 타입은 A, 실제 객체는 Bobj.print() → 메서드는 실제 객체(B) 기준 → B: 20obj.x → 필드는 참조 타입(A) 기준 → 10⚠ 메서드는 다형성 적용되지만, 필드(변수)는 다형성 적용 안 됨!
📝 문제 3 — Python
아래 코드의 출력 결과를 쓰시오.
아래 코드의 출력 결과를 쓰시오.
data = [3, 1, 4, 1, 5, 9, 2, 6] result = sorted(set(data), reverse=True) print(result[:3])
🔍 풀이
set(data) → 중복 제거 → {1, 2, 3, 4, 5, 6, 9}sorted(..., reverse=True) → 내림차순 → [9, 6, 5, 4, 3, 2, 1][:3] → 앞 3개 → [9, 6, 5]
📚 프로그래밍 실기 고득점 전략 3가지
① 손으로 직접 추적하세요. 변수 값이 바뀔 때마다 종이에 표로 적어가며 따라가는 게 가장 확실합니다. 머릿속으로만 계산하면 실수합니다.
② C언어는 포인터·재귀, Java는 상속·다형성에 집중하세요. 이 두 테마가 전체 프로그래밍 문제의 절반 이상을 차지합니다.
③ Python은 슬라이싱 인덱스를 정확히 익히세요.
① 손으로 직접 추적하세요. 변수 값이 바뀔 때마다 종이에 표로 적어가며 따라가는 게 가장 확실합니다. 머릿속으로만 계산하면 실수합니다.
② C언어는 포인터·재귀, Java는 상속·다형성에 집중하세요. 이 두 테마가 전체 프로그래밍 문제의 절반 이상을 차지합니다.
③ Python은 슬라이싱 인덱스를 정확히 익히세요.
a[1:3]이 인덱스 1~2(3 미포함)라는 것, a[::-1]이 역순이라는 것을 헷갈리면 안 됩니다.