[C++] wchar_t 배열 함수 - wcslen(), wcscat_s(), wcscmp(), wcscpy_s()

2024. 3. 27. 23:27Programming Language/C++

아래 링크 클릭 시 해당 본문으로 이동

wcslen()

wcscat_s()

wcscmp()

wcscpy_s()

해당 본문 내용은 문자열 함수 본문과는 char와 wchar_t 차이지, 대부분의 내용은 거의 비슷하다.

겹치는 내용은 최대한 제외했다.

참고 링크
• 문자열 함수

wcslen(), wcscat_s(), wcscmp(), wcscpy_s()

헤더 파일

// wcslen(), wcscat(), wcscmp()를 사용하려면 아래 헤더 파일을 불러와야 한다.
#include <wchar.h>

 

wcslen()

• 문자열의 길이를 반환하는 함수

▶ 함수 원형

size_t wcslen(const wchar_t* _String);
// 와이드 문자열의 시작 주소를 가리킨다.

▷ 예시

#include <wchar.h>

int main()
{
	wchar_t cName[10] = L"Alice";
    int iLen = wcslen(cName);  // 5

	return 0;
}

`wcslen()` 직접 구현해 보기

unsigned int myWcslen(const wchar_t* _nL)
{
	int i = 0;
    while (true)
    {
    	wchar_t c = *(_nL + i);  // wchar_t c = _nL[i];
    	if ('\0' == c)
        {
        	break;
        }
        ++i;
    }
    
    return i;
}

int main()
{
	wchar_t cName[10] = L"Alice";
    int iLen = myWcslen(cName);  // 5

	return 0;
}

 

▷ while문 수정

unsigned int myWcslen(const wchar_t* _nL)
{
	int i = 0;
    while ('\0' != _nL[i])
    {
        ++i;
    }
    
    return i;
}

wcscat()_s

• 문자열을 이어 붙여주는 함수이다.

`wcscat()_s`은 오버로딩된 함수이고, 2종류가 있다.

▶ 함수 원형

// wcscat_s() 원형
errno_t wcscat_s(wchar_t* _Destination, rsize_t _SizeInBytes, const wchar_t* _Source);

// 템플릿 기반 strcat_s() 원형
errno_t wcscat_s<_Size>(wchar_t (&_Destination)[_Size], const wchar_t* _Source);

 

1) 인자를 3개 받는 경우

• 크기가 얼마인 목적지 공간에 어떤 문자열을 이어 붙인다.

Destination : 목적지
Source : 소스, 원본

① `wchar_t *_Destination` : 어디에 (목적지, 이어 붙임을 당하는 쪽)

• 다른 문자나 문자열을 붙이려면 이어 붙여지는 쪽은 수정 가능해야 한다.

 

② `rsize_t _SizeInWords` : 배열의 최대 개수(이어 붙이려는 목적지 공간의 크기)

• 배열의 최대 개수를 받는 이유 : 이어 붙일 쪽 배열의 최대 개수를 초과하면 안 되기 때문에 이를 방지하기 위해 복사받을 곳의 최대 공간을 입력받아서 확인해 준다.

배열 초과 시 예외 처리가 발생하므로 이어 붙는 쪽을 생각해서 공간 자체가 넉넉하게 잡아야 한다.

#include <wchar.h>

int main()
{
	wchar_t wcString[10] = L"abc";
	wcscat_s(wcString, 10, L"defghijklmnopqrstuvwxyz");  // 배열 초과
    // abc 뒤에 NULL까지 생각해서 배열의 공간을 설정해야 한다.

	return 0;
}

 

배열의 최대 개수를 잘못 적으면 예외 처리나 오류가 발생하지 않고 경고만 발생한다.

시작 주소만 받아가서 주소로부터 몇 칸까지 괜찮은지 알 방법이 없기 때문에 컴파일러는 작성한 칸까지 가능하다고 믿고 그대로 실행한다.

이때 문법적으로는 오류가 발생하지 않으므로 주의해야 한다.

 

