C언어에서 CSV 데이터나 명령어 포맷을 처리할 때 특정 기호를 기준으로 문자열을 나누는 작업은 필수입니다. 이때 가장 많이 쓰이는 함수가 문자열 분할의 strtok과 동적 복제의 strdup입니다.
오늘은 이 두 함수의 상세한 동작 원리와 함께, 실무에서 주의해야 할 메모리 관리 방법을 정리해 보겠습니다.

1. strtok: 구분자로 문자열 자르기 (Tokenization)
strtok 함수는 문자열을 특정 구분자(Delimiter)를 기준으로 나누어 토큰(Token) 단위로 분할합니다.
1.1 함수 원형
char *strtok(char *str, const char *delim);
1.2 동작 원리 (중요!)
strtok은 단순히 문자열을 찾는 것에 그치지 않고 원본 문자열을 직접 수정합니다.
- 구분자를 찾으면 그 위치에 널 문자(\0)를 삽입하여 문자열을 끊습니다.
- 첫 번째 호출 시에는 대상 문자열(str)을 인자로 주지만, 두 번째 호출부터는 NULL을 전달하여 이전 위치 다음부터 탐색을 이어갑니다.
1.3 예제 코드
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "C,Python;Java:JavaScript";
const char *delim = ",;:"; // 여러 개의 구분자 지정 가능
char *token;
// 첫 번째 호출: 대상 문자열 전달
token = strtok(str, delim);
while (token != NULL) {
printf("Token: %s\n", token);
// 두 번째 호출부터는 NULL 전달
token = strtok(NULL, delim);
}
return 0;
}
⚠️ 주의사항: strtok은 원본 문자열을 변형시키므로, 원본 데이터를 보존해야 한다면 반드시 복사본을 만들어 작업해야 합니다. 또한 내부 정적 변수를 사용하므로 멀티스레드 환경에서는 안전한 strtok_r을 권장합니다.
2. strdup: 문자열 동적 복제 (Duplicate)
strdup은 원본 문자열과 똑같은 새로운 문자열을 힙(Heap) 메모리에 생성합니다.
2.1 함수 원형
char *strdup(const char *s);
2.2 특징 및 장점
- 동적 할당: 내부적으로 malloc을 호출하여 원본 문자열 크기(+ 널 문자 1바이트)만큼 메모리를 할당합니다.
- 독립성: 복제된 문자열은 원본과 별개의 메모리 주소를 가지므로 서로 영향을 주지 않습니다.
2.3 예제 코드
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char original[] = "Hello, world!";
char *copy = strdup(original); // 내부에서 malloc 실행
if (copy != NULL) {
printf("원본 주소: %p, 복제본 주소: %p\n", (void*)original, (void*)copy);
printf("복제된 내용: %s\n", copy);
free(copy); // 사용 후 반드시 메모리 해제!
}
return 0;
}
3. 실전 활용: 분할된 토큰 안전하게 저장하기
strtok은 원본을 훼손하므로, 분할된 각 단어를 나중에 다시 사용하려면 strdup으로 각각 복제해 두는 방식이 실무에서 자주 쓰입니다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str[] = "Apple,Banana,Cherry";
char *token;
char *saved_tokens[3];
int i = 0;
token = strtok(str, ",");
while (token != NULL && i < 3) {
// 분할된 토큰을 동적으로 복제하여 저장
saved_tokens[i++] = strdup(token);
token = strtok(NULL, ",");
}
for (int j = 0; j < i; j++) {
printf("저장된 토큰 [%d]: %s\n", j, saved_tokens[j]);
free(saved_tokens[j]); // 할당된 메모리 반환
}
return 0;
}
4. 핵심 요약 및 비교
| 함수 | 주요 기능 | 메모리 특징 | 주의사항 |
| strtok | 문자열 분할 | 원본 문자열 수정 | 멀티스레드 주의 (strtok_r 권장) |
| strdup | 문자열 복제 | 힙 메모리 동적 할당 | 사용 후 반드시 free() 호출 |
마무리하며
문자열 파싱은 C언어의 강력하면서도 까다로운 부분입니다. strtok으로 데이터를 나누고, strdup으로 필요한 데이터를 안전하게 보관하는 패턴을 익히면 더 복잡한 데이터 처리도 충분히 해낼 수 있습니다.
포스팅이 도움이 되셨다면 하트(♥)와 댓글 부탁드립니다!
임베디드 소프트웨어 및 최적화 기법에 대한 전문적인 정보는 'Coding by Head' 블로그에서 계속됩니다.
'Core Programming > C Standard Library: Resource & Performan' 카테고리의 다른 글
| C언어 문자열 숫자 변환: atoi, atof 대신 strtol을 써야 하는 이유 (정리) (0) | 2025.02.15 |
|---|---|
| C언어 문자열 검색 완벽 가이드: strspn과 strcspn 차이 및 실전 활용법 (0) | 2025.02.14 |
| C언어 문자열 검색 완벽 가이드: strchr과 strstr 함수 사용법 및 차이점 (0) | 2025.02.12 |
| C언어 문자열 비교 완벽 가이드: strcmp와 strncmp 사용법 및 원리 (0) | 2025.02.11 |
| C언어 문자열 이어붙이기 완벽 가이드: strcat과 strncat의 안전한 사용법 (0) | 2025.02.10 |