|
|||||||||||||||
문자열(string)은 2주차 강의 2.4절에서 다루었듯이, 일련의 문자들이 큰 따옴표로 둘러싸여 표현된다. 다음은 문자열 상수에 대한 예이다.
문자열은 내부적으로 문자들의 배열로 표현된다. 따라서 문자열이 기억공간에 저장될 때, 포함된 문자들이 바이트 단위로 연속되어 저장된다. 앞 장에서 다루었듯이, 문자는 한 개의 바이트 상에 ASCII 코드 형태로 표현된다는 것을 기억하라. 다음은 "String"의 문자열에 대한 기억공간 표현을 보여준다. ![]() “String"에 포함된 각 문자는 한 개의 바이트에 표현되고, 이들이 연속되어 저장된다는 것을 알 수 있다. 또한, 문자열 끝에 ‘\0’의 문자가 추가되어 있는 것을 알 수 있다. 이 문자는 널 문자(null character)라 불리는데, 문자열의 끝을 알리는데 사용된다. 다음 두 데이터가 기억공간 상에 어떻게 표현되는가?
'a'는 문자이나 “a"는 문자열이다. 따라서 이들은 다음과 같이 기억공간 상에 다르게 표현된다. 즉, ‘a'는 한 개의 바이트 상에 표현되나, “a"는 두 개의 바이트 상에 표현된다.
널 문자로부터 위의 기억공간에는 두 개의 문자열, “happy"와 ”ending"이 저장되어 있는 것을 알 수 있다. 만약에, 널 문자 없이 다음과 같이 “happy" 바로 다음에 ”ending"이 저장된 경우를 생각해보자.
여러분은 C 프로그램 상에서 문자열 데이터를 표현할 때도, 문자 배열을 사용하여 그렇게 한다. 다음은 문자 배열의 선언문과 초기화 코드를 사용하여 문자열 “happy"를 표현하고 있다.
배열 s1의 마지막 원소에 문자열의 끝을 알리는 널 문자를 반드시 포함시키는 것을 유의하라. 그렇지 않으며, s1은 문자열로 인식되지 않는다. 위의 문자 배열 s1에 대한 초기화는 다음과 같이 배열 선언시에 수행될 수 있다. 배열 s의 크기는 초기 값들의 개수로 판단될 수 있기 때문에 생략 가능하다는 것을 기억하라.
문자열 데이터는 프로그램에서 빈번히 사용되기 때문에, C는 다음과 같이 간단한 형태의 문자열 초기화 구문을 제공한다.
위에서 선언된 문자열 s1, s2, s3는 모두 동일한 문자열을 정의하며, 다음과 같이 기억공간 상에 동일하게 표현된다.
|
|
|||||||
2. 문자열의 입력과 출력 C 언어는 문자열에 대한 입력과 출력을 위해서 gets()와 puts()의 라이브러리 함수를 제공한다. 이 두 함수는 문자의 입출력을 위한 getchar()와 putchar()와 마찬가지로, 표준 입출력 라이브러리 stdio에 포함되어 있다. 다음은 두 함수에 대한 설명이다.
엔터 키는 개행 문자(‘\n')로 입력된다는 것을 유의하라. 위의 문자열에 대한 gets()의 행동을 보여준다. 즉, gets()는 사용자가 입력한 문자들을 순서대로 문자 배열 s에 저장한다. 한 가지 유의할 사항은 사용자가 마지막에 입력한 '\n'의 문자가 ‘\0’으로 변환되어 저장된다는 것이다. 따라서 gets()가 s에 저장한 데이터는 문자열로 인식될 수 있다. 다음은 s에 저장된 문자열에 대한 puts()의 행동을 보여준다.
다음은 gets()와 puts()를 사용하여 사용자로부터 문자열을 입력받고 출력하는 프로그램이다. |
위의 프로그램에서 문자 배열 s를 사용자가 입력하는 문자열을 포함할 수 있는 충분한 크기로 선언하는 것이 중요하다. 그렇지 않으면, 예상하지 않은 결과가 초래될 수 있음을 유의해야 한다. puts()의 기능은 ‘%s'의 출력제어문자를 사용하여 printf()로 표현될 수 있다. 다음 두 문장은 동일하다. 즉, 동일한 문자열을 출력한다.
그러나 다음 두 문장은 다르다.
즉, puts()에서는 개행 문자가 문자열 끝에 자동으로 추가되나, printf()에서는 그렇지 않다. scanf()도 문자열 입력을 위한 입력제어문자 ‘%s'를 제공한다. 그렇다면, gets()의 기능은 scanf()로 표현될 수 있는가? 다음 코드를 생각해보자.
gets()는 개행 문자가 나올 때까지 문자들을 계속 입력받아 s1에 저장한다. 그러나 scanf()에서는 공백 문자나 개행 문자를 만날 때까지만 문자들을 입력받는다. 따라서 첫 번째 scanf()는 공백으로 구분된 첫 번째 문자열을 s1에 저장하고, 나머지 문자열은 무시된다. 두 번째 scanf()는 공백으로 구분된 첫 번째 문자열이 s1에 저장되고, 두 번째 문자열이 s2에 저장된다.
scanf()에서 s1이 배열이기 때문에 &s1이 아니고, s1으로 표현되었음을 유의하라. 배열 이름은 배열의 첫 번째 원소에 대한 기억공간 주소를 포함하고 있다는 사실을 기억하라. |
|
||
3. 문자열의 처리 예를 들면, 문자열 s에서 i번째 문자를 선택하려면, 다음과 같이 표현하면 된다.
배열에서와 마찬가지로, s에 포함된 문자열의 첫 번째 문자는 s[0]으로 선택된다. 다음 프로그램 예제를 통해서 문자열을 문자단위로 처리하는 방법을 설명한다.
![]()
다음에서 여러분은 프로그램 13-3을 단계별로 실행시키면서, 그 결과를 확인한다. |
프로그램 13-3은 gets()를 사용하여 한 개의 문자열을 입력한다. 그러나 C에서는 문자 단위로 문자열을 입력받을 수 있다. 다음 프로그램을 생각해보자. 이 프로그램은 문자 단위로 문자열을 입력받아 출력한다. 위 프로그램의 while 문의 각 반복은 한 개의 문자를 입력받아 문자 배열 s에 저장한다. while 문의 반복 조건을 생각해 보자.
오른쪽 부분은 문자를 개행 문자가 입력될 때까지 입력된 문자를 s에 저장한다는 것을 의미한다. 식의 왼쪽 부분은 배열 s의 범위를 벗어나서 문자가 저장되는 것을 피하기 위함이다. 여기서 i < MAX 가 아니고, i < (MAX - 1)로 표현된 이유는 s의 마지막 번째 원소에 널 문자를 삽입하기 위함이다. 실제로, while 문의 바로 다음번째 문장이 문자열의 끝을 알리는 널 문자를 저장한다. ![]() |
4. 문자열 라이브러리 함수 C 컴파일러는 문자열을 처리하기 위한 유용한 여러 가지 함수들을 string 라이브러리에 포함시켜 제공한다. 따라서 이러한 함수를 사용하기 위해서 그 헤더 파일 <string.h>을 포함해야 한다. 다음은 string 라이브러리에 포함된 문자열 처리 함수를 보여준다. 여기서 함수 매개변수로 사용된 s1, s2, s는 모두 문자 배열이다.
다음 코드를 생각해보자. 먼저, strcmp() 함수를 생각해보자. 이 함수는 s1, s2를 사전식 순서에 기반하여 비교한다. 즉, "song"이 “happy"보다 영어사전에 먼저 나오기 때문에 s1 > s2가 성립된다. 따라서 if 문의 수행 결과로 다음이 출력된다.
다음은 두 문자열이 어떻게 비교되는지를 보여준다.
다음에 strcpy() 함수를 생각해보자. 이 함수는 s2의 문자열을 s1에 그대로 복사한다.
다음에 strlen(s1)을 생각해보자. s1은 다음과 같은 문자열을 포함하고 있다.
다음 프로그램은 위의 코드에서 s1과 s2에 문자열을 초기화하지 않고 사용자로부터 읽어들여서 설정하여
작성한 것이다. 여러분은 문자열을 입력하고, 단계별로 실행시키면서 문자열 함수의 수행 효과를 확인하기 바란다. |
|
|