(1) 문자
컴퓨터에서 사용하는 문자는 대부분 고유의 ASCII 코드를 가지고 있다. (물론 요즘은 다국어 지원 등으로 ASCII 외에 유니코드, UTF-8, UTF-16 등의 체계 또한 많이 사용하며 C 표준에도 이를 지원하는 함수가 존재하지만 이 모든 체계들이 기본적으로 ASCII 와 호환이 되도록 설계되었으므로 여기서는 생략하기로 한다.) 예를 들어 문자 'A' 는 65, 문자 '0' 은 48, 문자 '&' 는 38, 줄바꿈(라인피드) 문자는 10 등이다. 이 ASCII 코드가 127을 넘지 않으므로 char로 표현할 수 있는 것이다.
C에서는 모든 문자는 ASCII 코드로 저장한다. 즉, ABCDE 라는 문자 5개를 저장하고 싶다면 char의 배열을 사용하여
char c[5] = { 65, 66, 67, 68, 69 }; // 예 1
라고 하면 된다.
또 하나. 문자 하나에 작은 따옴표로 묶어도 같은 의미이다. 즉
char c[5] = { 'A', 'B', 'C', 'D', 'E' }; // 예 2
는 위의 [예 1]과 같다.
즉 'A' 와 65는 C언어에서는 같은 의미이다.
또한 화면 등으로 표현할 수 없는 문자(줄바꿈 등) 혹은 C언어의 문법상 직접 표현할 수 없는 문자 (따옴표 자체 등) 을 표현하기 위하여 특수문자 개념을 두었다. 특수문자는 역슬래시(\)를 이용하여 표현하며 역슬래시 바로 다음 문자를 보고 판단한다. 예를 들어 다음과 같다.
'\n' : 줄바꿈 문자
'\'' : 작은 따옴표
'\"' : 큰따옴표
'\t' : 가로 탭 문자
'\0' : null 문자
'\\' : 역슬래시 문자
이러한 식으로 거의 모든 문자를 표현할 수 있다.
(2) 문자열
앞서 말했듯이 C언어는 문자열 자료형이 따로 없다. 다만 위에서 약간 짐작은 했겠지만 char의 배열로 문자열을 대신 표현할 수 있다.
C에서 문자열 자료형은 따로 없지만 문자열 자체를 표현하기 위하여 " "(큰따옴표) 를 지원한다. 예를 들어 문자열 ABCDE 를 저장하기 위하여 다음과 같이 정의할 수 있다.
char c[10] = "ABCDE"; // 예 3
그런데 문제가 있다. C언어에서는 문자열이라는 자료형이 따로 없기 때문에 저렇게 char형의 배열을 이용하여 문자열을 저장했다 하더라도 그 문자열의 길이가 얼마인지를 알 수 없다. 그렇다고 배열 c 의 길이(10)를 문자열의 길이라고 할 수도 없다. 하지만 눈으로 봐도 알 수 있듯이 문자열의 길이는 5이며, 또한 10개의 공간에 5개의 문자를 저장하였으므로 저 구문도 전혀 틀리지 않았다.
그렇다면 위의 [예 3] 과 아래 구문과는 같은 것일까?
char c[10] = { 'A', 'B', 'C', 'D', 'E' }; // 예 4
얼핏 보기엔 같아 보인다. (실제로 문자열을 출력해 보아도 같다.) 하지만 실제로는 미세한 차이가 있다.
"ABCDE" 라는 문자열을 문자 하나 하나 풀었을 때 무엇일까?
'A', 'B', 'C', 'D', 'E' 라고 생각할 수 있겠지만, (C 프로그래밍을 하는 분들은 다 알겠지만) 한 문자가 더 들어가야 한다. 바로 '\0' 이라는 NULL 문자이다.
앞서 말했듯이 C언어는 문자열 자료형이라는 것이 따로 없기 때문에 문자열이 어디부터 어디까지인지를 알 수 있는 방법이 딱히 없다. 따라서 문자열의 끝을 알리는 '\0' 문자가 들어가게 된다. ( '\0' 문자의 ASCII 코드는 0 이다.)
따라서 [예 3] 의 경우는 다음과 같다고 보아야 한다.
char c[10] = { 'A', 'B', 'C', 'D', 'E', '\0' }; // 예 5
그런데 [예 3] 과 [예 4] 가 미세한 차이가 있음에도 불구하고 결국 같은 목적을 달성하는 이유는 무엇일까? 그것은 C 언어에서의 배열의 초기화 특성이 있기 때문이다.
char c[10]; 에서 c 는 10개의 char(문자) 값을 저장할 수 있는 배열이며, 원래 초기화할 때에는 10개의 값이 들어가야 한다. 하지만 [예 4] 를 보면 5개의 값만 들어가 있다. 이럴 경우에는 C에서는 나머지 5개의 값에 모두 0을 넣는다. 따라서 결국 [예 5] 와 같은 결과를 갖게 된다. ('\0' 의 ASCII값은 0이라고 앞서 이야기했다.)
[예 3]과 [예 4] 의 미세한 차이가 문제를 발생시키는 경우는 아래의 경우이다.
char c[5] = { 'A', 'B', 'C', 'D', 'E' }; // 예 6 : 문제 없음
char c[5] = "ABCDE"; // 예 7 : 문제??
[예 6]의 경우, 5개의 문자를 저장할 수 있는 배열에 딱 5개가 들어갔다. 이는 옳은 표현이다. (물론 [예 6] 과 같이 저장해 놓고 이를 문자열로 사용할 때에는 문제가 있지만...)
하지만 [예 7]의 경우는 문제가 있는 표현이다. C언어에서는 배열의 크기가 5라고 하여 이를 5개까지만 채우고 나머지를 무시하는 작업을 하지 않는다. 즉,
char c[5] = "ABCDEFG";
라고 한다고 F, G 를 무시하지 않는다는 것이다. F, G 도 어딘가에 저장된다. 그런데 그 저장되는 장소가 어디가될지 불분명하기 때문에 위와 같이 코딩을 하면 프로그램 실행시 치명적인 오류가 발생할 수 있다. (컴파일러는 이 오류를 알려주지 않거나 단지 warning으로만 알려주며, 오류 없이 정상적으로 컴파일은 완료된다.)
다음을 보자.
#include <stdio.h> int main() { char c[5] = "ABCDEFG"; char d[5] = "123"; printf("[%s] [%s]\n", c, d); return 0; }
결과는 다음과 같이 나온다.
[ABCDE123] [123]
의도한 결과와는 다소 다르게 나오게 된다.
위에서 c 를 정의하는 코드를
char c[5] = "ABCDE";
라고 변경해도 같은 결과이다.
따라서 문자열을 저장하거나 다룰 때는 끝에 항상 '\0' 이 있다는 것을 고려하여 '\0' 까지 저장할 수 있는 공간을 마련하여야 한다.
잘보고가영
답글삭제감사합니다.
답글삭제좋은 글이네요
답글삭제