[C언어] 특정 문자로 문자열 자르기 - Split 구현

C언어에는 문자열을 쉽게 Split하는 내장함수가 없습니다.

그래서 열받죠...😩 아니 str.split(",") 하면 알아서 딱 되어야하는 거 아니냐~~!

 

C언어 사용하면서 가장 불편한 부분이 String 관련해서이지않나 싶어요.

자주 쓰이는 코드이기에 기록할 겸 포스팅!

 


 

★ 최종 목표 : C언어에서 사용할 수 있는 Split함수 구현

→ 바로 보실 분은 맨 아래쪽으로

 

 

특정 구분자를 기준으로 문자열 분할

문자열을 분할하는 방법으로는 문자열에서 특정 구분자(delimiter)를 기준으로 분할하는 방법이 있습니다.

strtok 함수를 사용하는 것인데요, 우선 예제 코드 보시죠

 

예제

#include <stdio.h>
#include <string.h>

int main() {
   char str[] = "apple,banana,cherry,date";
   char* token = strtok(str, ","); // ","를 구분자로 사용하여 문자열 분할
   while (token != NULL) {
      printf("%s\n", token);
      token = strtok(NULL, ","); // 다음 분할 위치로 이동
   }
   return 0;
}

위 코드는 "apple,banana,cherry,date" 문자열에서 ","를 구분자로 사용하여 문자열을 분할합니다.

strtok 함수를 사용하여 구분자를 기준으로 첫 번째 토큰을 추출한 뒤, while문을 이용해 모든 토큰을 출력합니다.

strtok 함수는 이전 호출에서 마지막으로 발견된 토큰 이후부터 다음 토큰을 찾습니다.

 

출력 결과

위 코드의 출력 결과는 다음과 같습니다.

apple
banana
cherry
date

 

 

strtok 함수 설명

함수 원형 및 설명

char* strtok(char* str, const char* delim);

 

strtok 함수는 첫 번째 매개변수로 문자열 포인터(str)를 받고, 두 번째 매개변수로 구분자(delimiter)를 받습니다.

 

strtok 함수는 첫 번째 호출 시 문자열 포인터(str)가 가리키는 문자열에서 구분자(delimiter)를 찾아 구분자 이전까지의 문자열을 반환합니다. 이후, 다음 호출에서는 이전 호출에서 반환한 문자열 이후의 문자열에서 구분자를 찾아 반환합니다. 이를 반복하여 문자열의 모든 구분자를 기준으로 분할할 수 있습니다.

 

예를 들어 "apple,banana,cherry,date" 문자열에서 ","를 구분자로 사용하여 문자열을 분할하면 다음과 같은 과정이 이루어집니다.

 

1) 첫 번째 호출: "apple,banana,cherry,date"에서 첫 번째 "," 이전까지의 문자열 "apple"을 반환합니다.

    * 이때, 원래 문자열은 "apple,banana,cherry,date"에서 "apple"이 제거된 "banana,cherry,date"가 됩니다.

2) 두 번째 호출: "banana,cherry,date"에서 첫 번째 "," 이전까지의 문자열 "banana"을 반환합니다.

    * 이때, 원래 문자열은 "banana,cherry,date"에서 "banana"가 제거된 "cherry,date"가 됩니다.

3) 세 번째 호출: "cherry,date"에서 첫 번째 "," 이전까지의 문자열 "cherry"을 반환합니다.

    * 이때, 원래 문자열은 "cherry,date"에서 "cherry"가 제거된 "date"가 됩니다.

4) 네 번째 호출: "date"에서 첫 번째 "," 이전까지의 문자열 "date"을 반환합니다.

5) 이후, 더 이상 ","이 없으므로 NULL을 반환하고 strtok 함수 호출이 종료됩니다.

 

 

함수 헤더

 

 

strtok 함수는 C 표준 라이브러리의 <string.h> 헤더 파일에 선언되어 있습니다.

따라서 strtok 함수를 사용하기 위해서는 해당 헤더 파일을 프로그램에 포함시켜야 합니다.

 

아래와 같이 프로그램 파일의 맨 위에 string.h 헤더 파일을 포함시키면 됩니다.

 

#include <string.h>

 

 

 

strtok 주의할 점

주의점

strtok 함수를 사용할 때 주의해야 할 점이 있습니다.

1) 예제에서도 볼 수 있듯이 strtok 함수는 원래 문자열을 변경합니다. 이 때문에 strtok 함수를 사용하면 원래 문자열이 손상될 수 있습니다.

