[C] string

muz·2021년 5월 3일

문자열(string)

""를 이용해 표현되는 문자열을 문자열 상수(string constant)라고 한다. 이를 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않고, 문자열의 내용 또한 변경할 수 없기 때문이다.

string은 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미하기에 문자열 배열을 선언하면 이 배열이 곧 문자열 변수가 된다.

  • 문자열 상수 및 변수를 선언하는 방법들
char strA[] = "This is a string."; // 크기를 지정하지 않고 문자열 변수 선언
char strB[7] = "string"; // 크기를 지정하여 문자열 변수 선언

printf("문자열 상수\n");
printf("문자열strA에 저장되어 있는 문자열 : %S\n", strA);
printf("문자열strB에 저장되어 있는 문자열 : %S\n", strB);

printf() 함수에서 사용된 "%s"는 문자열 표현을 위한 입출력 서식 문자임

null문자

C언어에서는 문자열에 속한 데이터가 끝나면 문자열의 끝을 의미하는 문자를 하나 더 삽입한다. 이 문자를 널(NULL)이라 하며, '\0'이라쓰고 아스키코드값은 0이다. 이렇게 끝을 프로그램에게 알려줌으로써 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레기값을 구분할 수 있게끔 한다.

int str_len = 0;
char str[] = "string";

while (str[str_len] != '\0') { // 널 문자가 나올 때까지 길이를 증가함
    str_len++; }
printf("이 문자열의 길이는 %d입니다.\n", str_len);


위의 사진은 사용된 문자열이 메모리 상에 저장되어있는 것을 보여준다.

문자열 입출력 함수

fgets()함수

C언어에서 문자열을 입력할 때에는 fgets()함수를 사용한다. 이는 키보드의 입력뿐만이 아닌 파일에서도 문자열을 입력받을 수 있는 함수이다.

#include <stdio.h>
char *fgets(char *restrict s, int n, FILE *restrict stream);
  • char *restrict s : 입력받는 문자열의 저장을 위해 선언한 배열의 시작주소를 전달
  • int n : 입력받을 수 있는 문자열의 최대 길이 전달
  • restrict stream : 문자열을 입력받을 스트림 전달

문자열 출력 함수

C언어에서 문자열을 출력할 때에는 puts()나 fputs()를 사용한다.

puts()함수

puts()는 표준 출력 스트림(stdout)인 모니터에 하나의 문자열을 출력하는 함수로, 모니터에 문자열을 출력한 다음 자동으로 줄바꿈을 해준다.

#include <stdio.h>
int puts(const char *s);
  • const char *s : 인수로 출력할 문자열을 가리키는 포인터를 전달함

fputs()함수

fputs()는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수이다. 이는 문자열 출력 후 자동으로 줄을 바꿔주지 않는다.

#include <stdio.h>
int fputs(const char *restrict s, FILE *restrict stream);
  • const char *restrict s : 출력할 문자열을 가리키는 포인터를 전달함
  • FILE *restrict stream : 문자열을 출력할 스트림을 전달함

puts()는 문자열을 출력한 후 자동으로 줄 바꿈을 해주지만, fputs()는 문자열 출력 후 줄 바꿈을 하지 않는다.

#include <stdio.h>

int main(void)
{
    char str[100];

    fputs("문자열을 입력해 주세요 :\n", stdout);
    fgets(str, sizeof(str), stdin);
    puts("입력하신 문자열 : ");
    puts(str);

    fputs("입력하신 문자열 : ", stdout);
    fputs(str, stdout);
    return 0;
}

문자열 처리 함수

C언어에서 문자열은 마지막에 Null문자를 가지는 문자형 배열로 표현되며, 기본 타입에는 포함되지 않아 문자열을 처리하기 위한 다양한 함수를 별도로 사용해야 한다.

1. strlen()함수

인수로 전달된 문자열의 길이를 반환하는 함수이다.

#include <string.h>
size_t strlen(const char *s);

이 때, 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다.

  • example
char str[] = "C언어";  
printf("문자열의 길이: %d\n", strlen(str)); // 결과 : 7

utf-8 인코딩 환경에서 한글은 한 문자당 3byte로 처리된다.

2. strcat(), strncat()함수

strcat()과 strncat()함수는 하나의 문자열에 다른 문자열을 연결해주는 함수이다.

#include <string.h>
char *strcat(char *restrict s1, const char *restrict s2);  
  • char *restrict s1 : 기준 문자열
  • const char *restrict s2 : 추가하고자 하는 문자열의 복사본

📌 restrict 키워드
: 포인터의 선언에서만 사용할 수 있는 C99부터 추가된 키워드로, 포인터 선언 시 이를 이용하면 컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시함


Q. 기준 문자열이 저장된 배열의 공간이 충분하지 않으면 어떻게 될까?
A. 배열을 채우고 남은 문자들이 배열 외부로 흘러넘칠 수 있음 ⇒ 오버플로우(overflow)