③ `const wchar_t *_Source` : 무엇을 (이어 붙일 것)

• 이어 붙일 쪽은 원본을 수정하지 않고 읽기만 해야 되기 때문에 const가 붙는다.

 

▷ 이어 붙여지는 쪽의 공간을 여유 있게 잡아놓은 경우

wchar_t wcString[100] = L"abc";
wcscat_s(wcString, 100, L"def");  // abc 뒤에 def를 붙인다.

`abc` 뒤에 나머지는 전부 0으로 채워져 있지만 0은 문자로 채워진 것이 아니라 실제로는 빈 공간이기 때문에 `abc` 바로 뒤에 `def`가 붙는다.

 

2) 인자를 2개 받는 경우

배열의 크기를 템플릿으로 받아가서 초과하는지 아닌지 자동으로 인식해 주는 방법이다.

직접 배열의 크기를 적는 것보다 알아서 배열의 개수가 초과되는지 체크해 주는 방법이 실수를 줄여줘서 더 좋다.

▷ 예시

#include <wchar.h>

int main()
{
    wchar_t wcString[10] = L"abc";

    // 템플릿 기반 wcscat_s() 호출
    wcscat_s(wcString, L"def");

    return 0;
}

`wcscat_s()` 직접 구현해 보기

#include <assert.h>  // 경고 발생시키기
#include <iostream>

using namespace std;

unsigned int myWcslen(const wchar_t* _nL)
{
	int i = 0;
    while (true)
    {
    	wchar_t c = *(_nL + i);  // wchar_t c = _nL[i];
    	if ('\0' == c)
        {
        	break;
        }
        ++i;
    }
    
    return i;
}

// 이어 붙인 최종 문자열의 길이가 목적지의 저장 공간을 넘어서면 예외 처리가 뜨게 해야 된다.
void myWcscat_s(wchar_t* _pDest, unsigned int _iBufferSize, const wchar_t* _pSrc)
{
	// 예외 처리 => 이어 붙인 최종 문자열의 길이가 목적지 저장 공간을 넘어서려는 경우
    int iDestLen = myWcslen(_pDest);
    int iSrcLen = myWcslen(_pSrc);

    if (_iBufferSize < iDestLen + iSrcLen + 1)  // Null 문자 공간까지 계산
    {
        assert(nullptr);
    }

    // 문자열 이어 붙이기
    // 1. Dest 문자열의 끝을 확인 (문자열이 이어 붙은 시작 위치)
    // abc 뒤에 NULL 문자('\0') 자리부터 문자를 붙여야 되므로 목적지 문자열의 끝을 확인해야 한다.
    //iDestLen;  // Dest 문자열의 끝 인덱스

    // 2. 반복적으로 Src 문자열을 Dest 끝 위치에 복사하기
    // 3. Src 문자열의 끝을 만나면 반복 종료
    // 반복문을 진행하면서 Src 문자열을 Dest 끝 위치에 복사하고, 반복 횟수는 _Source 문자열의 개수만큼이다.
    for (int i = 0; i < iSrcLen + 1; ++i)
    {
        _pDest[iDestLen + i] = _pSrc[i];
    }
}

int main()
{
    wchar_t wcString[10] = L"abc";
    myWcscat_s(wcString, 10, L"def");

	wcout << wcString;
    
    return 0;
}

▽ 출력 결과

abcdef

wcscmp()

두 문자열을 비교하여 값을 반환하는 함수이다.

왼쪽의 우선순위가 높으면 -1을, 두 문자열이 일치하면 0을, 오른쪽의 우선순위가 높으면 1을 반환한다.

마치 저울처럼 -1, 0, 1 중에서 각각 상황에 맞게 값을 반환한다.

wcscmp값

우선순위가 높고 낮음은 사전과 아스키 코드를 생각했을 때 더 먼저 오는 것이 우선순위가 높다.

ex. `가` > `가나`, `a` > `b`

 

▶ 함수 원형

