Skip to content

35. 문자열 복사/결합


1. 키워드

  • strcpy(String Copy)
  • strcat(String Concatenate)


2. 문자열을 복사하고 붙이기

  • 이번에는 문자열을 다른 곳으로 복사하는 방법과 두 문자열을 붙이는 방법을 알아보자


3. 문자열 복사하기

  • 문자열은 다른 배열이나 포인터(메모리)로 복사할 수 있다.
  • string.h 헤더 파일에 선언되어 있는 strcpy 함수를 사용하면 문자열을 다른 곳으로 복사할 수 있다.


strcpy(대상문자열, 원본문자열);
대상문자열의 포인터를 반환
#define _CRT_SECURE_NO_WARNINGS // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcpy 함수가 선언된 헤더 파일

int main()
{
    char s1[10] = "Hello"; // 크기가 10인 char 타입 배열을 선언하고 문자열 할당
    char s2[10];           // 크기가 10인 char 타입 배열을 선언

    strcpy(s2, s1); // s1의 문자열을 s2로 복사

    printf("%s\n", s2);

    return 0;
}

// Hello


  • 먼저 "Hello" 문자열이 들어있는 배열 s1과 아무것도 들어있지 않은 배열 s2를 선언했다.
  • 그리고 strcpy(s2, s1)와 같이 strcpy 함수에 복사된 결과가 저장될 문자열과 복사할 문자열을 넣는다.
  • 이렇게 하면 s2s1의 문자열이 복사된다.


001


  • 복사된 결과가 저장될 배열의 크기는 반드시 NULL까지 들어갈 수 있어야 한다.
  • 크기가 더 작다면 복사가 되더라도 문자열이 정상적으로 출력되지 않는다.
  • 따라서 "Hello" 문자열이 복사되려면 배열의 크기는 최소한 6이 되어야 한다.


  • 지금까지 문자 배열(char 타입 배열)을 사용하여 문자열을 복사했다.
  • 그러면 문자열 포인터에 복사하면 어떻게 되는지 확인해 보자.


#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcpy 함수가 선언된 헤더 파일

int main()
{
    char *s1 = "Hello"; // 문자열 포인터
    char *s2 = "";      // 문자열 포인터

    strcpy(s2, s1); // 실행 에러

    printf("%s\n", s2);

    return 0;
}


  • strcpy 함수로 문자열 포인터 s1을 문자열 포인터 s2로 복사했다.
  • 복사가 될 것 같지만 실행을 해보면 에러가 발생한다.
  • 왜냐하면 s2에 저장된 메모리 주소는 복사할 공간도 없을 뿐더러 읽기만 할 수 있고, 쓰기가 막혀있기 때문이다.


002


문자열과 읽기 전용 메모리

  • char *s1 = "Hello"; char *s2 = "";와 같이 문자열 포인터에 할당된 문자열은 읽기 전용이다.
  • 왜냐하면 C 컴파일러는 문자열 포인터에 할당한 문자열 리터럴을 실행 파일의 읽기 전용 데이터 섹션(데이터 세그먼트)에 배치하기 때문이다.
  • 따라서 실행 파일이 실행된 뒤에는 읽기 전용 메모리가 되며 쓰기를 할 수 없다.
  • 다음은 각 OS별 읽기 전용 데이터 섹션 이름이다.


1] Windows PE

  • .rdata

2] 리눅스 ELF

  • .rodata

3] OSX

  • __TEXT, __cstring


  • 문자열 포인터에 문자열을 복사하려면 문자열이 들어갈 공간을 따로 마련해야 한다.
  • 따라서 다음과 같이 malloc 함수로 메모리를 할당한 뒤 문자열을 복사한다.


#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcpy 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일

int main()
{
    char *s1 = "Hello";                   // 문자열 포인터
    char *s2 = malloc(sizeof(char) * 10); // char 타입 10개 크기만큼 동적 메모리 할당

    strcpy(s2, s1); // s1의 문자열을 s2로 복사

    printf("%s\n", s2);

    free(s2); // 동적 메모리 해제

    return 0;
}

// Hello


  • char *s2 = malloc(sizeof(char) * 10);처럼 char 타입 10개 크기만큼 동적으로 메모리를 할당했다.
  • 이렇게 하면 strcpy 함수로 s1의 문자열을 s2에 복사해서 넣을 수 있다.
  • 문자열 사용이 끝났다면 반드시 free 함수로 동적 할당한 메모리를 해제한다.


003


4. 문자열 붙이기

  • string.h 헤더 파일에 선언되어 있는 strcat 함수를 사용하면 문자열을 서로 붙일 수 있다.


strcat(최종문자열, 붙일문자열);
최종 문자열의 포인터를 반환
#define _CRT_SECURE_NO_WARNINGS // strcat 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcat 함수가 선언된 헤더 파일

int main()
{
    char s1[10] = "world";
    char s2[20] = "Hello"; // s2 뒤에 붙일 것이므로 배열 크기를 크게 만듦

    strcat(s2, s1); // s2 뒤에 s1을 붙임

    printf("%s\n", s2);

    return 0;
}

