강좌 & 팁
포인터와 배열은 다른가? 첫 번째 시간
이번 시간에는 이전 강좌 내용의 답부터 말씀을 드려야 겠습니다. 이전 강좌는 아래와 같습니다.
- 제목: 포인터, 왜 어려울까?
- 주소: http://forum.falinux.com/zbxe/?document_srl=555892
문제를 다시 말씀드리면 아래의 코드에서 밑줄 그은 부분에서 실행 에러가 발생한다는 말씀을 드렸습니다. 그런데 해결 방법이 매우 간단했지요. 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"; 부분만 보겠습니다. 이 행은 한 줄이지만, 두 가지 명령이 있습니다.
- char 포인터인 name을 정의하고,
- 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[] 모습을 자세히 보도록 하겠습니다.
즐거운 추석 한가위를 보내세요. ^^