Quick Syntax
C 문자열은 별도 타입이 아니라 널 종료된 char 배열이라는 전제부터 잡아야 합니다.
문자열은 마지막 \0까지 포함한 char 배열입니다. sizeof는 buffer byte 수, strlen은 \0 앞 문자 byte 수이며, 내용 비교에는 strcmp를 씁니다.
char name[20] = "Mina";
size_t len = strlen(name);
int same = (strcmp(name, "Mina") == 0);
char copy[20];
int written = snprintf(copy, sizeof copy, "%s", name);
if (written < 0 || (size_t)written >= sizeof copy) {
/* 인코딩 오류 또는 잘림 */
}strlen·strcmp·%s는 널 종료를 찾을 수 있는 buffer만 받습니다. ==는 문자열 내용이 아니라 두 포인터 주소를 비교합니다.
문법
C 문자열은 결국 문자 배열 + 널 종료 문자 '\0' 입니다. 그래서 길이, 비교, 복사, 입력이 모두 이 규약을 전제로 움직입니다.
char s[] = "Hello";
char t[6] = {'H', 'e', 'l', 'l', 'o', '\0'};두 선언은 같은 문자열을 표현합니다. sizeof(s)는 배열 전체 바이트 수를 보고, strlen(s)는 널 종료 전까지의 문자 개수를 셉니다.
printf("%zu\n", sizeof(s)); // 6
printf("%zu\n", strlen(s)); // 5기본 작업
배열/포인터를 ==로 비교하면 내용이 아니라 주소를 비교하게 됩니다.
문자열이 같은지 보려면 strcmp 계열을 써야 합니다.
char a[] = "cat";
char b[] = "cat";
if (strcmp(a, b) == 0) {
/* 문자열 내용이 같음 */
}반대로 이 비교는 의도와 다릅니다.
if (a == b) {
/* 같은 주소인지 비교 */
}복사도 같은 원리입니다. 문자열 함수는 대부분 목적지 버퍼 크기를 자동으로 모르기 때문에, 복사 그 자체보다 버퍼 경계를 같이 추적하는 습관이 더 중요합니다.
char src[] = "hello";
char dst[16];
snprintf(dst, sizeof(dst), "%s", src);입력과 버퍼
char buf[] = "hello";는 수정 가능한 배열 복사본이고, const char *p = "hello";는 읽기 전용 리터럴을 가리키는 경우가 많습니다.
이 차이를 놓치면 수정 시점에 바로 위험해집니다.
char literal[] = "hello";
literal[0] = 'H'; // 가능
const char *view = "hello";
/* view[0] = 'H'; */ // 위험입력은 더 민감합니다. %s는 공백에서 끊기고 길이 제한을 빼먹으면 바로 버퍼를 넘깁니다. 줄 입력이 필요하거나 안전성이 중요하면 fgets가 기본에 가깝습니다.
char line[32];
if (fgets(line, sizeof(line), stdin) != NULL) {
line[strcspn(line, "\n")] = '\0';
}이 패턴은 공백을 포함한 줄 입력을 받을 수 있다는 점에서도 %s보다 낫습니다.
fgets가 NULL을 반환하면 EOF 또는 오류이므로 버퍼 내용을 새 입력으로 처리하면 안 됩니다. 개행이 없고 버퍼 끝까지 찼다면 긴 줄이 잘렸을 수 있어, 남은 입력을 비울지 오류로 처리할지 정책을 정합니다. strlen은 바이트 수이며 UTF-8 글자 수를 세지 않습니다.
빠른 점검
- 문자열 길이를 센다:
strlen - 문자열 내용을 비교한다:
strcmp(...) == 0 - 버퍼에 복사한다: 길이 제한과 널 종료 확인
- 입력을 받는다: 버퍼 크기와 함께 읽는다
- 문자열 리터럴을 받는다:
const char * sizeof와strlen은 묻는 질문이 다르다
주의할 점
버퍼 오버플로우는 C 문자열 처리에서 가장 흔하고 위험한 버그입니다.
char name[10];
// ❌ 길이 제한 없는 입력
scanf("%s", name);
// ✅ 길이 제한 포함
scanf("%9s", name);
// ✅ 또는 fgets 사용
fgets(name, sizeof(name), stdin);또한 문자열 비교는 ==가 아니라 strcmp로 해야 하고, 널 종료가 깨진 버퍼에 strlen을 쓰면 끝을 넘어 읽게 됩니다.
참고 링크
3 sources