2) strtok 함수는 연속된 구분자를 처리할 때 빈 문자열도 토큰으로 취급합니다.

    예를 들어 "apple,,banana"와 같은 문자열에서 ","를 구분자로 사용하면 빈 문자열도 토큰으로 인식됩니다.

3) strtok 함수는 내부적으로 정적 변수(static variable)를 사용하기 때문에 여러 스레드에서 동시에 호출하면 예기치 않은 결과가 발생할 수 있습니다. 

 

해결 방법 

이러한 문제를 해결하려면 strtok_r 함수를 사용하면 됩니다. strtok_r 함수는 원래 문자열을 변경하지 않고, delimiter가 연속해서 나타나는 경우 빈 문자열을 토큰으로 처리하지 않습니다. 또한 strtok_r 함수는 스레드 안전성을 위해 호출 간 상태를 유지하기 위한 포인터 변수를 인수로 전달합니다. 따라서 여러 스레드에서 동시에 호출해도 안전하게 사용할 수 있습니다.

 

 

strtok_r 함수 설명

strtok_r 함수는 strtok 함수와 거의 비슷하지만, 두 가지 매개변수가 추가됩니다. strtok_r 함수의 원형은 다음과 같습니다.

char* strtok_r(char* str, const char* delim, char** saveptr);

첫 번째 매개변수와 두 번째 매개변수는 strtok 함수와 동일합니다. 그러나 세 번째 매개변수는 이전에 처리한 문자열을 저장하기 위한 포인터를 전달합니다. 이 포인터는 strtok_r 함수의 호출 간에 유지됩니다. 따라서 strtok_r 함수는 여러 문자열을 동시에 처리할 수 있습니다.

strtok_r 함수를 사용하여 "apple,banana,cherry,date" 문자열에서 ","를 구분자로 사용하여 문자열을 분할하면 다음과 같은 과정이 이루어집니다.

 

 

 

 

★ 최종 목표 : Split함수

 

C 언어에는 기본적으로 문자열을 분리하는 split 함수가 없지만, 직접 구현하여 사용할 수 있습니다.

아래는 Split 함수 입니다.

이 예시에서는 문자열을 구분자(delimiter)를 기준으로 분리한 후, 분리된 문자열들을 문자열 배열(String[]) 형태로 반환합니다. 이 때 문자열의 개수는 count 변수에 담습니다.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char** split(char* str, const char* delimiter, int* count) {
    int i, j, len;
    char* token;
    char** result = NULL;

    // 구분자로 문자열을 분리한 후, 문자열 개수(count)를 구합니다.
    token = strtok(str, delimiter);
    while (token != NULL) {
        (*count)++;
        result = (char**)realloc(result, (*count) * sizeof(char*));
        result[(*count) - 1] = token;
        token = strtok(NULL, delimiter);
    }

    // 문자열 개수(count)만큼의 문자열 배열을 동적으로 할당합니다.
    result = (char**)realloc(result, (*count) * sizeof(char*));

    // 문자열 배열에 분리된 문자열을 복사합니다.
    len = strlen(str);
    j = 0;
    for (i = 0; i < (*count); i++) {
        len -= strlen(result[i]) + strlen(delimiter);
        strncpy(result[i], str + j, strlen(result[i]));
        j += strlen(result[i]) + strlen(delimiter);
        result[i][strlen(result[i])] = '\0';
    }

    return result;
}

int main() {
    char str[] = "apple,banana,cherry,date";
    const char delimiter[] = ",";
    int count = 0;
    char** arr = split(str, delimiter, &count);

    for (int i = 0; i < count; i++) {
        printf("%s\n", arr[i]);
    }

    // 동적으로 할당한 문자열 배열 메모리를 해제합니다.
    for (int i = 0; i < count; i++) {
        free(arr[i]);
    }
    free(arr);

    return 0;
}

** 위 예시 코드는 문자열 배열을 동적으로 할당하여 사용하기 때문에, 사용 후에는 반드시 할당한 메모리를 해제해주어야 합니다.

 

 

위 코드를 실행하면 다음과 같은 결과가 출력됩니다.

apple
banana
cherry
date

 

아주 쉽죠~!!!

복붙해서 기본 내장함수처럼 편하게 사용하세요!

 

Free!! 메모리 해제하는 것 잊지말기!

 

반응형
그리드형

댓글

❤️김세인트가 사랑으로 키웁니다❤️