배열과 포인터의 메모리 할당

아래와 같이 배열과 포인터 두가지 방법을 사용하여 "Test"라는 문자열을 메모리에 할당할 수 있습니다.
배열은 각 문자에 대해 수정이 가능하지만 포인터를 각 문자에 대해 수정이 불가능합니다.

 

char p[] = "Test" -> p[0] = 'B' (가능)
char *p = "Test"  -> p[0] = 'B' (불가능)


=> 이유는 배열과 포인터가 할당되는 메모리 영역의 차이로 인해 발생하는데 배열과 포인터의 각 메모리 할당 과정을 설명드리겠습니다.

 

■ 배열

char p[] = "Test";

 

배열은 선언 시 시작 주소를 변경할 수 없는 상수 포인터형을 가집니다.
배열의 메모리 할당 시 요소의 순서대로 Stack 영역에 할당이 이루어집니다.

예를 들어 char p[] = "Test" 문자 배열을 선언할 경우 "Test" 문자열은 Stack 영역에 할당됩니다.
이때, p는 Stack 영역에 할당된 "Test" 문자열의 첫 번째 문자 'T'의 주소를 가리키게 됩니다. 


또한 배열은 선언시 주소를 변경할 수 없으므로 다른 문자열을 가리킬 수 없습니다.
"Test" 문자열은 Read/Write가 가능한 Stack 영역에 선언되기 때문에 p[0] = 'B'로 변경이 가능하고 문자열은 오류 없이 "Best"로 변경됩니다.

 

■ 포인터

char *p = "Test";

 

포인터는 선언 시 전역/지역에 따른 선언 위치에 따라 BSS/Stack 영역에 할당됩니다.
예제로 char *p = "Test" 를 선언하면 "Test"라는 상수 리터럴을 직접 가리키는 포인터를 선언한 것이 됩니다.
이때, p 포인터는 BSS/Stack 영역에 할당되고, "Test" 문자열은 Data 영역 중 Read만 가능한 .rodata 영역에 할당됩니다. 

따라서, "Test" 문자열이 배열에 선언되었을 때와 달리 p[0]에 접근하여 값을 바꾸려고 하면 

.rodata 영역에 위치하여 수정이 불가능한 Read Only 데이터이기 때문에 Segmentation Fault가 발생합니다.