[C++] 문자열(2)

꿈별·2023년 5월 2일
0

C++

목록 보기
13/27

문자열 길이 구하는 함수

  • wcslen() : 문자열 길이 알려주는 함수
    • 문자열 길이를 계산하기 위해 배열의 시작 주소를 인자로 넘겨줘야 한다. ex) 배열명 szName
    • 문자열의 길이만 반환받고, 문자열 데이터를 수정할 의도가 없음을 const로 명시했다.
      (szName에 초기화된 문자열은 ROM에 저장되어 있기 때문)
wchar_t szName[10] = :"Raimond";

-> 문자 개수 : 7개
(NULL 문자는 문자열의 끝을 알릴 뿐, 문자 개수에 포함 안 됨)

문자열 길이 구하는 함수 구현

unsigned int GetLength(const wchar_t* _pStr)
{
	//문자 개수 체크 용도
	int i = 0;

    //while(0 != *(_pStr + i)) 와 같음
	while('\0' != _pStr[i])
    {        
        ++i;
    }
    return i;
}

int main()
{
	wchar_t szName[10] = L"Raimond";
    
    int iLen = GetLength(szName);
    
    return 0;
}

-> 널 문자가 나올 때까지 문자 수 카운팅을 반복한다. 몇 번 반복해야 할 지 미리 알 수 없으므로 while문 사용
-> 반환 타입으로 문자의 개수를 알려주는데, 개수가 음수일 리는 없으므로 unsigned int 형으로 반환한다.
-> 2byte 함수니까 wchar_t 로 문자열 주소 받기
-> 문자열 수정 못하도록 const 포인터로 설정

[출력]
7


문자열 이어 붙이기 함수

  • wcscat_s()
    • 원본 문자열은 const로 읽어 오지만 이어 붙이게 될 변수는 const 아님.
    • 오버로딩 되어 있어서 함수가 2가지 존재
      -> 지금은 함수 원형을 확인하여 인자 3가지인 버전을 사용한다.
    • 이어 붙여지는 쪽 (_Destination)에는 넉넉한 공간이 필요하다

wchar_t szString[100] = L"abc";
wcscat_s(szString, 100, L"def");

-> abcdef 로 합쳐짐

문자열 이어 붙이기 함수 구현

예외처리

  1. 이어 붙이고자 하는 배열의 사이즈를 명시해서 붙여질 대상 배열을 초과하는 문제를 방지한다.
  • 사이즈 매개변수를 실제 크기보다 크다고 잘못 입력하면 문제 발견 못할수도 있음, 함수 템플릿 배우고 나면 템플릿 방식을 사용하는 wsccat_sn() 함수 사용하기

  • 붙일 배열 안전한지 체크

    • 경고 발생 기능
      assert(nullptr);
      : 특정 함수를 호출하는 매크로, assert라는 구문을 작성하면 함수를 호출하여 경고창을 띄운다.
      -> 헤더파일
      C : <assert.h> / C++ : <cassert>
if (_iBufferSize < iDestLen + iSrcLen + 1) //널 문자 공간까지 계산
{
    assert(nullptr);
}
  • iDestLeniSrcLen의 길이는 위에서 구현했던, 문자열 길이 구하는 함수 GetLength 사용해서 구함
  • 문자열 합친 길이 +1(널문자) 가 버퍼사이즈 초과하지 않는지 체크해야 함
    -> 초과하면 경고 띄우고 프로그램 종료

문자열 이어 붙이기

  1. Dest(목적지) 문자열의 끝을 확인(문자열이 이어 붙을 시작 위치)

  • iDestLen : Dest 문자열의 끝 인덱스,
    문자열 크기가 2라면 2번째 칸에 널 문자가 있다는 뜻이므로 그 위치에 문자열을 이어 붙이면 됨
  1. 반복적으로 Src 문자열을 Dest 끝 위치에 복사하기
  2. Src 문자열의 끝(\0)을 만나면 반복 종료
for(int i = 0; i < iSrcLen + 1; ++i)
{
	_pDest[iDestLen + i] = _pSrc[i];
}

구현

//매개변수 : 이어 붙여질 목적지, 목적지 배열 사이즈, 원본
void StrCat(wchar_t* _pDest, unsigned int _iBufferSize, const wchar_t* _pSrc )
{
	// 예외처리
    // 이어붙인 최종 문자열 길이가, 원본 저장 공간을 넘어서는 경우
	int iDestLen = GetLength(_pDest);
    int iSrcLen = GetLength(_pSrc);
    
    if (_iBufferSize < iDestLen + iSrcLen + 1) //널 문자 공간까지 계산
    {
        assert(nullptr);
    }
    
    //문자열 이어 붙이기
    for(int i = 0; i < iSrcLen + 1; ++i)
	{
		_pDest[iDestLen + i] = _pSrc[i];
	}
}


