당신이 이태원의 아주 바쁜 식당에서 음식을 만드는 알바생이라고 생각해보자.
CPU라는 쉐프가 복잡한 식당의 주방에서 주문서를 받고 당신은 절차에 따라 음식을 만든다.
각 주문서는 손님의 취향에 따라 메뉴가 제각각이고 한 요리가 테이블에 서빙되면 주문서는 쓰레기통에 버려진다.
이는 마치 주문서가 지역변수이고, 함수가 완료되면 메모리 할당이 해제되면서 함수가 끝날 때 지역 변수가 폐기되는 것과 같다.

함수에서 반환된 지역 변수의 메모리를 다시 참조하게 되면, 운영체제 또는 C 런타임이 그 영역을 '쓰레기 값(garbage value)'으로 간주한다. 이는 그 영역이 공식적으로는 비어 있으며 언제든지 다른 데이터로 덮어 쓰여질 수 있다는 것을 의미한다. 만약 이전에 함수에서 사용하던 메모리 영역이 아직 다른 용도로 사용되지 않아서 원래 값이 남아 있는 경우, 그 값을 읽었을 때 우연히 '올바른' 값으로 보일 수 있다. 하지만 이는 운이 좋은 경우일 뿐이며, 안정적이거나 예측 가능한 프로그래밍 방식이 아니다.

이런 현상은 특히 반환된 포인터가 가리키는 메모리에 접근할 때 두드러진다. 포인터가 함수의 지역 변수를 가리킬 때, 그 함수가 끝나고 나면 포인터는 '댕글링 포인터(dangling pointer)'가 된다. 즉, 유효하지 않은 메모리 영역을 가리키게 되는 것이다. 이러한 포인터를 통해 메모리에 접근하는 것은 '정의되지 않은 동작(undefined behavior)'을 초래하며, 프로그램의 오류나 보안 취약점을 일으킬 수 있다.
따라서, 지역 변수나 그 메모리를 반환하는 것은 위험하고 피해야 하는 행위이다. 필요한 값이 있으면 항상 그 값을 복사하여 반환하거나, 더 안전하게 관리할 수 있는 malloc 같은 메모리(예: 동적 할당된 메모리)에 값을 저장해야 한다.
<예시>
#include <stdio.h>
int* returnLocalVariableAddress() {
int localVariable = 5;
printf("Local variable inside function: %d\n", localVariable);
return &localVariable; // 경고: 함수가 끝난 후 지역 변수의 주소를 반환
}
int main() {
int* ptr = returnLocalVariableAddress();
// 함수 반환 후, ptr은 해제된 스택 메모리를 가리킴
printf("Value at returned address: %d\n", *ptr); // 정의되지 않은 동작 (Undefined Behavior)
return 0;
}
.
<결과는 A 혹은 B가 될 수 있다.>
결과 A
Local variable inside function: 5
Value at returned address: 5
결과 B
Local variable inside function: 5
Value at returned address: 쓰레기 값 (또는 예측할 수 없는 값)
- returnLocalVariableAddress 함수는 지역 변수 localVariable의 주소를 반환한다. 이 주소는 함수가 종료되면서 해제되는 스택 메모리를 가리키게 된다.
- main 함수에서는 이 주소를 포인터 ptr을 통해 참조한다. 하지만, 이 시점에서 localVariable의 메모리는 공식적으로 해제되어 재사용될 수 있는 상태이다. 따라서 ptr을 통해 접근하는 것은 정의되지 않은 동작(Undefined Behavior)을 초래한다.
- 실행 결과는 컴파일러와 실행 환경에 따라 달라질 수 있다. 때로는 운 좋게도 해제된 메모리에 남아 있던 값이 그대로 출력될 수도 있지만, 이는 안정적이거나 보장된 동작이 아니다. 대부분의 경우, 쓰레기 값이 출력되거나 프로그램이 예상치 못하게 동작할 수 있다.
이 예제는 함수에서 지역 변수의 주소를 반환하는 것이 왜 위험한지를 명확하게 보여준다. 안전하고 예측 가능한 프로그래밍을 위해서는 지역 변수의 값을 필요로 할 때 해당 값을 복사하여 반환하는 방식을 사용해야 한다.
'윤성우의 C Programming' 카테고리의 다른 글
Chapter 27. 파일의 분할과 헤더파일의 디자인 (0) | 2024.02.12 |
---|---|
Chapter 26. 매크로와 선행처리기 (Preprocessor) (1) | 2024.02.12 |
#include <stdlib.h> (0) | 2024.02.11 |
Chapter 25 : 메모리 관리와 메모리의 동적 할당 (0) | 2024.02.11 |
Chapter 23. 구조체와 사용자정의 자료형 2 (1) | 2024.01.28 |