함수·매개변수·재귀
호출마다 지역변수와 반환 위치를 따로 기록한다.
실기 학습 목표
호출마다 지역변수와 반환 위치를 따로 기록한다.
핵심 이론
함수는 인수 전달 → 지역 처리 → 반환의 흐름이다. 지역변수와 같은 이름의 전역변수는 유효 범위에 따라 구별한다.
C의 기본 인수 전달은 값 복사다. 포인터 값을 전달하면 그 포인터가 가리키는 대상은 바꿀 수 있지만 호출자의 포인터 변수 자체를 바꾸려면 추가 간접 참조 등이 필요하다.
Java도 값 전달이며 객체 인수에서는 참조값이 복사된다. 객체 내부 변경과 매개변수를 새 객체로 재대입하는 것은 효과가 다르다.
재귀는 종료 조건을 먼저 확인한다. 호출 전 출력은 내려가며, 호출 뒤 출력은 복귀하며 실행된다. f(3)→f(2)→f(1) 호출과 f(1)→f(2)→f(3) 반환을 별도로 그린다.
개념 도식
함수 호출마다 별도 계산 공간이 생긴다
함수의 매개변수와 지역변수는 호출마다 구별한다. 재귀는 같은 함수 이름을 다시 사용하지만 모든 호출이 하나의 지역변수를 공유하는 방식이 아니다. 호출 스택에 인수와 아직 계산하지 못한 식을 적으면 어느 호출로 돌아가야 하는지 분명해진다. static·전역 변수는 별도로 공유 상태에 표시한다.
f(n) = n <= 1 ? 1 : n * f(n-1)에서 f(3)은 다음과 같이 풀린다.
| 단계 | 아직 남은 계산 | 반환 |
|---|---|---|
| f(3) 진입 | 3 × f(2) | 대기 |
| f(2) 진입 | 2 × f(1) | 대기 |
| f(1) 종료 조건 | 더 호출하지 않음 | 1 |
| f(2) 복귀 | 2 × 1 | 2 |
| f(3) 복귀 | 3 × 2 | 6 |
출력이 재귀 호출 앞에 있으면 내려갈 때, 뒤에 있으면 돌아올 때 출력된다. 반환값과 출력 문자열은 따로 기록한다. Java·Python의 f(n-1)+f(n-2)는 왼쪽 호출을 끝낸 뒤 오른쪽 호출로 이동한다. C에서는 +의 양쪽 평가 순서가 항상 고정되는 것은 아니므로 공유 상태를 바꾸는 코드의 순서를 임의로 단정하지 않는다.
인수 전달은 언어별로 확인한다. C의 정수 인수 변경은 호출자의 정수를 바꾸지 않지만 전달받은 주소를 역참조하면 원래 저장 칸을 바꿀 수 있다. Java는 참조값도 값으로 전달한다. Python은 매개변수가 같은 객체를 가리킬 수 있다. 어느 경우든 변수의 재대입과 공유 객체 내부 변경을 구별해야 한다.
풀이 예시
다음 C17 프로그램이 표준 출력에 기록하는 내용을 쓰시오. 마지막 줄바꿈의 유무는 답안에서 구별하지 않는다.
#include <stdio.h>
int down(int n);
int cross(int n) {
if (n <= 1) return n + 1;
return down(n - 2) + n;
}
int down(int n) {
if (n <= 1) return 1;
return cross(n - 1) - 1;
}
int main(void) {
printf("%d:%d\n", cross(6), down(5));
return 0;
}
예시 정답
9:4
풀이 과정
cross(6)=down(4)+6이고 down(4)=cross(3)−1=down(1)+3−1=3이므로 첫 결과는 9이다. down(5)=cross(4)−1=down(2)+4−1이고 down(2)=cross(1)−1=1이므로 두 번째 결과는 4이다. 두 함수의 서로 다른 기저 조건을 각각 적용해야 한다.
답안 점검
위 풀이 예시의 답을 가린 뒤, 핵심 이론의 규칙을 적용해 직접 풀어 보세요. 코드와 계산 문제는 중간값·단위·최종 출력의 순서를, 용어 문제는 지문의 핵심 단서와 답의 의미를 점검하세요. 해설과 다른 부분이 있으면 어느 조건을 놓쳤는지 확인하고 연결된 실기 문제로 다시 연습하세요.