문자열 함수는 이름보다 작업 종류를 먼저 나누면 훨씬 덜 헷갈립니다.
문자열 함수는 이름순으로 외우기보다, 문자열 작업을 다섯 종류로 나눠 보는 편이 훨씬 빠릅니다.
- 이어 붙인다:
strncat - 찾는다:
strstr,strchr,strrchr - 토큰으로 나눈다:
strtok - 버퍼에 포맷팅한다:
snprintf - 문자열을 숫자로 바꾼다:
strtol,strtod
숏컷 코드
char buf[64] = "Hello";
strncat(buf, ", World", sizeof(buf) - strlen(buf) - 1);
char *pos = strstr(buf, "World");
if (pos) printf("found at offset %td\n", pos - buf);문법
문자열 함수는 이름을 하나씩 외우기보다 작업을 다섯 종류로 나누면 정리가 됩니다. 연결, 탐색, 토큰 분리, 포맷팅, 숫자 변환입니다.
char path[64] = "/tmp";
strncat(path, "/data.txt", sizeof(path) - strlen(path) - 1);
char out[64];
snprintf(out, sizeof(out), "%s/%s", "tmp", "data.txt");strcat은 남은 공간을 모르면 위험하고, sprintf는 목적지 크기를 모르기 때문에 버퍼 기반 작업에서는 strncat이나 snprintf가 먼저 떠올라야 합니다.
작업별 선택
탐색 함수는 결과를 인덱스가 아니라 원본 문자열 안의 위치 포인터로 돌려준다고 읽는 편이 맞습니다.
char text[] = "user@example.com";
char *at = strchr(text, '@');
char *domain = strstr(text, "example");strtok는 토큰을 잘라내는 대신 원본 버퍼를 직접 바꿉니다.
구분자를 '\0'로 바꿔 토큰을 나누는 방식이므로, 원본 문자열을 보존해야 하는 상황에는 바로 쓰면 안 됩니다.
또 내부 상태를 쓰므로 멀티스레드나 중첩 파싱에서 주의가 필요합니다.
char line[] = "red,green,blue";
char *token = strtok(line, ",");그래서 문자열 리터럴에 바로 strtok를 쓰는 건 위험합니다.
포맷과 변환
문자열 버퍼에 형식 문자열을 써 넣을 때는 크기 제한이 있는 snprintf가 기본입니다.
반환값으로 잘렸는지도 판단할 수 있습니다.
char out[32];
int written = snprintf(out, sizeof(out), "id=%d", 42);숫자 변환은 실패 여부와 남은 문자열을 같이 볼 수 있어야 합니다. 그래서 atoi보다 strtol/strtod가 더 실전적입니다.
char *end = NULL;
long value = strtol("123x", &end, 10);int n = atoi("123x"); /* 123, 실패 구분 어려움 */이런 경우 atoi는 어디까지 읽었는지 알기 어려워서, 검증이 필요한 입력에서는 strtol 쪽이 낫습니다.
선택 기준
- 문자열을 이어 붙인다:
strncat또는snprintf - 부분 문자열을 찾는다:
strstr - 문자 위치를 찾는다:
strchr,strrchr - 토큰 분리한다:
strtok(원본 수정 주의) - 포맷 문자열을 버퍼에 쓴다:
snprintf - 숫자로 바꾼다:
strtol,strtod
주의할 점
strtok는 원본 문자열을 수정하고 내부 상태를 사용합니다. 보존해야 하는 문자열이나 복잡한 파싱 흐름에서는 그대로 쓰면 의도와 달라질 수 있습니다.
char line[] = "apple,banana";
char *token = strtok(line, ",");또한 숫자 변환에서 atoi는 실패와 0을 구분하기 어렵습니다. 실패를 감지해야 하면 strtol을 우선하는 편이 낫습니다.
참고 링크
1 sources