정보처리기사 문제는 쓸모가 많다.

오늘 친구의 정보처리기사 실기시험 대비를 봐주다가, 오답노트를 같이 해줬는데

오랜만에 C언어 포인터와 Java의 객체지향 개념을 문제풀이와 함께 정리해봤다.


함수 포인터, 안에서 밖으로 읽기

한눈에 봐도 난해한 이 문법은 함수포인터라고 한다.

int* (*fn)(int*);

변수 이름부터 시작해서 바깥으로 읽어나가면 자연스럽게 해석이 된다.

  1. fn : 변수 이름이다.
  2. (*fn) : 포인터라는 의미다. *fn()(*fn)()은 호출과 포인터 선언으로 의미가 완전히 다르니 괄호가 필수다.
  3. (*fn)(int*) : int*를 매개변수로 받는 함수를 가리키는 포인터다.
  4. 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와 관련된 출력이 나왔을 것이다.


정처기를 합격한 지 시간이 제법 흘렀다. 그럼에도 예전보다 지금 이런 코드들의 뼈대가 더 선명하게 읽히는 걸 보면, 문제들을 겪으며 나도 모르는 새 조금은 성장해 있었나 보다. 정말 기분 좋은 발견이다.