문자열

지금껏 문자열에 관련된 내용들은 어물쩍 넘어갔습니다. "BOY"와 같은 것 말이죠. 왜냐하면, 문자열은 하나의 자료형이 아니라 그저 char의 배열이기 때문입니다. 하지만 그냥 char 배열과는 다른 점이 있는데, 그것은 마지막에 반드시 '\0'(NULL)이 들어간다는 것입니다. printf도, puts'\0'이 나올 때까지 출력합니다. 눈치가 빠른 사람이라면, '\0'이 그냥 숫자 0을 의미함을 알았을 것입니다.

문자열을 저장하는 방법은 다음과 같습니다.

#include <stdio.h>
int main() {
      char a[ 4 ]   = "BOY",    //반드시 \0(NULL)을 위한 자리가 필요
           b[ 3 ]   = "HO!",     //위험합니다!
           c[]      = "GIRL",   //크기는 5
           d[]      = { 'H', 'A', 'H', 'A' },         //위험합니다!
           e[]      = { 'H', 'O', 'H', 'O', '\0' },   //OK!
           * f      = "그아아앗"; //이것들은
      char* g       = "퉤에에엣"; //의미가 조금 다릅니다
      char* h[ 2 ]  = { "nya", "ayn" };   //이것도 단순한 문자열의 배열은 아닙니다
      char i[][ 5 ] = { "asdf", "fdsa" }; //이건 문자열의 배열입니다
      printf("a: %s\n", a); printf("b: %s\n", b);
      printf("c: %s, 크기는 %d\n", c, sizeof c / sizeof(char));
      printf("d: %s\n", d); printf("e: %s\n", e);
      printf("f: %s\n", f); printf("g: %s\n", g);
      printf("h[ 0 ]: %s\n", h[ 0 ]);
      printf("h[ 1 ]: %s\n", h[ 1 ]);
      printf("i[ 0 ]: %s\n", i[ 0 ]);
      printf("i[ 1 ]: %s\n", i[ 1 ]);
      return 0;
}

a: BOY
b: HO!BOY
c: GIRL, 크기는 5
d: HAHAGIRL
e: HOHO
f: 그아아앗
g: 퉤에에엣
h[ 0 ]: nya
h[ 1 ]: ayn
i[ 0 ]: asdf
i[ 1 ]: fdsa

다소 깁니다만, 천천히 음미해 주세요.

a는 크기 4짜리 char 배열입니다. 만약 크기를 3으로 했더라면 '\0'(NULL)이 들어갈 공간이 없어 출력할 때 애로사항이 생겼을 것입니다 또, = "BOY"= { 'B', 'O', 'Y', 0 }와 같은 의미입니다.

b는 크기 3짜리 배열입니다. printf'\0'을 만날 때까지 출력하는데, b의 끝에 '\0'이 없기 때문에 엉뚱한 것까지 출력합니다. 여기에서는 b[ 3 ]이 되었어야 하는 공간이 우연히 a[ 0 ]과 같은 탓에 BOY까지 출력되었고, a[ 3 ]에 있는 '\0'을 만나 겨우 출력을 멈추었습니다★.

c는 크기를 정하지 않았습니다. GIRL4글자이므로, '\0'까지 더해져 총 5의 크기를 갖게 됩니다.

d는 말 그대로 char 배열입니다. 그런데, '\0'이 없습니다. 여기에서는 d[ 4 ]이 되었어야 하는 공간이 우연히 c[ 0 ]과 같은 탓에 GIRL까지 출력되었고, c[ 4 ]에 있는 '\0'을 만나 겨우 출력을 멈추었습니다★.

ed가 잘못한 일을 완벽히 고쳤습니다. \0' 대신 그냥 0을 써도 괜찮습니다.

fg는 앞의 것들과는 조금 의미가 다릅니다★. 이 둘은 포인터 변수로, 지금 당장 알 필요는 없습니다. 이렇게도 문자열을 저장할 수 있다는 것만 알아두세요.

h도 문자열들의 배열이라기보다는 char 포인터들의 배열입니다★. 이것도 '포인터' 부분을 읽으면 이해할 수 있습니다.

i야말로 진정한 문자열의 배열입니다.

문자열을 입력받아 보겠습니다.

#include <stdio.h>
int main() {
      char a[ 5 ] = { 65, 65, 65, 65, 65 };  //65는 대문자 A입니다
      scanf("%s", a);
      printf("%s\n", a);
      printf("%d %d %d %d %d\n", a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ]);
      return 0;
}

BBB

BBB

66 66 66 0 65

우리는 여기서 두 가지 사실을 눈치 채야 합니다. 첫 번째는 %s로 문자열을 입력받을 때는 &가 필요하지 않다는 것입니다. 사실 %s는 주소값을 필요로 하는데, a 자체가 주소값이기 때문입니다★. '포인터' 부분에서 자세히 다룹니다. 자꾸 '포인터'거린다고 불평하지 마세요. 배열과 포인터는 떼려야 뗄 수 없는 관계입니다.

두 번째 사실은 입력받고 나면 자동으로 '\0'까지 채워진다는 사실입니다. 그렇기 때문에 우리는 입력받을 문자열 길이 + 1 이상의 크기를 갖는 배열을 만들어 놓아야 합니다.

큰 따옴표로 둘러싸인 문자열의 실체와 아까 의미가 다르다고 했던 f, g, h의 진짜 의미는 '포인터' 부분에서 모두 해명하도록 하겠습니다. 진짜로!