티스토리 뷰

strtok, strtok_s 사용법과 주의 사항에 대하여 알아보도록 하자.

Include

#include <string>

strok prototype

char *strtok
(
     char *strToken,
     const char *strDelimit 
);

Parameters

strToken

분리될 문자열 원본입니다.


strDelimit

구분자로 쓰일 문자열입니다. 문자 하나도 가능하지만 문자열도 가능합니다. 단, 주의사항으로는 문자열로 인자를 주게되면 각각의 문자열 전체를 구분자로 간주하는 것이 아닌 문자 하나씩 분리하여 구분자로 간주하여 원본 문자열을 최종 분리하게 됩니다. 예를 들면… I’m super man 원본 문자열을 “ ‘”라는 구분자로 strtok()을 사용하여 분리하게 될 경우 “ “와 “’”를 각각 구분자로 사용하여 I m super man 이라는 결과를 갖고 오게 됩니다.

Example

char str[] = "My name is Hong Gil Dong";
char *pToken = NULL;
char *pSeparator = " "; // 구분자
 
/* 첫번째 수행시에" " 구분자로 자른 후 My 라는 문자열을 리턴합니다. 정확히 얘기하면 주소값을 리턴합니다. 
나머지 name is.... 문자열은 strtok() 함수 내부에서 static 변수로 기억되고 있다가, 
두 번째 호출시 파라미터에 NULL을 받게되면 기억하고 있던 name is... 문자열을 꺼내어 다시 자르게 됩니다. */
 
pToken = strtok(str, pSeparator);
printf("%s\n", pToken);
 
/* 두번째 수행부터 strtok() 호출시에는 파라미터에 NULL을 넣음으로 계속해서 자르기 작업을 수행하게 됩니다.
strtok가 NULL을 반환하면 더 이상 자를 문자열이 없으므로 while 문을 빠져 나갑니다. */
 
while (NULL != (pToken = strtok(NULL, pSeparator)))
{
    printf("%s\n", pToken);
}

Result

My
name
is
Hong
Gil
Dong

기본적인 함수 사용 방법은 예제와 같습니다. 하지만 주의사항으로 세 가지가 있습니다. 첫 번째는 strtok() 함수 사용 후 원본 문자열인 str[]의 데이터를 보장할 수 없습니다. 확인 결과 위 예제에서 strtok() 함수를 수행 후에 str[]내부의 “ “ space 문자는 NULL로 모두 변환 되어버립니다.

해결 방법은 원본 데이터를 보존하기 위한 임시 버퍼 변수를 사용하는 방법이 있겠습니다.

두 번째는 VS6.0에서는 strtok()는 잘 작동하지만 VS2005이상에서는 원할한 작동을 보장하지 않습니다. 그러므로 온라인상에서도 주요 포럼 게시물들을 살펴보면 strtok() 보다는 VS2005 이상에서 사용할 수 있게끔 개선된 strtok_s() 함수의 사용을 권장하고 있습니다.

세 번째는 strtok() 함수는 내부적으로 문자열 분리를 위한 위치 식별을 위해 static변수를 놓고 정적 공유하여 사용한다고 합니다. 그러므로 현재 진행 중인 분리 작업을 훼손할 수 있기 때문에 Thread-Safe 하지 않습니다. 이는 하나의 스레드에서 서로 다른 문자열을 동시에 분리하게 되면 문제가 발생될 여지가 있습니다. 이를 개선한 함수가 strtok_s()가 되겠습니다.

strtok_s() 의 사용법은 strtok()과 동일하나 세 번째 인자가 추가 되었습니다.

strtok_s prototype

char *strtok_s(
     char *strToken,
     const char *strDelimit,
     char **context
);

세 번째 인자인 Context는 구분자로 분리된 후의 앞으로 남은 문자열을 저장하며 함수 사용시에 반환 후 그만큼을 제외한 나머지 문자열을 가리킵니다. 다시 말하면 다음 반환될 token의 위치를 가리키게 됩니다. 참조변수(&)를 넣어 사용하면 되겠습니다.

댓글
  • 프로필사진 김병희 char **context; // 자르고 남은 분자열
    pToken = strtok_s(str, pSeparator, context);
    모양으로 코딩했는데, 초기화가 되지 않았다고 ...
    어떻게 처리해야 될지 모르겠습니다.
    도움 부탁드립니다.
    감사합니다.
    2016.11.25 05:30 신고
  • 프로필사진 눈팅이 안녕하세요.
    지나가던 사람입니다.

    char *context; // 자르고 남은 분자열
    pToken = strtok_s(str, pSeparator, &context);

    이렇게 하셔야 합니다.
    세번째 인자에 포인터 값을 넣어주게 되는데 더블포인터로 설정해 두셨기 때문에 더블포인터가 가리키는 위치 초기화가 되어 있지 않아 값을 넣을수 없는거에요. ^^
    2017.02.24 10:21 신고
  • 프로필사진 김병희 뒤늦게 보아서 인사가 늦었습니다.
    감사합니다.
    2017.04.01 20:17 신고
댓글쓰기 폼