오버플로우 방지를 위해서는 strcat()대신 strncat()을 쓰는 것이 좋다.
strncat()은 추가할 문자열의 최대 길이를 지정할 수 있는 3번째 인수가 있기 때문이다. 이는 null문자를 만나거나 추가하는 문자의 개수가 3번째 인수로 전달된 최대 길이에 도달할 때까지 추가를 계속한다.

#include <string.h>
char *strncat(char * restrict s1, const char * restrict s2, size_t n);  
  • example
char str01[20] = "C language is "; // 널 문자를 포함하여 15문자
char str02[] = "Cool! and funny!";  
//strcat(str01, str02);   // 이 부분을 실행시키면 배열 오버플로우 발생 
strncat(str01, str02, 5); // 최대 길이를 설정해 놓으면 오버플로우가 발생하지 않음
puts(str01);

Q. strncat()에서 3번째 인수로 5가 들어간 이유?
A. 원래 null문자를 포함한 총 14byte의 문자열을 19byte의 배열에 저장한다. 이후 이 문자열에 5byte 크기의 문자열을 추가해줌으로써 19byte를 맞추어 준 것이다.

3. strcpy(), strncpy()함수

strcpy(), strncpy()는 문자열을 복사하는 함수이다.

#include <string.h>
char *strcpy(char * restrict s1, const char * restrict s2);  
  • char * restrict s1 : 첫 번째 인수로 전달된 배열에
  • const char * restrict s2 : 두 번째 인수로 전달된 문자열을 복사함

만약 첫 번째 인수로 전달된 배열의 크기 < 복사할 문자열의 길이 이면 배열 오버플로우가 발생한다. 이를 방지하기 위해 strncpy()를 사용한다.

strncpy()도 위의 strncat()처럼 세 번째 인수가 추가된 것이다. 이 세 번째 인수에 복사할 문자열의 최대 길이를 지정해줄 수 있다. strncpy()는 null문자를 만나거나, 복사하는 문자의 개수가 3번째 인수로 전달된 최대 길이에 도달할 때까지 계속 복사한다.

#include <string.h>
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);   

포인터 연산을 이용하면 수정을 시작할 지점을 지정할 수 있다.

  • example
char str01[20] = "C is Cool!";
char str02[11];  

// str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임
strncpy(str02, str01, sizeof(str02)-1);
str02[sizeof(str02)-1] = '\0'; // 이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음
puts(str02);

// --------------------------------
char str[20] = "C is cool!";  
strncpy(str+5, "nice", 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함
puts(str);

4. strcmp(), strncmp()함수

strcmp()와 strncmp()는 문자열의 내용을 비교하는 함수이다.

strcmp()는 인수로 두 개의 문자열 포인터를 전달받아, 해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. 두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, 문자열의 맨 앞에서부터 순서대로 비교된다.

#include <string.h>
int strcmp(const char *s1, const char *s2);  

strcmp()의 상황별 반환값

  • 반환값이 양수 : 첫 번째 인수로 전달된 문자열 > 두 번째 인수로 전달된 문자열
  • 반환값이 0 : 두 문자열의 내용이 완전히 같은 경우
  • 반환값이 음수 : 첫 번째 인수로 전달된 문자열 < 두 번째 인수로 전달된 문자열

strncmp()도 세 번째 인수에 비교할 문자의 개수를 지정할 수 있다. 이는 일치하지 않는 문자를 만나거나 세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다.

#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);  
  • example
#include <stdio.h>
#include <string.h>  

int main(void)
{
    char str[20];
    char ch;  

    while (1)
    {
        puts("미국의 수도를 입력하세요 :");
        scanf("%s", str);
        if (strcmp(str, "워싱턴") == 0 || strcmp(str, "washington") == 0) // 문자열의 비교
        {
            puts("정답입니다!");
            break;
        }else {
            puts("아쉽네요~"); }
        fflush(stdin);  
        
        puts("\n이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!");
        puts("계속 도전하고자 하시면 Enter를 눌러주세요!");
        scanf("%c", &ch);  
        if (ch == 'q') // 문자의 비교
        {
            break;
        }
        fflush(stdin);
    }
    return 0;
}

strcmp() 함수는 문자열을 비교하는 함수이므로, 문자를 비교할 때에는 관계연산자 '=='를 사용해야 한다.

5. atoi(), atol(), atoll(), atof()함수

이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수이다.

#include <stdlib.h>
int atoi(const char *nptr);            // int형 정수로 변환
long int atol(const char *nptr);       // long형 정수로 변환
long long int atoll(const char *nptr); // long long형 정수로 변환
double atof(const char *nptr);         // double형 실수로 변환

6. toupper(), tolower()함수

이 함수들은 인수로 전달된 문자열의 영문자를 모두 대문자 or 소문자로 변환시켜주는 함수이다.

#include <ctype.h>
int toupper(int c); // 문자열의 모든 영문자를 대문자로 변환
int tolower(int c); // 문자열의 모든 영문자를 소문자로 변환

Reference
1. 문자열
2. 문자열 입출력 함수
3. 문자열 처리 함수

profile
Life is what i make up it 💨

0개의 댓글