C 언어 | 포인트 | 문자열 포인터


문자 배열과 문자열에 대한 포인터에 대해 설명한다. 특성상 리터럴 문자열에 대한 포인터에서 리터럴 문자열을 변경해서는 안된다. 리터럴 문자열에서 읽어 들인 문자열을 편집할 경우는 배열에 복사해야 한다.

리터럴 문자열에 대한 포인터

리터럴 문자열을 배열 초기화를 하면 배열에 문자열을 저장할 수 있었다. 그런데 어떤 의문이 생긴다. 초기화 이외의 식에서 리터럴 문자열을 지정한 경우, 이 문자열 리터럴은 어떤 형태로 사용되는가. 사실, 문자열 리터럴은 그 문자열에 대한 포인터를 반환한다.

예를 들어 printf("Kitty on your lap")라는 문장은 printf() 함수에 char *형의 값을 인수로 전달하고 있다고 생각할 수 있다. 그럼 이 문자열은 어디에 저장되어 있는가.

리터럴 문자열이나 숫자 등의 상수는 모두 컴파일시 고정 값으로 바이너리화되어 결국 실행 파일에 데이터가 저장된다. 프로그램 실행시 데이터가 상수 값으로 메모리에 로드할 수 있도록 되어 있다. 구체적으로 상수를 어떻게 저장하고 실행시에 어떻게 가져올지 컴파일러와 시스템에 의존한다.

이 점을 감안하면 문자열 리터럴은 프로그램을 실행하고 있을 때에 이미 메모리에 저장되어 있기 때문에 배열 이니셜 라이저를 사용하여 다른 배열에 복사를 한다는 것은, 문자 단위의 편집 등을 의도 하지 않으면 의미가 없는 행위이다. 목적에 따라 리터럴에 대한 포인터를 사용하는지 배열에 복사할지 여부를 선택해야 한다.

char chStr[] = "Kitty on your lap";

위의 문장은 리터럴 문자열을 새로운 배열 chStr에 복사할 수 있다. 리터럴 문자열에서 생성된 배열을 편집할 경우에 유효하지만 단순히 문자열을 가리키는 변수를 준비하고 싶은 것 뿐이라면 리터럴 문자열을 배열에 복사할 필요가 없다.

char *chpStr = "Kitty on your lap";

이것은 배열 이니셜 라이저에 리터럴 문자열을 지정하는 문장과는 큰 차이가 있다. chStr[] = "..."는 문자열을 저장만 하는 충분한 배열이 할당되고, 이것을 지정한 리터럴 문자열을 복사하지만, *chpStr = "Kitty on your lap"의 경우는 실행 파일에서 메모리에 로드된 문자열 리터럴에 주소를 대입하고 있는 것에 지나지 않는다.

코드1

#include <stdio.h>

int main() {
 char *chpStr = "Kitty on your lap";
 printf("%s\n" , chpStr);
 return 0;
}

코드1에서 포인터 chpStr에 리터럴 문자열 “Kitty on your lap"에 주소를 할당한다. 결과는 예상대로 “Kitty on your lap"라는 문자열을 표시할 뿐이다. 이 때, 포인터에서 리터럴 문자열의 내용을 변경할 수 없다. 내용의 변경을 시도했을 경우의 결과는 부정된다.