2024. 3. 27. 23:27ㆍProgramming Language/C++
아래 링크 클릭 시 해당 본문으로 이동
해당 본문 내용은 문자열 함수 본문과는 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 중에서 각각 상황에 맞게 값을 반환한다.
우선순위가 높고 낮음은 사전과 아스키 코드를 생각했을 때 더 먼저 오는 것이 우선순위가 높다.
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
'Programming Language > C++' 카테고리의 다른 글
[C/C++] 가변 배열 - 구조체/분할 구현 (0) | 2024.03.28 |
---|---|
[C++] 문자열 함수 - strlen(), strcat_s(), strcmp(), strcpy_s() (0) | 2024.03.27 |
[C++] 문자열 (0) | 2024.03.26 |
[C++] 스트림(stream), 버퍼(buffer) (0) | 2024.03.26 |
[C++] 주석(Comment), 세미콜론(;) (0) | 2024.03.25 |