31.3 디버거에서 포인터 확인하기

디버거를 사용하면 변수의 메모리 주소, 포인터, 역참조를 손쉽게 확인할 수 있습니다. 다음 내용을 소스 코드 편집 창에 입력하세요.

dereference_assign.c

#include <stdio.h>

int main()
{
    int *numPtr;      // 포인터 변수 선언
    int num1 = 10;    // 정수형 변수를 선언하고 10 저장

    numPtr = &num1;   // num1의 메모리 주소를 포인터 변수에 저장

    *numPtr = 20;     // 역참조 연산자로 메모리 주소에 접근하여 20을 저장

    printf("%d\n", *numPtr);    // 20: 역참조 연산자로 메모리 주소에 접근하여 값을 가져옴
    printf("%d\n", num1);       // 20: 실제 num1의 값도 바뀜

    return 0;
}

*numPtr = 20;이 있는 줄에서 F9 키를 눌러 중단점을 설정하고 F5 키를 눌러 디버깅을 시작합니다. 그리고 화면 아래쪽에 지역 탭을 클릭합니다.

그림 31-10 디버거로 포인터 확인

현재 numPtr = &num1;까지만 실행한 상태이고 포인터 numPtr에 변수 num1의 주소가 저장되어 있습니다. 그림 34-10에서 지역 창을 보면 num1numPtr에 저장된 값을 볼 수 있는데 num1은 초깃값으로 10을 할당했으므로 10이 표시되고, numPtrnum1의 메모리 주소를 할당했으므로 0x0084fe5c가 표시됩니다(메모리 주소는 컴퓨터마다, 실행할 때마다 달라집니다). 이 상태를 그림으로 표현하면 다음과 같은 모양이 됩니다.

그림 31-11 포인터에 변수의 주소를 저장한 상태

지역 창에서 numPtr의 왼쪽에 있는 ▷을 클릭하면 현재 메모리 주소에 저장된 값이 표시됩니다. 여기서는 numPtrnum1의 메모리 주소를 저장하고 있으므로 num1의 값 10이 나옵니다.

그림 31-12 현재 메모리 주소에 저장된 값을 표시

이번에는 메모리의 내용을 직접 확인해보겠습니다. 메뉴의 디버그(D) > 창(W) > 메모리(M) > 메모리 1(1)을 클릭합니다.

그림 31-13 메뉴에서 메모리 탭 열기

화면 아래쪽에 메모리 1 탭이 열렸습니다. 이제 소스 코드 편집 창에서 numPtr 위에 마우스 커서를 가져다 놓으면 포인터에 저장된 메모리 주소가 나옵니다. 이 메모리 주소를 선택하고 마우스 오른쪽 버튼을 누른 뒤 복사(C)를 클릭합니다(Ctrl+C 키를 눌러도 됩니다).

그림 31-14 포인터에 저장된 메모리 주소 복사

메모리 1 창의 주소 부분을 클릭하고 마우스 오른쪽 버튼을 누른 뒤 붙여넣기(P)를 클릭합니다(Ctrl+V 키를 눌러도 됩니다). 그리고 엔터 키를 누르면 해당 메모리 주소의 내용이 표시됩니다.

그림 31-15 메모리 주소 붙여넣기

이제 메모리 주소 0x0084fe5c의 내용이 보입니다. 0a 00 00 00라고 나오는데 메모리의 내용은 보통 16진수로 표현하므로 0a를 10진수로 변환하면 10입니다. 즉, 이 메모리 공간이 변수 num1의 위치입니다.

그림 31-16 메모리 창에서 메모리 내용 확인

특히 num1int 자료형이므로 4바이트입니다. 따라서 0a 00 00 00과 같이 숫자 4개를 차지합니다. 또한, 우리가 사용하는 x86(x86-64) 계열 CPU는 리틀 엔디언 방식이라 값이 거꾸로 저장됩니다. 그래서 0a 00 00 00은 원래 00 00 00 0a이며 0a 값을 갖는다는 뜻입니다. 리

메모리의 내용을 확인했으면 F10 키를 눌러 *numPtr = 20;이 있는 줄을 실행합니다.

그림 31-17 역참조 코드 실행

화면 아래쪽 메모리 1 창을 보면 0a가 14로 바뀌었습니다(코드 실행으로 인해 바뀐 메모리 공간은 빨간색으로 표시됨). 16진수 14는 10진수로 20이므로 역참조 후 20을 할당하는 코드 *numPtr = 20;이 실행되어 메모리의 내용이 바뀐 것을 확인할 수 있습니다.

그림 31-18 역참조 후 20을 할당하여 메모리의 내용이 바뀜

*numPtr = 20;을 실행한 상태를 그림으로 표현하면 다음과 같은 모양이 됩니다. 즉, 역참조로 메모리 주소 0x0084fe5c에 접근하여 20을 할당(저장)합니다.

그림 31-19 역참조 후 20을 저장

이번에는 조사식 창에서 변수의 메모리 주소와 포인터의 역참조를 표시해보겠습니다. 화면 아래 쪽의 조사식 1 탭을 클릭합니다. 그리고 이름 부분을 클릭하여 &num1*numPtr을 입력합니다.

그림 31-20 조사식 창에서 변수의 메모리 주소와 포인터의 역참조 확인

&num1num1의 메모리 주소 0x0084fe5c가 표시되고, *numPtrnumPtr을 역참조한 값인 20이 표시됩니다. 특히 조사식 창을 이용하면 소스 코드를 고치지 않아도 변수의 값이나 메모리 주소를 바로 확인할 수 있습니다.

이처럼 디버거를 활용하면 변수의 메모리 주소, 포인터, 역참조를 확인하기가 편리합니다. 메모리에는 우리가 저장한 값들이 들어 있을뿐 어려울 것이 하나도 없습니다. 메모리 창과 조사식 창을 활용하면 포인터를 이해하기도 쉽고 프로그래밍하기도 편리합니다.

참고 | 메모리의 내용을 10진수로 보기

메모리 창은 16진수뿐만 아니라 10진수로도 볼 수 있습니다. 다음과 같이 메모리 창에서 마우스 오른쪽 버튼을 누르면 팝업 메뉴가 나옵니다. 16진수 표시(H)가 기본으로 선택되어 있는데 부호 있는 표시(S), 부호 없는 표시(U)를 클릭하면 메모리의 내용을 10진수로 볼 수 있습니다.

그림 31-21 메모리 창 팝업 메뉴

여기서는 부호 있는 표시(S)를 클릭했습니다. 메모리 내용에서 *numPtr = 20;으로 저장한 20을 볼 수 있습니다.

그림 31-22 메모리의 내용을 부호 있는 10진수로 표시