2 분 소요

❄️ 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으로 할당된 메모리의 데이터가 저장됩니다. 그리고 스택에는 프로그램 내의 함수와 관련된 것들이 저장됩니다.
스크린샷 2023-06-17 오전 1 39 08

🤔 메모리 영역을 다양하게 나누는 이유는 무엇일까요?
컴퓨터에서 메모리를 텍스트, 데이터, 힙, 스택 네 가지 영역으로 나누는 이유는 프로그램의 실행과 관련된 다양한 요구사항을 충족시키고 메모리 관리를 효율적으로 수행하기 위함입니다.

  • 코드 영역에는 (프로그램 실행 시) 프로그램이 컴파일된 바이너리가 저장됩니다.
  • 데이터 영역에는 프로그램 안에서 저장된 전역 변수가 저장됩니다.
  • 힙 영역에는 malloc을 이용해 동적으로 할당된 메모리의 데이터가 저장됩니다.
  • 스택 영역에는 프로그램 내의 함수, 지역 변수와 관련된 것들이 저장됩니다.

이를 바탕으로 다시 생각해보면, 위의 코드에서 a, b, x, y, tmp 모두 스택 영역에 저장되지만 a와 x, b와 y는 그 안에서도 서로 다른 위치에 저장된 변수입니다.
따라서 a와 b를 바꾸는 것은 x와 y를 바꾸는 것에 아무런 영향도 미치지 않는 것이죠.

따라서 아래 그림 및 코드와 같이 a와 b를 각각 x와 y를 가리키는 포인터로 지정함으로써 이 문제를 쉽게 해결할 수 있습니다.
스크린샷 2023-06-17 오전 1 39 45

#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에서 사용된 * 은 주소의 "값"이라는 의미이다


💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기

태그:

카테고리:

업데이트: