4과목 프로그래밍언어활용 ① — 언어
이 과목이 과락의 주범이다. 기출 160문항(과목4)에서 지문에 실제로 등장한 횟수를 세면
int(52) ·main(23) ·printf(19) ·char(18) ·for(24) · Java(15) · Python(11) — 코드를 직접 읽고 출력을 계산하는 문항이 회차당 3~6개이고 그 대부분이 이 과목에 몰려 있다.이 과목은 절반이 언어, 절반이 운영체제·네트워크다. 분량이 커서 편을 나눴다 — 운영체제·네트워크는 다음 편에서 다룬다.
언어 문항은 외워서 풀리지 않는다. 종이에 변수 표를 그려 한 줄씩 굴리는 것이 유일한 방법이고, 이 편은 그 굴리는 절차를 예제마다 적었다.
0. 이 과목의 지형
언어 특성 활용 자료형 · 변수 · 연산자 · 제어문 · 함수 ← 코드 문항
C · Java · Python 문법과 출력 계산 ← 코드 문항
모듈 구현 모듈화 · 결합도 · 응집도 · 재사용
라이브러리·예외 표준 라이브러리 · 예외 처리
운영체제 · 네트워크 (다음 편)
1. 언어 일반
언어의 분류
| 분류 | 언어 |
|---|---|
| 절차적(명령형) | C, FORTRAN, COBOL, PASCAL |
| 객체지향 | Java, C++, C#, Smalltalk |
| 함수형 | LISP, Haskell, Scala |
| 논리형(선언형) | PROLOG |
| 스크립트 | JavaScript, Python, PHP, ASP, JSP, Ruby, Perl |
함정 — PROLOG 는 논리형, LISP 는 함수형이다. 이 둘을 바꿔 낸 보기가 단골. 그리고 JSP·ASP·PHP 는 서버 측 스크립트, JavaScript 는 클라이언트 측에서 출발했다.
컴파일러와 인터프리터
| 컴파일러 | 인터프리터 | |
|---|---|---|
| 번역 단위 | 전체를 한 번에 | 한 행씩 |
| 목적 코드 | 생성한다 | 생성하지 않는다 |
| 실행 속도 | 빠르다 | 느리다 |
| 메모리 | 목적 코드 공간 필요 | 적게 든다 |
| 예 | C, C++, FORTRAN | Python, JavaScript, BASIC |
번역 과정
원시 코드 → 어휘 분석(토큰 분리) → 구문 분석(파싱·구문 트리) → 의미 분석
→ 최적화 → 목적 코드 생성 → 링커(라이브러리 결합) → 로더(메모리 적재) → 실행
함정 — 링커는 목적 코드와 라이브러리를 묶어 실행 파일을 만들고, 로더는 그것을 메모리에 올린다. 순서와 역할을 바꿔 낸다.
변수와 식별자 (식별자 2회 · 예약어 2회)
식별자 규칙 영문자·숫자·밑줄(_) 사용 / 첫 글자에 숫자 불가 / 예약어 사용 불가
대소문자 구분 / 공백·특수문자 불가
함정 —
2sum(숫자로 시작),int(예약어),my var(공백),total-sum(하이픈)은 모두 부적합._count,sum2,myVar는 적합하다.
기억 클래스(C)
| 클래스 | 저장 위치 | 생존 |
|---|---|---|
| auto | 스택 | 블록을 벗어나면 소멸 (기본값) |
| static | 데이터 영역 | 프로그램 종료까지 유지, 초기값 0 |
| register | 레지스터 | 빠른 접근 요청 |
| extern | 데이터 영역 | 다른 파일의 전역 변수를 참조 |
static지역 변수는 함수를 다시 호출해도 값이 유지된다. 이 성질로 출력 계산 문항이 나온다.
스코프
지역(local) 선언된 블록 안에서만
전역(global) 파일 전체에서 (함수 밖에 선언)
같은 이름이면 안쪽(지역)이 우선한다
2. 연산자 — 우선순위가 계산의 출발점
우선순위 (높은 것부터)
① ( ) [ ] . -> 괄호·배열·멤버
② ! ~ ++ -- (형변환) * & sizeof 단항
③ * / % 산술(곱·나눗셈)
④ + - 산술(덧셈·뺄셈)
⑤ << >> 시프트
⑥ < <= > >= 관계
⑦ == != 등가
⑧ & → ^ → | 비트 AND → XOR → OR
⑨ && → || 논리 AND → OR
⑩ ? : 삼항
⑪ = += -= *= /= %= 대입 (오른쪽 → 왼쪽 결합)
⑫ , 쉼표
가장 자주 쓰이는 함정 —
&&가||보다 먼저다. 그리고 관계 연산자가 등가 연산자보다 먼저다.a + b * c는a + (b*c).
정수 나눗셈과 나머지
int a = 7, b = 2;
printf("%d %d %d", a/b, a%b, a*1.0/b); // 3 1 3.5
정수끼리 나누면 소수점이 버려진다. 이 한 줄이 오답의 가장 큰 원인이다. 음수 나머지는 처리 방식이 언어마다 달라 시험에서는 잘 나오지 않는다.
비트 연산자
& AND 둘 다 1이면 1 | OR 하나라도 1이면 1
^ XOR 다르면 1 ~ NOT 비트 반전
<< 왼쪽 시프트 = ×2 씩 >> 오른쪽 시프트 = ÷2 씩
int a = 12; // 0000 1100
printf("%d", a & 10); // 0000 1010 → 0000 1000 = 8
printf("%d", a | 10); // → 0000 1110 = 14
printf("%d", a ^ 10); // → 0000 0110 = 6
printf("%d", a << 2); // 12 × 4 = 48
printf("%d", a >> 2); // 12 ÷ 4 = 3
계산 요령 — 2진수로 세로로 적어 놓고 비트를 맞춰 계산한다. 시프트는 곱하기·나누기로 바꿔 계산.
증감 연산자 — 전위와 후위
int i = 5, r;
r = i++; // r = 5, i = 6 (먼저 쓰고 나중에 증가)
i = 5;
r = ++i; // r = 6, i = 6 (먼저 증가하고 사용)
주의 —
printf("%d %d", i++, ++i)처럼 같은 식에서 같은 변수를 두 번 증감하는 형태는 C 표준이 결과를 정의하지 않는다. 기출은 대개 문장을 나눠 출제한다.
3. 제어문
if (조건) { } else if (조건) { } else { }
switch (값) {
case 1: ... break; // break 를 빼면 아래로 흘러 내려간다(fall-through)
case 2: ... break;
default: ...
}
for (초기식; 조건식; 증감식) { }
while (조건) { }
do { } while (조건); // 조건이 거짓이어도 최소 한 번 실행
| 키워드 | 동작 |
|---|---|
| break | 반복문·switch 를 완전히 빠져나온다 (5회 출제) |
| continue | 이번 회차만 건너뛰고 다음 반복으로 (7회 출제) |
| goto | 지정 레이블로 점프 — 가독성 때문에 권장되지 않는다 |
함정 둘 — ①
switch에서break누락 시 다음 case 로 계속 실행된다. ②do-while은 조건과 무관하게 한 번은 실행된다.
반복 횟수 세기
for (i = 1; i <= 10; i += 3) // i = 1, 4, 7, 10 → 4회
for (i = 0; i < 10; i++) // 0~9 → 10회
for (i = 10; i > 0; i -= 2) // 10,8,6,4,2 → 5회
4. C 언어
출력 서식
| 서식 | 의미 |
|---|---|
%d | 10진 정수 |
%f | 실수 (기본 소수점 6자리) |
%.2f | 소수점 2자리까지 |
%c | 문자 하나 |
%s | 문자열 |
%x %o | 16진 · 8진 |
%5d | 폭 5칸, 오른쪽 정렬 |
%-5d | 폭 5칸, 왼쪽 정렬 |
배열과 문자열
int a[5] = {1, 2, 3}; // 나머지는 0 으로 채워진다 → {1,2,3,0,0}
char s[] = "hello"; // 크기는 6 ('\0' 포함)
printf("%d", sizeof(s)); // 6
printf("%d", strlen(s)); // 5 ← 널 문자를 세지 않는다
| 함수 | 기능 |
|---|---|
strlen(s) | 길이 (널 문자 제외) |
strcpy(d, s) | 복사 |
strcat(d, s) | 이어 붙이기 |
strcmp(a, b) | 같으면 0, 사전순 앞이면 음수 |
함정 —
sizeof는 널 문자를 포함,strlen은 제외한다. 이 차이가 그대로 문항이 된다. 2차원 배열a[2][3]의 원소 수는 6이고,a[i][j]는 행 i, 열 j.
포인터
int a = 10;
int *p = &a; // p 는 a 의 주소를 갖는다
printf("%d", *p); // 10 (역참조 = 그 주소의 값)
*p = 20; // a 가 20 이 된다
printf("%d", a); // 20
배열과 포인터는 같은 것을 다르게 쓴 것이다.
int arr[3] = {10, 20, 30};
int *p = arr; // 배열 이름은 첫 원소의 주소
arr[1] == *(arr + 1) == p[1] == *(p + 1) // 모두 20
포인터 연산의 핵심 —
p + 1은 1 바이트가 아니라 자료형 크기만큼 이동한다.int*라면 4바이트 뒤. 이 성질을 묻는 문항이 나온다.
함수의 값 호출과 참조 호출
void swapWrong(int x, int y) { int t = x; x = y; y = t; } // 값 호출 — 원본 안 바뀜
void swapRight(int *x, int *y) { int t = *x; *x = *y; *y = t; } // 주소를 넘겨야 바뀐다
int a = 1, b = 2;
swapWrong(a, b); // a=1, b=2 그대로
swapRight(&a, &b); // a=2, b=1 바뀐다
이 예제가 그대로 출제된다. 값 호출(call by value)은 복사본을 넘기므로 원본이 안 바뀐다.
구조체와 공용체
struct Point { int x; int y; }; // 멤버가 각자 공간을 갖는다
union Data { int i; char c; }; // 멤버가 같은 공간을 공유 → 크기 = 가장 큰 멤버
struct Point p = {3, 4};
printf("%d", p.x); // 3
struct Point *pp = &p;
printf("%d", pp->y); // 4 (포인터는 -> 로 접근)
동적 메모리
int *p = (int*)malloc(sizeof(int) * 5); // 힙에 정수 5개 공간
free(p); // 반드시 해제 (안 하면 메모리 누수)
calloc 은 0으로 초기화하고, realloc 은 크기를 바꾼다.
전처리기 — 매크로 함정
#define SQ(x) x * x
printf("%d", SQ(2 + 3)); // 2 + 3 * 2 + 3 = 11 ← 25 가 아니다!
#define SQ2(x) ((x) * (x))
printf("%d", SQ2(2 + 3)); // 25 ← 괄호를 씌워야 한다
매크로는 함수가 아니라 문자열 치환이다. 괄호가 없으면 우선순위가 어긋난다.
5. Java
클래스와 객체
class Person {
private String name; // 필드
Person(String name) { this.name = name; } // 생성자
public String getName() { return name; }
}
Person p = new Person("홍길동");
접근 제어자 — 좁은 것부터
private < default(생략) < protected < public
같은 클래스 같은 패키지 +상속 자식 전부
상속·오버라이딩·오버로딩
class Animal { void sound() { System.out.println("..."); } }
class Dog extends Animal {
@Override void sound() { System.out.println("멍멍"); } // 오버라이딩 (재정의)
}
Animal a = new Dog();
a.sound(); // "멍멍" ← 실제 객체 타입의 메서드가 실행된다(다형성)
| 오버로딩(Overloading) | 오버라이딩(Overriding) | |
|---|---|---|
| 무엇 | 같은 이름, 다른 매개변수 | 부모 메서드를 재정의 |
| 결정 시점 | 컴파일 시 | 실행 시 |
| 조건 | 매개변수 타입·개수가 달라야 | 이름·매개변수·반환형이 같아야 |
함정 — 반환형만 다른 것은 오버로딩이 아니다. 그리고 오버라이딩은 접근 제어자를 더 좁게 만들 수 없다.
static · final · this · super
static 객체 없이 클래스 이름으로 접근. 모든 객체가 공유
final 변수 = 상수, 메서드 = 재정의 금지, 클래스 = 상속 금지
this 자기 객체 참조 / this(...) 는 자기 생성자 호출
super 부모 객체 참조 / super(...) 는 부모 생성자 호출
추상 클래스와 인터페이스
| 추상 클래스 | 인터페이스 | |
|---|---|---|
| 키워드 | abstract class | interface |
| 상속 | 단일 상속 | 다중 구현 가능 |
| 구현 | 일반 메서드도 가질 수 있다 | 추상 메서드 중심(+default) |
| 목적 | 공통 구현을 물려준다 | 규약을 정한다 |
예외 처리
try {
int r = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
System.out.println("0으로 나눔");
} finally {
System.out.println("항상 실행"); // 예외가 나든 안 나든 실행된다
}
Throwable ┬ Error — 복구 불가 (OutOfMemoryError)
└ Exception ┬ RuntimeException — 컴파일러가 강제하지 않음(unchecked)
└ 그 외 — try-catch 또는 throws 필수(checked)
함정 —
finally는return이 있어도 실행된다.NullPointerException·ArrayIndexOutOfBoundsException·ArithmeticException은 unchecked,IOException·ClassNotFoundException은 checked 다.
문자열
String a = "hello";
String b = "hello";
String c = new String("hello");
a == b // true ← 문자열 상수 풀에서 같은 객체를 공유
a == c // false ← new 는 새 객체
a.equals(c) // true ← 값 비교는 equals
String s = "a";
s += "b"; // 새 객체가 만들어진다 (String 은 불변)
| 클래스 | 가변 | 동기화 |
|---|---|---|
String | 불변 | — |
StringBuilder | 가변 | 없음 (빠름) |
StringBuffer | 가변 | 있음 (스레드 안전) |
배열과 출력 계산 예제
int[] arr = {3, 1, 4, 1, 5};
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 1) sum += arr[i];
}
System.out.println(sum); // 3 + 1 + 1 + 5 = 10
굴리는 절차 — 변수 표를 만들고 한 회차씩 적는다.
i=0 arr[0]=3 홀수 sum=3
i=1 arr[1]=1 홀수 sum=4
i=2 arr[2]=4 짝수 sum=4
i=3 arr[3]=1 홀수 sum=5
i=4 arr[4]=5 홀수 sum=10
6. Python
자료형 네 개의 성격
| 자료형 | 표기 | 순서 | 변경 | 중복 |
|---|---|---|---|---|
| 리스트(list) | [1,2,3] | ✅ | ✅ | ✅ |
| 튜플(tuple) | (1,2,3) | ✅ | ❌ 불변 | ✅ |
| 딕셔너리(dict) | {'a':1} | (삽입 순) | ✅ | 키 유일 |
| 집합(set) | {1,2,3} | ❌ | ✅ | ❌ 중복 제거 |
함정 — 튜플은 원소를 바꿀 수 없다(
t[0]=9는 오류). 집합은 중복이 자동 제거되고 순서가 없다.
인덱싱과 슬라이싱 — 계산 문항 단골
a = [10, 20, 30, 40, 50]
a[0] # 10
a[-1] # 50 음수는 뒤에서부터
a[1:3] # [20, 30] ← 끝 인덱스는 제외한다
a[:3] # [10, 20, 30]
a[2:] # [30, 40, 50]
a[::2] # [10, 30, 50] 간격 2
a[::-1] # [50, 40, 30, 20, 10] 역순
핵심 함정 — 슬라이싱의 끝 인덱스는 포함되지 않는다.
a[1:3]은 2개다. 문자열도 같은 규칙이 적용된다:"python"[1:4]→"yth".
range 와 반복
range(5) # 0 1 2 3 4
range(1, 5) # 1 2 3 4
range(1, 10, 2) # 1 3 5 7 9
range(5, 0, -1) # 5 4 3 2 1
for i in range(3):
print(i, end=' ') # 0 1 2
함수와 람다
def add(a, b=10): # 기본값 매개변수
return a + b
add(5) # 15
f = lambda x: x * 2
list(map(lambda x: x*2, [1,2,3])) # [2, 4, 6]
list(filter(lambda x: x%2==0, [1,2,3,4])) # [2, 4]
문자열·기타
s = "Hello World"
s.upper() # 'HELLO WORLD'
s.split() # ['Hello', 'World']
s.replace('l','L')
len(s) # 11
'-'.join(['a','b']) # 'a-b'
a, b = 1, 2
a, b = b, a # 스왑이 한 줄로 된다
들여쓰기가 문법이다. 블록을 중괄호가 아니라 들여쓰기로 구분하므로,
들여쓰기가 어긋나면 IndentationError 가 난다.
출력 계산 예제
a = [1, 2, 3, 4, 5]
r = 0
for x in a:
if x % 2 == 0:
continue # 짝수는 건너뛴다
r += x
print(r) # 1 + 3 + 5 = 9
7. 모듈 구현 — 이 과목에서도 결합도·응집도가 나온다
기출에서 결합도 13회 · 응집도 11회가 과목4 범위에서 등장했다. 자세한 표는 1과목 6절에 있고, 여기서는 결론만 다시 붙인다.
결합도 자료 < 스탬프 < 제어 < 외부 < 공통 < 내용 (낮을수록 좋다)
응집도 기능적 > 순차적 > 통신적 > 절차적 > 시간적 > 논리적 > 우연적 (높을수록 좋다)
모듈화의 목적 — 재사용성·유지보수성 향상, 복잡도 감소, 오류 파급 최소화. 팬인은 높게, 팬아웃은 낮게.
8. 라이브러리와 예외 처리
표준 라이브러리 언어가 기본 제공 (C: stdio.h·stdlib.h·string.h·math.h / Java: java.lang·util)
외부 라이브러리 따로 설치해 사용
| C 헤더 | 담긴 것 |
|---|---|
stdio.h | 입출력 — printf, scanf, fopen |
stdlib.h | 형변환·동적 메모리 — atoi, malloc, rand |
string.h | 문자열 — strlen, strcpy, strcmp |
math.h | 수학 — sqrt, pow, abs |
예외 처리의 원칙 — 예외를 무시하지 않는다, 구체적인 예외를 먼저 잡는다,
자원은 finally(또는 try-with-resources)에서 해제한다.
9. 코드 문항 대처법
① 변수 표를 그린다 변수 이름을 가로로 적고, 회차마다 한 줄씩 값을 적는다
② 반복 횟수를 먼저 센다 for 문의 시작·끝·증감으로 몇 번 도는지 확정
③ 정수 나눗셈을 표시한다 / 가 나오면 소수점 버림 여부를 즉시 확인
④ 전위·후위를 동그라미로 ++i 와 i++ 를 헷갈리면 전부 틀린다
⑤ 배열 인덱스는 0부터 길이 n 이면 마지막 인덱스는 n-1
⑥ Python 슬라이싱은 끝 제외
⑦ 값 호출인지 참조 호출인지 포인터·주소(&)가 있으면 원본이 바뀐다
시간이 부족할 때 — 코드 문항은 회차당 3~6개(전체의 3~6%)다. 계산이 오래 걸리면 표시하고 넘어간 뒤, 용어 문항을 먼저 확보하고 돌아온다. 다만 과목4 안에서는 20문항 중 3~5문항이라 통째로 버리면 과락 위험이 커진다.
10. 함정 정리
정수 / 정수 = 정수.
7/2는 3이다.
sizeof는 널 문자 포함,strlen은 제외.
값 호출은 원본을 바꾸지 못한다. 주소(
&)를 넘겨야 바뀐다.
매크로는 문자열 치환이다.
#define SQ(x) x*x에2+3을 넣으면 11.
switch의break누락 → 아래 case 로 흘러간다.
do-while은 최소 한 번 실행.
Java
String은 불변이고==는 참조 비교,equals가 값 비교.
오버로딩은 반환형만 달라서는 성립하지 않는다.
finally는return이 있어도 실행된다.
Python 슬라이싱 끝 인덱스는 제외.
a[1:3]은 2개.
튜플은 불변, 집합은 중복 제거.
PROLOG 는 논리형, LISP 는 함수형.
링커는 실행 파일을 만들고 로더는 메모리에 올린다.
한눈에 정리
- 이 과목은 코드를 굴려야 점수가 나온다. 변수 표를 그리는 습관이 곧 실력이다
- 계산 오답의 최대 원인 셋 — 정수 나눗셈, 전위/후위 증감, Python 슬라이싱 끝 제외
- C 는 포인터와 값/참조 호출, Java 는 문자열·오버라이딩·예외, Python 은 자료형 성격과 슬라이싱
- 연산자 우선순위는 단항 → 산술 → 시프트 → 관계 → 등가 → 비트 → 논리 → 삼항 → 대입
- 언어 분류는 PROLOG(논리) · LISP(함수) · JSP·PHP(서버 스크립트) 를 짝지어 둔다
- 모듈화 문항도 이 과목에서 나온다 — 결합도 낮게, 응집도 높게, 팬인 ↑ 팬아웃 ↓
- 운영체제와 네트워크는 다음 편에서 — 이 과목 20문항의 절반이 거기서 나온다