마저 못한 정리를 시작하자.
상수형 문자열을 가르키는 포인터.
지금까지는 배열을 통해 문자열을 선언했었다. 하지만 우리는 포인터를 배우면서 배열은 상수형 포인터임을 배웠다.
그렇다면 포인터를 통해 문자열을 다룰 수 있을까?
char str1[] = "string 1";
이는 배열을 통해 선언한 문자열이다. 더 정확히 말하면 변수 형태의 문자열이다. 우리가 임의로 문자열의 일부를 수정할 수 있기 때문이다.
포인터와 배열은 상수냐 변수냐에 따라 구분되는 같은 것이라고 볼 수 있다. 그렇기에 우리는 다음처럼 쓸 수도 있다.
char *str2 = "string 2";
이렇게도 역시 가능하다. 배열과 포인터 모두 문자 s의 주소값을 나타낸다. 그럼 차이점이 무엇인가? 몇가지 차이점이 존재한다.
첫번째, 메모리상에서의 차이점이다. 위 두가지의 경우를 그림으로 나타내면 다음과 같다.
str1은 문자열 전체를 저장하여 첫 글자의 주소를 갖는 배열이고, str2는 자동으로 할당된 문자열의 첫 글자를 가르키는 포인터이다. 이렇게 보면 차이가 없어보이긴 한다. 하지만 우리는 배열이 상수형 포인터임을 알고 있다. 따라서 str1은 s의 주소를 계속해서 가르키고 있어야만 한다. 하지만 str2는 포인터 변수이므로, 언제든지 다른 문자열을 가르킬 수 있다.
두번째는 가르키는 문자열의 종류이다. 앞서 소제목에서 말했듯이 문자열 포인터는 상수형 문자열을 가르킨다고 했다. 상수로 선언된 자료는 수정이 불가능하기 때문에 str2는 가르키는 문자열은 바꿀 수 있지만, 가르키고 있는 문자열을 수정할 수는 없다.
개인적인 추측이지만, 컴파일러에서 자동 할당하는 문자열은 리터럴 상수로 취급하는 듯 하다.
정말 헷갈리는게 많은 문자열이다. 이를 모두 정리하여 결론을 내자면,
문자열 배열은 변수 형태의 문자열의 첫 주소를 가르키는 상수형 포인터
문자열 포인터는 상수 형태의 문자열의 첫 주소를 가르키는 포인터 변수
로 결론 낼 수 있을 것이다.
포인터로 나타내는 문자열의 처리과정
앞서 포인터 변수로 선언한 문자열은 상수 형태라고 했다.
char *str = "const string";
이러한 문자열의 처리과정을 조금 더 알아보자.
일단 const string이라는 문자열을 메모리에 자동적으로 할당하고 나서 맨 앞글자 c의 주소를 반환한다. 이를 str이라는 char형 포인터 변수 str에 저장할 것이다. 이 문자열이 0x1111에 저장되었다고 치자. 이는 다음과 동치일 것이다.
char *str = 0x1111;
(이것이 내가 리터럴로 할당되는 것이라고 추측한 이유)
그렇다면, 할당하지 않고 함수를 호출하면서 선언하는 문자열들은 어떻게 처리될까? 가령
printf("hello world");
처럼 말이다.
똑같다. hello world를 자동 할당한 후에, 그 주소값을 반환하는 것이다. 이렇게 말이다.
printf(0x1111);
실제로 printf함수의 형태를 살펴보면 다음과 같다.
int printf(const char *format, ...); //stdio.h 헤더에 정의되어있다.
문자열 자체를 받는 것이 아니라, 상수형 문자열의 주소를 입력받는 것이다(앞에 int는 일단 무시하도록 하자).
결국 큰따옴표로 묶인 문자열은 뭐가 되었든, 메모리 공간에 할당된 후에 주소값을 반환하는 것이다. (이래서 작은 따옴표와 큰따옴표의 구분은 정말 중요하다)
포인터 변수로 이루어진 배열 - 포인터 배열
정말 배열은 아무거나 다 담을수 있나보다. 배열은 포인터변수까지 저장이 가능하다. 선언 방식만 살펴보고 넘어가자. 이런게 있다 정도만 알면 될 것 같기 때문.
#include <stdio.h>
int main () {
int num1 = 1, num2 = 2, num3 = 3;
double num4 = 1.1, num5 = 2.2, num6 = 3.3;
int * arr1[] = {&num1, &num2, &num3};
double * arr2[] = {&num4, &num5, &num6};
char * arr3[] = {"sample", "string", "array"}; // 큰따옴표는 뭐다?
for(int i = 0; i < 3; i++) {
printf("%d ", *arr1[i]);
}
printf("\n");
for(int i = 0; i < 3; i++) {
printf("%f ", *arr2[i]);
}
printf("\n");
for(int i = 0; i < 3; i++) {
printf("%s ", arr3[i]);
}
return 0;
}
실행결과