정보처리기사 문제는 쓸모가 많다. Pt.1
정보처리기사 문제는 쓸모가 많다.
오늘 친구의 정보처리기사 실기시험 대비를 봐주다가, 오답노트를 같이 해줬는데
오랜만에 C언어 포인터와 Java의 객체지향 개념을 문제풀이와 함께 정리해봤다.
함수 포인터, 안에서 밖으로 읽기
한눈에 봐도 난해한 이 문법은 함수포인터라고 한다.
int* (*fn)(int*);
변수 이름부터 시작해서 바깥으로 읽어나가면 자연스럽게 해석이 된다.
fn: 변수 이름이다.(*fn): 포인터라는 의미다.*fn()과(*fn)()은 호출과 포인터 선언으로 의미가 완전히 다르니 괄호가 필수다.(*fn)(int*):int*를 매개변수로 받는 함수를 가리키는 포인터다.int* (*fn)(int*): 그 함수의 반환형이int*이다.
결국 “fn은 int 포인터를 인자로 받아 int 포인터를 반환하는 함수를 가리키는 포인터”라는 뜻이 된다. C의 복잡한 선언을 읽는 가장 정석적인 방법이다.
정처기 기출문제에 나온 코드 형태는 대략 이렇다.
struct fns {
int* (*fn)(int*);
} mine;
int* dummy(int *d) {
return d + 1;
}
int main() {
struct fns mine;
int n[] = {16, 32};
mine.fn = dummy;
printf("%x", *mine.fn(n));
return 0;
}
코드의 흐름을 따라가 보면 생각보다 단순하다.
mine.fn(n)이 실행되면 배열의 첫 번째 원소 주소(n)가 넘어간다. dummy 함수는 d + 1을 반환하니 결국 n + 1의 주소가 나온다. 여기에 *를 붙여 *mine.fn(n)을 평가하면 n[1]의 값인 32가 된다. 이걸 %x로 출력하니 10진수 32가 16진수 20으로 출력된다. 원리만 알면 단순한 치환의 연속이다.
Pass by Value, String과 String[]의 차이
C언어의 포인터를 지나 객체지향으로 넘어오면, 이번엔 ‘참조(Reference)’가 사람을 헷갈리게 한다.
public class Main {
public static void change(String[] data, String s) {
data[0] = s;
s = "Z";
}
public static void main(String[] args) {
String[] data = { "A" };
String s = "B";
change(data, s);
System.out.print(data[0] + s);
}
}
이 코드의 출력은 BB다. 예전 C# 프로그래밍 수업 때 겪었던 복사의 헷갈림이 다시 떠오르는 대목이다.
결론부터 말하면 Java는 오직 ‘Pass by Value(값 전달)’뿐이다. 흔히 객체를 넘길 때 참조가 넘어간다고 해서 Pass by Reference라 착각하지만, 실상은 ‘객체를 가리키는 참조값(메모리 주소의 복사본)’ 자체가 ‘값’으로서 복사되는 것이다.
- 배열 (
data): 참조값이 복사되어 넘어간다. 복사된 참조값도 원본과 같은 배열 객체를 가리키니, 메서드 안에서 요소를 바꾸면 원본도 바뀐다. 전형적인 얕은 복사다. - 문자열 (
s): 마찬가지로 참조값이 복사된다. 하지만 Java의String은 불변(Immutable) 객체다.s = "Z"를 수행하는 순간 기존 객체를 덮어쓰는 게 아니라, “Z”라는 새로운 객체를 만들고 복사된 매개변수s가 거기를 가리키게 된다. 당연히 원본s는 여전히 “B”를 가리키고 있다.
C#도 기본적으로는 Java와 같은 Pass by Value를 따른다. 다만 C#은 ref, out, in 같은 키워드를 통해 진짜 참조 전달을 구현할 수 있다는 게 차이다. 만약 저 코드의 C# 버전에서 ref string s로 넘겼다면 원본 변수 자체가 바뀌어 ZB 혹은 Z와 관련된 출력이 나왔을 것이다.
정처기를 합격한 지 시간이 제법 흘렀다. 그럼에도 예전보다 지금 이런 코드들의 뼈대가 더 선명하게 읽히는 걸 보면, 문제들을 겪으며 나도 모르는 새 조금은 성장해 있었나 보다. 정말 기분 좋은 발견이다.
댓글이 보이지 않으면 GitHub에 로그인한 뒤 새로고침해 주세요. 공개 댓글은 로그인 상태에서 더 안정적으로 표시됩니다.