본문 바로가기
공부/C언어

[C언어] C언어 문자열 완벽 정리: NULL 문자부터 문자열 함수, 입출력까지

by 강갱갱 2025. 6. 14.

 

 

C언어 문자열 완벽 정리: NULL 문자부터 문자열 함수, 입출력까지

이번 글에서는 C언어 문자열에 관한 핵심 개념들을 꼼꼼하게 정리합니다. NULL 문자란 무엇인지, 문자열 초기화 방법, 입출력 함수 사용법, 그리고 문자열 처리에 유용한 다양한 함수들을 자세히 설명하며 예제 코드와 함께 쉽게 이해할 수 있도록 작성했습니다.


1. NULL 문자(종료 문자)란?

문자열의 끝을 나타내는 특별한 문자로, '\0' (널 문자)라고 부릅니다. 문자열은 내부적으로 이 NULL 문자를 만날 때까지 계속 출력됩니다. 예를 들어:

char str[] = "abc";
printf("%s", str);  // abc 출력, 내부적으로 "a", "b", "c", '\0'로 저장됨

만약 배열 선언 시 문자열 길이보다 배열 크기가 크면, 나머지 공간은 자동으로 '\0' 문자로 채워집니다.

주의! printf(str);처럼 형식 지정자 없이 문자열 변수를 바로 출력하려 하면 에러가 발생할 수 있으니 항상 printf("% s", str); 형식을 사용하세요.


2. 문자열 저장 공간과 초기화 방법

문자열을 저장하는 공간은 크게 두 가지로 나눌 수 있습니다:

  • 스택 메모리: 지역 변수로 선언된 문자열 배열
  • 힙 메모리: malloc 등으로 동적 할당한 공간

문자열 초기화 방법은 다양합니다.

  • char str [] = "HELLO"; // 문자열 상수로 초기화
  • char str[] = {'H', 'E', 'L', 'L', 'O', '\0'}; // 문자 배열 직접 초기화
  • char str [6]; strcpy(str, "HELLO"); // 문자열 복사
  • char* str = (char*) malloc(6 * sizeof(char)); strcpy(str, "HELLO"); // 동적 할당 후 복사

3. 문자 입출력 함수

문자를 입출력할 때는 버퍼를 사용하기 때문에 Enter 키를 눌러야 입력이 처리됩니다.

#include <stdio.h>

int main(void) {
  int ch;  // getchar() 반환형은 int!
  while ((ch = getchar()) != EOF) {
    putchar(ch);
  }
  return 0;
}
  • int getchar(void): 한 문자 읽기 (버퍼 사용)
  • void putchar(int c): 한 문자 출력 (버퍼 사용)
  • EOF: 파일 끝 표시, 보통 -1

버퍼를 사용하지 않는 함수들도 있는데, <conio.h>에 포함된 다음과 같습니다:

  • _getch(): 입력 문자 에코(화면 출력) 없음
  • _getche(): 입력 문자 에코 있음 (입력 문자 두 번 출력되는 현상 주의)
  • _putch(): 버퍼 사용 없이 문자 출력

4. 문자열 읽기와 출력 함수

  • gets_s(char s [], int length): 한 줄 전체 문자열 읽기 (보안 강화 버전)
  • puts(char s []): 문자열 출력 (자동으로 줄 바꿈 포함)

참고: gets_s는 환경에 따라 작동하지 않을 수 있고, 사용을 권장하지 않습니다. 대신 fgets를 사용하는 것이 안전합니다.


5. <ctype.h> - 문자 판별 및 변환 함수

이 함수들은 인자로 int형을 받지만 char형도 사용할 수 있습니다.

  • isalpha(c): 영문자 여부 검사
  • isupper(c): 대문자 여부
  • islower(c): 소문자 여부
  • toupper(c): 소문자를 대문자로 변환
  • tolower(c): 대문자를 소문자로 변환
  • toascii(c): 문자를 ASCII 코드로 변환

6. <string.h> - 문자열 처리 함수

  • strlen(s): 문자열 길이 반환 (NULL 문자 제외)
  • strcpy(s1, s2): s2를 s1에 복사
  • strcat(s1, s2): s2를 s1 끝에 이어 붙임
  • strcmp(s1, s2): 문자열 사전 순 비교 (음수: s1 < s2, 0: 같음)
  • strncpy(s1, s2, n): 최대 n 문자만 복사
  • strchr(s, c): 문자열 s에서 문자 c 탐색
  • strstr(s1, s2): s1에서 s2 문자열 찾기 (포인터 반환)
  • strtok(s, seps): 토큰 분리 함수, 구분자 문자열 seps 기준으로 문자열 분리

예를 들어 토큰 분리:

char* token;
char seps[] = ",\t\n";
token = strtok(s, ",");
while(token != NULL) {
  // 토큰 처리
  token = strtok(NULL, ",");
}

7. 문자열과 숫자 변환 및 포맷 함수

  • sscanf(s, "% s % d", name, &number): 문자열 s에서 형식에 맞게 데이터 읽기
  • sprintf(s, "정수 % d 더하기 % d는 % d다.", x, y, result): 형식화된 문자열을 s에 저장
  • atoi(const char* str): 문자열을 정수로 변환
  • atof(const char* str): 문자열을 실수(double)로 변환

8. 문자열 저장 방식과 주의사항

  • 문자열은 char 배열에 '\0'이 포함된 형태로 저장됩니다.
  • 변경 가능한 문자열은 스택 또는 힙에 저장되며, char* p = "HELLO"처럼 선언된 문자열은 텍스트 세그먼트에 저장되어 수정 불가합니다.
  • char s []는 배열이므로 수정 가능하지만, char* s에 문자열 리터럴을 직접 할당하면 수정하면 안 됩니다.
  • char a [][] (2차원 배열 형태)는 문자열 배열로 바로 초기화하기 어렵고, 대신 char* a [] 같은 포인터 배열로 관리합니다.
  • gets_s 같은 함수는 사용을 권장하지 않으며, 버퍼 크기를 직접 지정할 수 있는 fgets를 활용하세요.

마무리

이번 포스팅을 통해 C언어에서 문자열을 다룰 때 꼭 알아야 하는 기본 개념부터 고급 함수 활용법까지 폭넓게 다뤘습니다. 문자열은 단순한 문자 배열이 아니라, 끝을 알리는 NULL 문자('\0')가 필수이며, 입출력 함수와 다양한 문자열 처리 함수들을 올바르게 사용하는 것이 중요합니다.

특히 포인터와 함께 쓰이는 경우가 많으므로, 포인터의 개념을 확실히 익히고, 메모리 구조를 이해하는 것이 문자열 처리를 정확하게 하는 데 큰 도움이 됩니다.

궁금한 점이나 추가로 알고 싶은 부분이 있으면 언제든 댓글로 남겨주세요!

반응형