// Helloworld


  • strcat(s2, s1)과 같이 strcat 함수에 최종 결과가 나올 문자열과 붙일 문자열을 넣는다.
  • 이렇게 하면 s2 뒤에 s1을 붙여서 "Helloworld"가 나온다.
  • 여기서 주의할 부분은 최종 결과가 나올 문자열의 배열 크기이다.
  • 문자열을 붙이더라도 NULL 까지 들어갈 수 있도록(배열이 모자라지 않도록) 크기를 넉넉하게 만든다.


004


  • 지금까지 배열 형태로 된 문자열을 붙였다.
  • 그러면 문자열 포인터는 어떻게 붙이는지 확인해 보자.


#define _CRT_SECURE_NO_WARNINGS // strcat 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcat 함수가 선언된 헤더 파일

int main()
{
    char *s1 = "world"; // 문자열 포인터
    char *s2 = "Hello"; // 문자열 포인터

    strcat(s2, s1); // 실행 에러

    printf("%s\n", s2);

    return 0;
}


  • strcat 함수로 문자열 포인터 s2 뒤에 문자열 포인터 s1을 붙였다.
  • 하지만 실행해 보면 에러가 발생한다.
  • 문자열 포인터 s2는 읽기 전용 메모리라서 문자열을 붙일 수 없다.


005


  • 문자열을 붙이려면 s2에 쓰기가 가능하도록 malloc 함수로 동적 메모리를 할당하고, 문자열을 붙일 수 있도록 공간도 넉넉하게 20으로 설정해 준다.


#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcat 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일

int main()
{
    char *s1 = "world";                   // 문자열 포인터
    char *s2 = malloc(sizeof(char) * 20); // char 타입 20개 크기만큼 동적 메모리 할당

    strcpy(s2, "Hello"); // s2에 "Hello" 문자열 복사

    strcat(s2, s1); // s2 뒤에 s1을 붙임

    printf("%s\n", s2);

    free(s2); // 동적 메모리 해제

    return 0;
}

// Helloworld


  • 먼저 char *s2 = malloc(sizeof(char) * 20);처럼 char 타입 20개 크기만큼 동적으로 메모리를 할당한다.
  • 그리고 메모리가 할당된 문자열 포인터에는 문자열을 =로 직접 할당할 수 없으므로 strcpy 함수를 사용하여 s2"Hello" 문자열을 복사한다.
  • s2가 준비되었으면 strcat 함수로 문자열 포인터 s2 뒤에 문자열 포인터 s1을 붙이면 된다.
  • 문자열 사용이 끝났다면 반드시 free 함수로 동적 할당한 메모리를 해제한다.


006


5. 배열 형태의 문자열을 문자열 포인터에 복사하기

  • 이번에는 배열 형태의 문자열을 문자열 포인터에 복사해 보자.


#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcpy 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일

int main()
{
    char s1[10] = "Hello";                // 크기가 10인 char 타입 배열을 선언하고 문자열 할당
    char *s2 = malloc(sizeof(char) * 10); // char 타입 10개 크기만큼 동적 메모리 할당

    strcpy(s2, s1); // s1의 문자열을 s2로 복사

    printf("%s\n", s2);

    free(s2); // 동적 메모리 해제

    return 0;
}

// Hello


  • 먼저 malloc 함수로 s2에 메모리를 할당한다.
  • 당연히 할당할 메모리 공간은 복사될 문자열보다 커야 한다.
  • 여기서는 메모리 공간이 10바이트이므로 "Hello"(다섯 글자 + NULL 하나)는 충분히 들어갈 수 있다.
  • 그리고 strcpy 함수로 s1의 문자열을 s2에 복사하면 된다.


007


6. 배열 형태의 문자열을 문자열 포인터에 붙이기

  • 이번에는 배열 형태의 문자열을 문자열 포인터에 붙여보자.


#define _CRT_SECURE_NO_WARNINGS // strcpy, strcat 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h> // strcpy, strcat 함수가 선언된 헤더 파일
#include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일

int main()
{
    char s1[10] = "world";                // 크기가 10인 char 타입 배열을 선언하고 문자열 할당
    char *s2 = malloc(sizeof(char) * 20); // char 타입 20개 크기만큼 동적 메모리 할당

    strcpy(s2, "Hello"); // s2에 "Hello" 문자열 복사

    strcat(s2, s1); // s2 뒤에 s1을 붙임

    printf("%s\n", s2);

    free(s2); // 동적 메모리 해제

    return 0;
}

// Helloworld


  • 문자열 포인터 s2 뒤에 문자열을 붙일 것이므로 먼저 malloc 함수로 메모리를 할당한다.
  • 문자열이 더 붙더라도 메모리가 모자라지 않도록 넉넉하게 할당한다.
  • 그리고 strcpy 함수로 s2"Hello" 문자열을 복사해 준다.
  • s2가 준비되었으면 strcat 함수로 문자열 포인터 s2 뒤에 문자열 포인터 s1을 붙이면 된다.
  • 그리고 문자열 사용이 끝났다면 반드시 free 함수로 동적 할당한 메모리를 해제한다.


008


References