icon안동민 개발노트

C 스타일 문자열


C 스타일 문자열 개요

 C 스타일 문자열은 널 종료 문자 '\0'로 끝나는 문자 배열입니다. C++에서도 이를 지원하며, 특히 레거시 코드나 C API와의 상호 운용성을 위해 중요합니다. C 스타일 문자열은 C 언어의 유산으로, 문자열 처리의 기본을 이해하는 데 중요한 역할을 합니다.

문자열 선언과 초기화

 문자 배열로 선언

#include <iostream>
 
int main() {
    char str1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
    char str2[] = "Hello";  // 컴파일러가 자동으로 널 문자 추가
 
    std::cout << "str1: " << str1 << std::endl;
    std::cout << "str2: " << str2 << std::endl;
 
    return 0;
}

 문자 포인터로 선언

#include <iostream>
 
int main() {
    const char* str3 = "Hello";  // 읽기 전용 문자열 리터럴
 
    std::cout << "str3: " << str3 << std::endl;
 
    return 0;
}

 주의 : 문자 포인터로 선언된 문자열 리터럴은 수정할 수 없습니다.

문자열 조작 함수 (cstring 헤더)

 strlen() : 문자열 길이

#include <iostream>
#include <cstring>
 
int main() {
    char str[] = "Hello";
    size_t length = strlen(str);
 
    std::cout << "문자열 \"" << str << "\"의 길이: " << length << std::endl;
 
    return 0;
}

 strcpy() : 문자열 복사

#include <iostream>
#include <cstring>
 
int main() {
    char src[] = "Hello";
    char dest[20];
 
    strcpy(dest, src);
 
    std::cout << "복사된 문자열: " << dest << std::endl;
 
    return 0;
}

 주의 : strcpy()는 버퍼 오버플로우의 위험이 있습니다. strncpy()를 사용하는 것이 더 안전합니다.

 strcat() : 문자열 연결

#include <iostream>
#include <cstring>
 
int main() {
    char str[20] = "Hello";
    strcat(str, " World");
 
    std::cout << "연결된 문자열: " << str << std::endl;
 
    return 0;
}

 strcmp() : 문자열 비교

#include <iostream>
#include <cstring>
 
int main() {
    const char* str1 = "apple";
    const char* str2 = "banana";
 
    int result = strcmp(str1, str2);
 
    if (result < 0)
        std::cout << str1 << " is less than " << str2 << std::endl;
    else if (result > 0)
        std::cout << str1 << " is greater than " << str2 << std::endl;
    else
        std::cout << str1 << " is equal to " << str2 << std::endl;
 
    return 0;
}

안전하지 않은 함수와 안전한 대안

 안전하지 않은 함수의 문제점

 strcpy(), strcat() 등의 함수는 버퍼 오버플로우의 위험이 있습니다. 이는 심각한 보안 취약점을 초래할 수 있습니다.

 안전한 대안

#include <iostream>
#include <cstring>
 
int main() {
    char dest[20];
    const char* src = "Hello, World!";
 
    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';  // 널 종료 문자 보장
 
    std::cout << "안전하게 복사된 문자열: " << dest << std::endl;
 
    return 0;
}

문자열과 숫자 변환

 atoi() : 문자열을 정수로

#include <iostream>
#include <cstdlib>
 
int main() {
    const char* str = "123";
    int num = atoi(str);
 
    std::cout << "문자열 \"" << str << "\"을 정수로 변환: " << num << std::endl;
 
    return 0;
}

 sprintf() : 숫자를 문자열로

#include <iostream>
#include <cstdio>
 
int main() {
    char str[20];
    int num = 123;
 
    sprintf(str, "%d", num);
 
    std::cout << "정수 " << num << "을 문자열로 변환: \"" << str << "\"" << std::endl;
 
    return 0;
}

C 스타일 문자열의 한계

  1. 길이 제한 : 배열의 크기를 미리 정해야 합니다.
  2. 버퍼 오버플로우 위험 : 문자열 조작 시 주의가 필요합니다.
  3. 문자열 조작의 어려움 : 연결, 삽입, 삭제 등의 작업이 복잡합니다.

C++ std::string과의 비교

#include <iostream>
#include <string>
 
int main() {
    std::string cpp_str = "Hello";
    cpp_str += " World";  // 간단한 문자열 연결
 
    std::cout << "C++ 문자열: " << cpp_str << std::endl;
 
    return 0;
}

 std::string은 동적 크기 조정, 안전한 조작, 편리한 멤버 함수 등 많은 장점을 제공합니다.

C 스타일 문자열과 std::string 간 변환

#include <iostream>
#include <string>
#include <cstring>
 
int main() {
    // std::string을 C 스타일로 변환
    std::string cpp_str = "Hello";
    const char* c_str = cpp_str.c_str();
 
    std::cout << "C 스타일 문자열: " << c_str << std::endl;
 
    // C 스타일을 std::string으로 변환
    char c_array[] = "World";
    std::string new_cpp_str(c_array);
 
    std::cout << "C++ 문자열: " << new_cpp_str << std::endl;
 
    return 0;
}

연습 문제

  1. 사용자로부터 두 문자열을 입력받아 연결하고 출력하는 프로그램을 작성하세요. (힌트 : gets() 대신 안전한 fgets()를 사용하세요)
  2. 주어진 문자열에서 특정 문자의 개수를 세는 함수를 구현하세요.
  3. C 스타일 문자열을 역순으로 만드는 함수를 작성하세요.


참고 자료