이 글에서는 문자열을 지정한 크기만큼 복사하는 Visual Sudio C/C++의 함수에 대해서 소개합니다.
전제 조건
이 글은 다음의 내용을 전제 조건으로 작성했습니다.
- 1문자는 1byte를 의미합니다.
- C/C++ 문자열은 문자열의 마지막을 알리는 널문자 0x00가 함수에 의해 자동으로 설정되거나 그렇지 않는 경우 프로그래머가 설정해야 합니다.
- cpySource는 복사 원본 문자열이라고 하겠습니다.
- copyDest1는 복사 사본 배열이라고 하겠습니다.
- strncpy_s 문법
- errno_t strncpy_s( char *strDest, size_t numberOfElements, const char *strSource, size_t count)
- 리턴값 strncpy_s(복사 사본 배열, 복사 사본 크기, 복사 원본 문자열, 복사 최대 크기)
- strncpy 문법
- errno_t strncpy( char *strDest, const char *strSource, size_t count)
- 리턴값 strncpy(복사 사본 배열, 복사 원본 문자열, 복사 최대 크기)
- strncpy 문법은 strncpy_s 문법에서 복사 사본 크기를 제외한 것과 동일하기 때문에 이 글에서는 strncpy_s에 대해서만 설명합니다.
- Visual Sudio C/C++ 프로그램 작성을 위한 글
문자열 상수 정의하기
우선, 다음 코드에서 정의한 배열 변수 cpySource의 크기가 얼마인지 확인해 봅시다.
#include <stdio.h>
void main() {
const char cpySource[] = "ABCDEFGHIJ";
printf("size of cpySource = %d\n", (int)sizeof(cpySource));
}
실행 결과, 다음과 같이 A부터 J까지의 문자 갯수는 10개지만 cpySource 배열의 크기는 11이 출력 되었습니다.
C:\Test002\x64\Debug>Test002.exe
size of cpySource = 11
“ABCDEFGHIJ“의 문자 갯수와 배열 변수에 설정된 크기가 다른 이유는 다음과 같습니다.
char cpySource[] = “ABCDEFGHIJ”; 실행 결과로 cpySource 변수는 다음과 같이 설정됩니다.
배열 index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
값 | A | B | C | D | E | F | G | H | I | J | 0x00 |
더 큰 배열 영역에 복사하기
다음 코드는 A부터 J까지 10개의 문자로 구성된 문자열 즉 “복사 원본 문자열”을 더 큰 100 크기의 배열 즉 “복사 사본 배열” 변수에 복사합니다.
#include <stdio.h>
#include <string.h>
void main() {
const char cpySource[] = "ABCDEFGHIJ";
char copyDest1[100];
memset(copyDest1, 0x00, sizeof(copyDest1));
printf("size of cpySource = %d\n", (int)sizeof(cpySource));
printf("size of copyDest1 = %d\n", (int)sizeof(copyDest1));
strncpy_s(copyDest1, sizeof(copyDest1), cpySource, sizeof(copyDest1)-1);
printf("cpySource=%s\n",cpySource);
printf("copyDest1=%s\n",copyDest1);
}
실행 결과, strncpy_s 함수에 지정할 “복사 최대 크기“는 sizeof(copyDest1)-1 의 99입니다만 이보다 작은 11 크기의 “복사 원본 문자열” cpySource가 복사되었음을 확인할 수 있습니다.
C:\Test002\x64\Debug>Test002.exe
size of cpySource = 11
size of copyDest1 = 100
cpySource=ABCDEFGHIJ
copyDest1=ABCDEFGHIJ
copyDest1 변수에는 다음과 같이 복사됩니다.
배열 index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | … | 99 | 100 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
값 | A | B | C | D | E | F | G | H | I | J | 0x00 | 0x00 | 0x00 | 0x00 |
더 작은 배열 영역에 복사하기
다음 코드는 A부터 J까지10개의 문자로 구성된 문자열 즉 “복사 원본 문자열”을 더 작은 5 크기의 배열 즉 “복사 사본 배열” 변수에 복사합니다.
#include <stdio.h>
#include <string.h>
void main() {
const char cpySource[] = "ABCDEFGHIJ";
char copyDest1[5];
memset(copyDest1, 0x00, sizeof(copyDest1));
printf("size of cpySource = %d\n", (int)sizeof(cpySource));
printf("size of copyDest1 = %d\n", (int)sizeof(copyDest1));
strncpy_s(copyDest1, sizeof(copyDest1), cpySource, sizeof(copyDest1)-1);
printf("cpySource=%s\n",cpySource);
printf("copyDest1=%s\n",copyDest1);
}
실행 결과, strncpy_s 함수에 지정한 “복사 최대 크기” sizeof(copyDest1)-1 의 4로 인해서 copyDest1에는 A부터 D까지 4개의 문자가 복사되고 마지막에 0x00 값이 설정되었음을 알 수 있습니다.
C:\Test002\x64\Debug>Test002.exe
size of cpySource = 11
size of copyDest1 = 5
cpySource=ABCDEFGHIJ
copyDest1=ABCD
copyDest1 변수에는 다음과 같이 복사됩니다.
배열 index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
값 | A | B | C | D | 0x0 |
“복사 최대 크기” 지정 오류
참고로 위에서 설명한 “더 작은 배열 영역에 복사하기“의 경우, 다음과 같이 strncpy_s 함수에 지정할 “복사 최대 크기“에 다음과 같이 sizeof(copyDest1) 는 5를 지정하면 메모리 에러가 발생합니다.
strncpy_s(copyDest1, sizeof(copyDest1), cpySource, sizeof(copyDest1));
C:\Test002\x64\Debug>Test002.exe
그 이유는 다음과 같이 “복사 최대 크기” 5만큼 전부 문자로 채워져 컴퓨터 메모리 copyDest1에 문자열의 끝을 알리는 널문자 0x0가 설정되지 못했기 때문 입니다.
배열 index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
값 | A | B | C | D | E |
이 오류를 해결하기 위해서는 다음과 같이 조건을 만족해야 합니다.
- 복사 원본 문자열과 복사 사본의 배열 변수의 크기가 같고 복사 원본의 문자열은 0x00로 끝날 것
const char cpySource[] = "ABCDEFGHIJ";
char copyDest1[11];
- 복사 원본 문자열 크기 보다 복사 사본의 배열 변수의 크기가 더 클 것
- 본사 원본 문자열 크기 보다 복사 사본의 배열 변수의 크기가 더 작은 경우 strncpy_s함수에 지정 할 “복사 최대 크기“에 복사 사본의 배열 변수의 크기 -1 을 설정할 것
“복사 최대 크기” 지정 방법 비교
strncpy_s 함수에 지정할 “복사 최대 크기“는 다음과 같이 2가지의 지정 방법이 있습니다. 어느 쪽이든 같은 결과를 얻을 수 있습니다.
strncpy_s(copyDest1, sizeof(copyDest1), cpySource, sizeof(copyDest1)-1);
strncpy_s(copyDest1, sizeof(copyDest1), cpySource, _TRUNCATE);