c++이나 java에는 부분 문자열을 가지고 오는 함수가 있습니다. 각각 substr과, substring이에요. 예를 들어, 어떠한 문자열 str = "chogahui"가 있고, 1번째부터 3번째까지 가지고 온 부분 문자열 sub = "hog"일 거에요. 이걸 가지고 오는 함수를 string.h에서는 찾기가 힘듭니다. 그러면 이것을 어떻게 구현해야 할지, 생각해 봅시다.

 

 


 사실 핵심적인 것은 간단합니다. 어떠한 시작 위치에서부터 t개 만큼을 어딘가로 복사한다. 만약에 문자열 str에서 [s,e)까지의 부분 문자열을 복사한다면 e-s개를 어딘가로 복사를 하는 것입니다. 그러면, 문자열을 복사를 하는데, 시작 위치로부터 t개만큼 copy 하는 함수를  찾으면 되는데요. 그것이 strncpy 함수입니다.

 

 

char *strncpy(char *dest,const char *src,size_t num);

 

 

 src부터 num개만큼의 character를 dest에 복사합니다. 경계 검사를 잘 해야 하고, src와 dest가 overlap 되지 않아야 한다는 것만 기억해 두시면 좋을 듯 싶어요. overlap 문제만 해결하고 싶다. 그렇다면 memmove가 좋은 선택이 될 수 있어요.

 

 

[관련글]

memmove vs memcpy

 

 

 strncpy(dest,str+1,3); 을 호출해 봅시다. 그리고 str[10] = "chogahui"; 라고 해 봅시다. 그러면, 이 말은 dest에 노란색으로 칠한 부분을 복사하겠다는 의미입니다. str+1은 'h'를 가리킬 거고, 거기서부터 3개의 문자를 복사할 거니까요.

 

 

 아래 예제 프로그램을 실행해 봅시다. 일단 str은 "chogahui05"입니다. 그리고 dest에는 이미 "ababababab"라는 문자열이 있었습니다. 저는 dest에 str+1에 있는 내용부터 3개의 문자만큼을 복사를 했는데요.

 

 

 결과값이 "hogababab"가 나옵니다.

 

 

 이는 노란색 부분을 밑에 있는 배열인 dest+0부터 복사를 해서 그렇습니다.

 

 

 여기까지 이해가 가시리라 믿습니다. 그러면 어떻게 문자열 str에서 [s, e)까지의 부분 문자열을 어떻게 뽑는지 이야기 해 보도록 하겠습니다. 즉, 저는 Java의 substring이라던지, C++의 string 클래스에 있는 substr을 구현해 볼 거에요. 단, 직접 구현하지는 않고, string.h에 있는 함수를 이용해서요.

 

 


 사실 여기까지 보셨으면 아시겠지만, strncpy를 이용하시면 됩니다.

 

 

 저는 시작 위치가 1이고, 끝나는 위치가 3인 부분 문자열을 출력하고 싶습니다. my_substring은 3개의 인자를 받을 거에요. 시작 위치랑 끝 위치. 그리고 부분 문자열을 뽑을 string인 str.

 

 

char *my_substr(int s,int e,char *str);

 

 

그러면 대충 요렇게 선언할 수 있는데요. s부터 e까지 들어가기 때문에, 실제로 e-s+1개에다가, 널문자까지 포함하려면 e-s+2개를 넣어야 합니다. 예를 들어서 s가 1이고, e가 3이라면 부분 문자열의 길이가 3입니다.

 

 

 그런데 NULL 문자 자리 하나 들어가야 합니다. 그러므로, 실제로는 3-1+2의 값, 4만큼 들어가야 합니다. 그 다음에는 간단합니다. strncpy 함수를 이용하면 되는데, 저는 str+1에서 시작하는, 3개만큼의 길이를 가지는, 연속적인, 부분 문자열을 복사하기 때문에 strncpy(new,str+1,3); 을 호출해 주면 됩니다. 이를 일반화 시키면 strncpy(new,str+s,e-s+1); 을 넣어주면 될 거에요.

 

 

 노란색 부분을 복사한 다음에는 초록색 부분에 NULL 값을 넣어야 합니다. 초록색 부분은 new[e-s+1]로 볼 수 있어요. 따라서, 마지막에 new[e-s+1]에다가 널 값을 넣으면 됩니다. 그리고 new를 리턴해 주면 됩니다. 제가 말한 내용을 그대로 구현해 봅시다.

 

 

 어때요? 어렵지 않아요. 그냥 저는 동적으로 할당한 다음에, 거기에 적당히 부분 문자열을 잘 복사해서 리턴을 한 것 뿐입니다. new를 지역 변수로 선언하지 않은 이유는, 만약에 지역 변수로 선언했다면, substr이 호출이 끝나면서 new가 사라지게 됩니다.

 

 

 이렇게 선언해 버리면, new가 지역 변수이기 때문에, substr이 끝난 시점에서 사라집니다. 그렇기 때문에, malloc 등으로 동적 할당 해 놓고, 처리를 한 다음에 결과값을 리턴한 것입니다.