[CS50] 메모리: 메모리 교환, 스택, 힙
❄️ David Malan 교수의 모두를 위한 컴퓨터 과학(CS50 2019)을 바탕으로 정리한 내용입니다.
아래와 같은 코드가 있습니다. 함수 swap은 정수 a와 b를 입력받아 그 값을 바꾸는 일을 수행합니다.
main 함수에서는 x에 1, y에 2를 입력하고 swap 함수를 통해 그 두 값을 바꾸려고 하고 있습니다.
과연 의도대로 잘 바뀌어서 출력이 될까요?
#include <stdio.h>
void swap(int a, int b);
int main(void)
{
int x = 1;
int y = 2;
printf("x = %i, y = %i\n", x, y);
swap(x, y) // ✅
printf("x = %i, y = %i\n", x, y);
}
void swap(int a, int b) // ✅
{
int tmp = a;
a = b;
b = tmp;
}
안타깝게도 위 코드를 컴파일하고 출력해보면 우리 의도와는 다르게 swap 함수를 거친 후에도 x와 y의 값이 바뀌지 않은채 그대로 출력됨을 알 수 있습니다.
x = 1, y = 2
x = 1, y = 2
어떤 이유로 교환되지 않았을까요?
사실 swap 함수는 교환 작업을 제대로 수행하고 있는데요, 문제는 교환하는 대상이 x, y 그 자체가 아닌 함수 내에서 새롭게 정의된 a, b라는 것이었습니다.
a와 b는 각각 x와 y의 값을 복제하여 가지게 됩니다. 서로 다른 메모리 주소에 저장되는 것이죠.
다시 말해서, swap 함수에는 복사본(=”값”)이 전달되기 때문에 swap 함수는 a 와 b를 교환하지만 x와 y가 교환되지는 않는 것이지요.
(swap 함수가 종료될 때 스택 프레임에서 a와 b는 사라집니다.)
아래 그림에서와 같이 메모리 안에는 데이터 저장되는 구역이 나뉘어져 있습니다.
머신 코드 영역에는 우리 프로그램이 실행될 때 그 프로그램이 컴파일된 바이너리가 저장됩니다.
글로벌 영역에는 프로그램 안에서 저장된 전역 변수가 저장됩니다.
힙 영역에는 malloc으로 할당된 메모리의 데이터가 저장됩니다. 그리고 스택에는 프로그램 내의 함수와 관련된 것들이 저장됩니다.
🤔 메모리 영역을 다양하게 나누는 이유는 무엇일까요?
컴퓨터에서 메모리를 텍스트, 데이터, 힙, 스택 네 가지 영역으로 나누는 이유는 프로그램의 실행과 관련된 다양한 요구사항을 충족시키고 메모리 관리를 효율적으로 수행하기 위함입니다.
- 코드 영역에는 (프로그램 실행 시) 프로그램이 컴파일된 바이너리가 저장됩니다.
- 데이터 영역에는 프로그램 안에서 저장된 전역 변수가 저장됩니다.
- 힙 영역에는 malloc을 이용해 동적으로 할당된 메모리의 데이터가 저장됩니다.
- 스택 영역에는 프로그램 내의 함수, 지역 변수와 관련된 것들이 저장됩니다.
이를 바탕으로 다시 생각해보면, 위의 코드에서 a, b, x, y, tmp 모두 스택 영역에 저장되지만 a와 x, b와 y는 그 안에서도 서로 다른 위치에 저장된 변수입니다.
따라서 a와 b를 바꾸는 것은 x와 y를 바꾸는 것에 아무런 영향도 미치지 않는 것이죠.
따라서 아래 그림 및 코드와 같이 a와 b를 각각 x와 y를 가리키는 포인터로 지정함으로써 이 문제를 쉽게 해결할 수 있습니다.
#include <stdio.h>
void swap(int *a, int *b);
int main(void)
{
int x = 1;
int y = 2;
printf("x = %i, y = %i\n", x, y);
swap(&x, &y) // ✅
printf("x = %i, y = %i\n", x, y);
}
void swap(int *a, int *b) // ✅ 인자로 정수의 주소를 받는다
{
int tmp = *a; // *를 통해 a가 가리키는 주소(&x)의 값을 tmp에 저장한다
*a = *b; // b가 가리키는 주소(&y)의 값(=2)을 a가 가리키는 주소(&x)의 값(=1)에 저장한다
*b = tmp; // tmp의 값인 1을 b가 가리키는 주소의 값에 저장한다
}
swap 함수에게 값이 아닌 주소를 넘김으로써 swap 함수가 그 주소로 가서 값을 바꾸도록 합니다.
이 경우에는 swap 함수가 반환해서 a와 b와 tmp가 사라져도 괜찮습니다.
x와 y 자체의 값을 교환했기 때문입니다.
swap 함수에서 *
기호가 많이 사용되어 헷갈릴 수 있습니다.
함수의 인자와 body에 사용된 *
의 의미가 다르니 주의하시길 바랍니다.
💥 인자에서 사용된 * 은 "자료형"이 "주소"라는 의미이고,
💥 함수 body에서 사용된 * 은 주소의 "값"이라는 의미이다
💛 개인 공부 기록용 블로그입니다. 👻