C언어 문자열 : 특별한 문자로 끝난다.

코딩/C 2019. 9. 9. 17:56

 저번 시간에 배열에 대해서 다루었습니다. 이번에는 무엇에 대해 다루어 볼까요? 간단하게 문자열에 대해서 다뤄 보도록 하겠습니다. char형은 문자를 저장합니다. 그러면 그것들을 연속적으로 모아놓은 것은 무엇일까요? 예를 들자면 'c', 'h', 'o'가 모여서, "cho"가 되고, 'd', 'o', 'g'가 모여서 "dog"가 됩니다. 이것을 우리는 문자열이라고 합니다.

 

 

 그러면, 문자열의 끝은 어떻게 판단할까요? 이게 문제가 될 수 있어요. 배열에서 끝은 어떻게 판단하나요? 사실, 이것은 배열의 크기에, 각 원소의 크기로 나누면 될 겁니다. 이 부분은 크게 어려울 건 없어 보여요. 그런데, 이런 경우를 생각해 봅시다.

 

 

 이 때에는 출력 결과가 어떻게 나오나요? 저는 main 함수 안에, str 배열을 선언했습니다. 그리고 gg라는 인풋을 주었습니다. 그러한 경우에, 메모리 상에 어떻게 들어가 있을까요?

 

 

 대충 이래 들어갔을 겁니다. 배열의 size는 10이고, 이를 sizeof(char)로 나누니까, 10개의 원소를 순회하면서, str[i]의 내용을 출력을 할 건데요. str[3], str[4], ... , str[9]에 들어간 내용이 쓰레기 값입니다. 그러니 str[9]까지 돌면 쓰레기 값이 출력이 될 거에요.

 

 단지, str[10]은 들어갈 수 있는 문자의 수만 나타낸 것이라고 할 수 있어요. 10개만큼 할당을 할 수 있는 것과, 실제 데이터의 길이가 10인 것과는 이야기가 다릅니다. 그러면 정말로 끝을 판단하는 방법이 없을까요?

 

 


 

먼저 아래 프로그램을 실행시켜 봅시다.

 

 

 보시면, 0 부터 9까지 돌면서, i와 str[i]의 값을 int형으로 출력하고 있어요. char형보다는 int가 크니까 잘 출력이 될 거에요. "gg"를 입력했을 때 출력 결과를 봅시다.

 

 

 그러면 이런 식으로 출력이 되었다는 것을 알 수 있는데요. 'g'의 아스키 코드 값이 103입니다. 103이 2번 나타난 후에 0이 나타났다는 것을 알 수 있는데요. 0이라는 값이 문자열의 끝을 나타내기 위해 쓰였다는 것을 알 수 있어요. 이것을 NULL 문자라고 합니다.

 

 

 

 널 문자는 문자열이 끝났다는 것을 판단하기 위해서 쓰입니다. 우리가 길이 정보를 가지고 있지 않는 이상. C++의 string 클래스는 이야기가 달라요. 이미 클래스 안에 길이에 대한 정보가 있어요. 그렇기 때문에, length()라던지 size()의 복잡도가 선형도 아닌, 상수가 되는 것입니다. 그 정보가 주어져 있지 않은 이상, 우리는 기준 위치로부터 특정한 문자가 나타날 때 까지 선형으로 탐색해야 한다는 것을 알 수 있는데요. string.h에 있는 strlen 함수는 복잡도가 O(1)일 거 같지만 O(n)이 되는 이유도, 자료구조 안에 길이에 대한 정보를 저장하지 않기 때문입니다.

 

 

 당연하게도, 이렇게 코드를 작성하시면 효율적이지 않을 거에요. 길이에 대한 정보를 저장하지 않으니까, base 주소로부터 계속 널 문자를 만날 때 까지 탐색을 할 거에요. 조건 검사할 때 마다요.

 

 


 

 

 그러면 문자열의 길이를 구할 때도, 이어 붙일 때도, 비교를 할 때도 저 널 문자가 굉장히 중요할 겁니다. 그러면, 문자열의 길이가 최대 100까지 들어옵니다. 이 때, string을 저장하기 위해서는 char형을 몇 개나 저장하는 배열이 필요할까요?

 

 

 100에다가 널 문자가 들어갈 공간 1을 더하면 101이 됩니다.

 

 


 그러면 문자열 함수 중 하나인, strlen을 직접 구현해 봅시다. strlen은, 길이를 리턴해 주는 함수입니다. 일단 인자는 다음과 같습니다.

 

 

 const char *의 의미는 지금 모르셔도 됩니다. 그냥 여기에서는 아. string을 가리키는 무언가를 받는 구나 정도만 생각하시면 됩니다. 그러면 base 위치를 str이라고 해 봅시다.

 

 

 그러면 str로부터, i만큼 떨어진 위치는 str+i로 표현을 할 수 있습니다. str[i]의 값이 0이 아니라면 계속 탐색을 하면 됩니다. 물론, 길이 값을 리턴할 변수의 값 또한 하나 증가시켜주면 되고요.

 

 

 그렇지 않으면 어떻게 하면 좋을까요? 그대로 빠져 나오면 됩니다. for loop를 빠져 나오면 됩니다. 그러면 for loop가 도는 조건을, str[i]가 널 문자가 아니라면 계속 돌게 만들면 될 거에요.

 

 

 의도대로 짜신다면 이렇게 작성하시면 됩니다. str[i]가 0이 아니라면, 리턴값인 r도 증가시키고, i도 증가시키는 식으로 작성하시면 됩니다. 이 때 i는 인덱스를 의미합니다. str[i]가 널 값이 아니라면 계속 뒤의 원소들을 보면 될 거에요. 우리는 뭘 기준으로 판단했나요? NULL 문자인지 아닌지.

 

 그만큼 C언어에서 문자열을 다룰 때, NULL 문자는 중요합니다. 이 점 기억해 두시면 좋을 듯 싶습니다.