int main()
{
    wchar_t szString[10] = L"abc";
    StrCat(szString, 10, L"def");
    return 0;
}


과제 - 문자열 비교 함수 구현

  • wcscmp() 함수와 똑같은 기능의 함수 구현하기
    : 두 문자열 전달받고, 완벽하게 일치하는지 확인하는 함수
    -> 왼/오 문자열 비교해서 아스키 코드 값이 작은 쪽에 의해 값이 달라짐
    (왼쪽이 작으면 -1, 오른쪽이면 +1, 완전히 일치하면 0)
    ex) "abc" "cbc" : -1, "cbe" "abc" : 1 ,
    -> 힌트 : 아스키코드 표로 알파벳 우열 알아보기

    NULL : 32
    A~Z : 65~90
    a~c : 97~122

    • 원본 문자열 수정 못하도록 const 포인터로 설정하고,
      2byte 함수이므로 wchar_t 타입 매개변수 설정
    • 문자열 길이가 다를 경우, 짧은 쪽이 우선됨
      (NULL 문자의 10진수가 32이므로)
    • 각 문자열에 구성된 문자가 같더라도, 문자열 인덱스가 작은 쪽의 비교값이 우선됨
      "ab" "ba" : -1
      (a b 똑같이 들어있지만, 왼쪽의 a가 먼저 나왔으므로 왼쪽이 우선)

  • 풀이 순서
    1. 두 문자열 전달받고, 문자열 인덱스 나타낼 변수와 비교결과 담을 변수 초기화
    2. while(true)로 반복
    3. 두 문자의 아스키 코드를 비교해서 왼쪽이 작으면 -1로 초기화하고,
      오른쪽이 작으면 1로 초기화
    4. 두 문자 중 하나라도 NULL이 있으면 비교결과 변수 리턴
    5. 인덱스 변수 1 증가시킴

  • 잡담......

    1. GetLength() 없이 구현하느라 각 문자의 NULL 여부를 확인하고 리턴시켜야 했는데 자꾸 무조건 리턴돼서 이상하다고 생각했다.
    if (_Src1[i] || _Src2[i] == NULL)

    조건식을 이렇게 적어둔 게 문제였다 .. .... 왜그랬을까?

    if (_Src1[i] == NULL || _Src2[i] == NULL)

    로 바꿔줬다.

    1. 조건문 간략화하겠다고 아래처럼 삼항 연산자로 바꾸려다가
    value = _Src1[i] < _Src2[i] ? -1 : 1;

    왼쪽 문자 아스키코드 값이 더 작을 때 빼고는 전부 value가 1이 돼버려서 다시 되돌렸다.
    값이 -1, 0, 1처럼 세 개 이상이면 삼항 연산자 주의하기..


구현

#include <stdio.h>

int strcmp(const wchar_t* _Src1, const wchar_t* _Src2)
{
    int i = 0; //문자열 배열 인덱스
    int value = 0;
    while (true)
    {
        //왼쪽이 작으면 -1, 오른쪽이면 1
        if (_Src1[i] < _Src2[i])
            value = -1;
        else if (_Src1[i] > _Src2[i])
            value = 1;
            
        if (_Src1[i] == NULL || _Src2[i] == NULL)
                return value;
        i++;
    }
}

int main()
{
    int cmp_val = strcmp(L"ab", L"ad");
    printf("%d", cmp_val);
    return 0;
}


💡 비교연산 팁

비교 연산상수를 왼쪽, 변수를 오른쪽에 두는 것이 좋다.
반대의 경우 비교 연산자가 아니라 부등호로 잘못 적더라도, 일단 대입된 상태로 실행되기 때문에 오류를 찾기 어려워질 수 있다.

💡 오버로딩/오버라이딩

오버로딩, 오버라이딩 구분하기 (면접 다수 출제)

  • 오버로딩 : 함수 중복 정의, 이름은 같지만 매개변수의 개수와 타입이 다른 함수를 선언하는 것
  • 오버라이딩 : 함수 재정의, 상속 관계에서 부모 클래스에 정의된 함수와 같은 이름, 매개변수를 가지는 함수를 자식 클래스에서 재정의하여 우선적으로 사용한다.

[참고]
https://youtu.be/hfUxtFKhOuE
https://youtu.be/hfUxtFKhOuE
오버로딩/오버라이딩

0개의 댓글