강좌 & 팁
재귀 호출을 가끔 사용할 때가 있습니다. 수학 함수 중 팩토리얼(Factorial) 값을 구하는 함수가 대표적이죠. 예제로도 많이 사용하는데, 당연한 얘기입니다만, 재귀 호출은 많은 곳에서 사용합니다. 예를 들어 디렉토리 안의 모든 파일을 뒤진 다든지, 그래픽에서는 특정 영역을 지정된 색으로 채울 때에도 재귀 호출은 매우 편합니다.
우선 팩토리얼을 구하는 루틴을 볼까요?
int factorial( int n_value){ if ( 1 < n_value){ return factorial( n_value -1) * n_value; } else { return 1; } } int main( void){ printf( "10!= %d\n", factorial( 10)); }
위의 루틴을 보시면서 어떤 생각이 드시나요? 어떤 부분이 제일 먼저 보이십니까?
물론, 잘 작동되는 코드이지만, 저 개인적인 생각으로는 바람직한 코드가 못 된다고 생각합니다. 뭐가? 잘 되지 않는가?라고 반문하시겠습니다. 또는 if 절에 " 1 < " 이렇게 보다는 " 1 == " 로 해야 되지 않겠는가 하는 분도 게실 것입니다.
모두 맞는 말씀입니다만, 제가 드리고 싶은 말씀은 재귀 호출은 매우 조심해야 하는 함수라는 점입니다. 저는 재귀호출을 만들 때는 (1) 반드시 바쪄 나가는 부분을 먼저 만들고, (2) 그 부분이 눈에 띄도록 될 수 있으면 위에 놓습니다. 그것이 좀 지나치더라도 그렇게 하는 것이 안전합니다. 왜냐하면 재귀호출은 매우 편한 방법입니다만, 자칫 무한으로 빠질 수 있고, Stack Overflow 에러를 발생할 수 있습니다.
그러므로 재귀호출은 만들 때부터 언제 재귀호출을 종료할지 조건부터 따져야 하고, 재귀호출을 검토할 때에는 언제 빠져 나가는 지를 제일 먼저 확인해야 안전합니다. 즉, 최종 return이 언제 걸리는지를 정확히 알아야 한다는 것이죠. 그래서 보기 좋게, 또는 최적화를 위해 코드 양을 줄이기 보다는 아래와 같이 여러 행이 되어도 확실하게 보여 주는 것이 좋습니다.
int factorial( int n_value){
// n_valure가 1과 같다면 복귀한다.
// 재귀 호출은 여기에서 종료된다.
if ( 1 == n_value){
return 1;
}
// 재귀 호출을 이용한다.
return factorial( n_value -1) * n_value;
}
int main( void){
printf( "10!= %d\n", factorial( 10));
}
때때로 언저 재귀호출이 종료되는지 한 눈에 보이지 않는 코드를 볼 때가 있습니다. 재귀함수 루틴에서 계속 같은 문제가 발생하면 다행인데, 조건에 따라 발생할 때가 있고 발생하지 않는 경우가 생긴다면, 일반 루틴보다 재귀호출 루틴이 더욱 버그가 잘 안 보입니다. 그래서 주위 코드를 의심하게 되는데, 이런 경험으로 재귀호출 작성에 대한 말씀을 드립니다.