포인터와 배열은 다른가? 첫 번째 시간

이번 시간에는 이전 강좌 내용의 답부터 말씀을 드려야 겠습니다. 이전 강좌는 아래와 같습니다.

문제를 다시 말씀드리면 아래의 코드에서 밑줄 그은 부분에서 실행 에러가 발생한다는 말씀을 드렸습니다. 그런데 해결 방법이 매우 간단했지요. name을 "char *name"이 아닌 "char []name"으로 변경하기만 하면 됩니다. 포인터 "*"와 배열 "[]"은 어떤 차이가 있길레 이렇게 간단한 방법으로 문제가 해결될까요?

#include <stdio.h>

int main( void){

    char *name  = "jang Kilseok";
                        
    name[0] = 'J';
                        
    printf( "%s\n", name);

    return 0;
}

우선 이 코드가 컴퓨터 안에서 어떻게 실행되는지 그 모습을 보시면 쉽게 이해하실 수 있습니다. 프로그램을 실행한다는 것은 실행 파일을 컴퓨터의 메모리로 읽어 들여서 프로그램 코드에 따라 차례로 진행하는 과정이 되겠습니다. 강좌 내용의 이해를 돕기 위해서 용어부터 정리하겠습니다. 우리가 프로그램을 작성하여 만들어진 실행할 수 있는 프로그램 파일을 "어플리케이션"이라고 하고, 컴퓨터 메모리에 올려 져서 실행 중인 프로그램을 "프로세스"라고 합니다.

 

코드 영역과 데이터 영역

프로세스는 아래와 같이 크게 두 개의 영역으로 나뉘어 컴퓨터 메모리에 올려져서 실행되는데, 바로 코드 영역과 데이터 영역입니다. 코드 영역은 ****.c 에서 이렇게 저렇게 하라는 실행 명령이 담긴 곳이라고 한다면, 데이터 영역은 말 그대로 데이터를 처리할 변수가 위치하는 부분이 되겠습니다. 그림으로 보겠습니다. 역시 이렇게, 저렇게 처리하라는 부분이 "코드 영역"에 들어 갑니다. 그리고 "char *name;" 으로 선언한 name 변수는 데이터 영역에 생성되었습니다.

 

 

코드 영역은 읽기는 가능해도 쓰기를 할 수 없는 보호 영역입니다. 언제 어느 때 이곳이 손상된다면 프로세스는 전혀 예상할 수 없는 어뚱한 행동을 하게 될 것입니다. 우리가 읽고 쓸 수 있는 영역은 데이터 영역입니다. 그렇다면 name은 코드 영역에 있는 "Jang Kilseok"와 어떻게 연결될까요?

코드 영역과 데이터 영역을 가리지 않는 포인터

 

코드 영역이든 데이터 영역이든 메모리입니다. 메모리는 Byte 단위의 데이터를 담을 수 있는 연속된 저장 장소입니다. 책을 쓰시는 대부분의 저자가 저장 장소를 박스로 표현하는 경우가 많은데, Byte 값이 하나씩 들어 가는 박스로 생각하셔도 좋습니다. 이런 박스가 한 줄로 주~욱 나열되어 있고, 각 상자 겉에는 구분을 위해 0부터 1, 2, 3, ... 식으로 번호가 붙여 있다고 생각하시면 되겠습니다.

 

흠~ 너무 초보적으로 글을 썼죠? ^^ 이정도는 모두 아시겠습니다만, 실은 아래의 그림을 설명해 드리고자 하기 때문에 길게 설명을 드렸습니다. 프로그램 코드에서 char *name = "Jang Kilseok"; 부분만 보겠습니다. 이 행은 한 줄이지만, 두 가지 명령이 있습니다.

  1. char 포인터인 name을 정의하고,
  2. name 값에 "Jang Kilseok" 문자열의 선두 번지를 넣어라 하는 것이죠.

그래서 결국 아래와 같이 메모리에 올려져 실행됩니다. 변수 name은 데이터 영역에 생성되므로 그 안에 어떤 값을 넣든, 빼든 아무런 문제가 발생하지 않습니다.

 

그리고 우리가 포인터를 이행하여 아래와 같이 분석할 수 있습니다.

  • name에는 200이 있다.
    name 변수 자체는 "Jang Kilseok" 문자열의 시작 주소, 그림 상으로 200 주소가 들어간다.
  • *name 에는 'J' 가 있다.
    포인터 변수 앞에 '*'를 붙이면 그 변수가 가지고 있는 값을 주소로 생각했을 때, 그 주소에 들어 있는 값이 들어 있다라고 이해하시면 됩니다.

코드 영역은 읽을 수는 있어도 변경할 수는 없다고 했습니다. 그러므로 아래와 같은 코드는 아무런 문제가 없습니다.

char   ch = *name;

실행하면 ch에 'J'가 들어 가게 됩니다. 그러나 아래의 코드는 실행될 수 없습니다.

*name  = 'A';

이 명령은 name이 가지고 있는 주소 200(코드 영역 내의 주소)의 내용을 'J'에서 'A'로 바꾸라는 것으로 즉, 코드 영역을 변경하는 것이기 때문에 허용할 수 없는 코드입니다. 그래서 영역 에러인 "Segmentation Error"가 발생합니다. 그림으로 다시 보죠.

 

 

이해 되시죠? 그렇다면 "char *name을 char name[]으로 바꾸면 뭐가 달라지나?" 라고 질문하실 것입니다. 네, 다릅니다. 많이 다른 모습으로 메모리 영역에 올라 옵니다. 이 설명은 다음 시간에 하겠습니다. 잉? 위의 내용은 이전 시간에 얘기한 내용인데, 라고 말씀하신 다면 역시 옳은 말씀입니다만, char name[]이 어떻게 다른지 설명을 드리기 위해 char *name에 대해 자세히 말씀을 드렸습니다. 이점 양해를 바라고요, 다음 시간에 char name[] 모습을 자세히 보도록 하겠습니다.

 

즐거운 추석 한가위를 보내세요. ^^