int wcscmp(const wchar_t* _Str1, const wchar_t* _Str2)

▷ 예시

#include <wchar.h>

int main()
{
	// 1. 두 문자열이 일치할 때
	int iRet = wcscmp(L"abc", L"abc"); // 0

	// 2. 두 문자열의 길이가 다를 때
	// 길이가 짧은 쪽이 우선순위가 더 높다.
	iRet = wcscmp(L"ab", L"abc");  // -1
	iRet = wcscmp(L"abc", L"ab");  // 1

	// 3. 두 문자열의 길이가 같을 때
	// 아스키 코드를 보면 a가 b보다 우선순위가 높다.
	iRet = wcscmp(L"abc", L"cbc");  // -1
	iRet = wcscmp(L"cbc", L"abc");  // 1

	return 0;
}

'wcscmp()` 직접 구현해 보기

#include <assert.h>

unsigned int myWcslen(const wchar_t* _nL)
{
    int i = 0;
    while (true)
    {
        wchar_t c = *(_nL + i);  // wchar_t c = _nL[i];
        if ('\0' == c)
        {
            break;
        }
        ++i;
    }

    return i;
}

int myWcscmp(const wchar_t* _left, const wchar_t* _right)
{
    int leftLen = myWcslen(_left);
    int rightLen = myWcslen(_right);

    // 두 문자열 중 하나를 저장해놓는다.
    int iLoop = leftLen;  // 두 문자열이 같을 때 아래 if문을 실행시킬 필요가 없어진다.
    int iReturn = 0;

    // 두 문자열의 길이가 다를 때
    // 왼쪽 문자열이 더 작으면 -1을 반환한다.
    if(leftLen < rightLen)
    {
        iLoop = leftLen;
        iReturn = -1;
    }
    // 오른쪽 문자열이 더 작으면 -1을 반환한다.
    else if(leftLen > rightLen)
    {
        iLoop = rightLen;
        iReturn = 1;
    }

    // 반복문은 두 문자의 반복 횟수에 맞게 반복된다.
    for (int i = 0; i < iLoop; ++i)
    {
        // 왼쪽 문자가 오른쪽보다 작다면 -1을, 그렇지 않다면 1을 반환한다.
        if (_left[i] < _right[i])
        {
            return -1;
        }
        else if(_left[i] > _right[i])  // ※ else로 작성하면 작다를 제외한 크거나 "같은" 경우도 포함되어버린다.
        {
            return 1;
        }
    }

    return iReturn;  // -1, 0, 1 중에서 해당하는 것을 반환한다.
}

int main()
{
    int iRet = myWcscmp(L"abc", L"ab");  // 1
    iRet = myWcscmp(L"abc", L"abcdef");  // -1

    return 0;
}

 


wcscpy_s()

• 문자열을 복사하는 함수

▶ 함수 원형

errno_t wcscpy_s<_Size>(wchar_t* (&_Destination)[_Size], const wchar_t* _Source)

▷ 예시

#include <wchar.h>
#include <iostream>

using namespace std;

int main()
{
    wchar_t wc[] = L"Hello World!";
    wchar_t dest[30];
    wcscpy_s(dest, wc);

    wcout << dest;

    return 0;
}

▽ 출력 결과

Hello World!

`wcscpy_s()` 직접 구현해 보기

#include <iostream>

void myWcscpy_s(wchar_t* _pDest, const wchar_t* _pSrc)
{
    int i = 0;
    // _pSrc 문자열을 끝까지 순차적으로 복사한다.
    while (_pSrc[i] != '\0')
    {
        _pDest[i] = _pSrc[i];
        ++i;
    }
    // 마지막에 NULL 문자 추가
    _pDest[i] = '\0';
}

int main()
{
    wchar_t wcSrc[] = "Hello";
    wchar_t wcDest[50];  // 복사본을 저장할 배열
	
    wcout << myWcscpy_s(wcDest, wcSrc);

    return 0;
}

▽ 출력 결과

Hello