문자열 키 값 사용

Yama·2024년 1월 10일
0

어소트락 수업

목록 보기
39/55

문자열 키 값 사용

	const wchar_t* pChar = L"asdasd";
  • 문자열의 타입은 const char* 타입이다.
  • 문자열을 키값으로 사용하면
    • 고블린, 전사 등등
    • 이진탐색트리에서 first이 주소값이 되어야 한다.
  	map<const wchar_t*, int > mapData;
  • const wchar_t*로 받았다 문자열은 const를 읽기 전용 영역에 저장되기때문에 수정할 여지를 방지하기 위해서 const로 막았다.
	mapData.find(L"Father");
  • 문자열을 키값으로 찾아오는 것.
	map<const wchar_t*, int > mapData;
	mapData.insert(make_pair(L"Father", 0));
	mapData.insert(make_pair(L"Mother", 1));
	mapData.insert(make_pair(L"Brother", 2));
	mapData.insert(make_pair(L"Sister", 3));
  • 탐색이 되니까 정렬이 되었다는건대 이건 어떻게 정렬되어있을까?
  • 문자열을 키값으로 주었으니까 주소값의 주소값으로 비교했다..?
	map<const wchar_t*, int >::iterator iter = mapData.find(L"Father");
	iter->first;
	iter->second;
  • 문자열을 비교로 한게 아니라 주소값이 동일한 주소값이 걸려서 검색된것이다.
	wchar_t szName[20] = L"Father";
  • 배열인 szName에 Father+ \0을 저장했다.
	mapData.find(szName);
  • map은 메모리의 주소값이 지역변수에 있는 배열의 주소값이라 읽기 전용 메모리에 있는 Father을 못찾는다.
  • 하드 코딩할게 아니라 변수로 접근할떄 이런 경우 동일한 주소가 아니라고 인식을 못한다.
    • 그래서 이런 문자열을 키값으로 사용할려면 문자열 클래스가 필요하다.

Str 클래스 가져오기.

class Str
{
private:
	wchar_t* 	m_pStr;							// 1
	int			m_MaxLength;					// 2
	int			m_Length;						// 3

public:
	int Length() { return m_Length; }			// 4
	const wchar_t* GetStr() { return m_pStr; }  // 5

private:
	void Realloc();								// 6

public:
	Str();
	Str(const wchar_t* _str);
	~Str();
};
  • 1번은 동적할당한 문자열의 주소다.
    • str클래스는 동적배열을타입을 wchar_t타입으로 고정시켜놓은 배열이라고 보면된다.
    • 문자열 전담할것이라.
  • 2번은 문자열을 저장할 수 있는 최대 길이
  • 3번은 문자열의 길이
  • 4번은 인라인 함수로 문자열 길이를 반환하는 함수
  • 5번은 인라인 함수로 문자열을 가져오는 함수
  • 6번은 크기 재할당 함수 선언부
// 1
Str::Str()
	: m_pStr(nullptr)
	, m_MaxLength(10)
	, m_Length(0)
{
	m_pStr = new wchar_t[m_MaxLength + 1];
}
// 2
Str::Str(const wchar_t* _str)
	: m_pStr(nullptr)
	, m_MaxLength(10)
	, m_Length(0)
{
	m_pStr = new wchar_t[m_MaxLength + 1];
	(*this) = _str;
}

// 3
Str::~Str()
{
	if (nullptr != m_pStr)
		delete m_pStr;
}
  • 1번은 기본 생성자, 2번은 인자를 받는 생성자, 3번은 소멸자
    • 생성될때는 널을 넣을 공간까지 생각해서 + 1 다 해준다.
void Str::Realloc()
{
	// 수용 공간을 2배로 확장하기
	m_MaxLength *= 2;

	// 새로운 공간을 만들어낸다.
	wchar_t* pNew = new wchar_t[m_MaxLength + 1];

	// 원래 있던 데이터를 새로운곳으로 옮긴다.
	for (int i = 0; i < m_Length; ++i)
	{
		pNew[i] = m_pStr[i];
	}
	pNew[m_Length] = '\0';

	// 기존 공간을 해제한다.
	delete m_pStr;

	// 새로운 공간을 가리킨다.
	m_pStr = pNew;
}
  • 재할당 함수 선언부
void Str::operator=(const wchar_t* _str)
{
	// 입력되려는 문자열의 문자 개수(길이) 파악
	int len = 0;
	while ('\0' != _str[len]) { ++len; }

	// 입력되려는 문자열의 길이가 최대 수용개수를 넘어서면 저장 공간 확장
	while (m_MaxLength < len)
	{
		Realloc();
	}

	// 입력 문자열의 값을, 힙 공간으로 하나씩 옮기기
	int i = 0;
	for (; i < len; ++i)
	{
		m_pStr[i] = _str[i];
	}

	// 마지막에 널문자로 막기
	m_pStr[i] = '\0';

	// 문자열 길이 갱신(입력된 문자열 길이로)
	m_Length = len;
}
  • 문자열 대입 operator 구현한부분이다.
Str Str::operator+(const Str& _string)
{
	Str strNew;
	strNew = m_pStr;
	strNew += _string.m_pStr;

	return strNew;
}
  • 문자열 합치는 + operator구현 코드
  • 문자열에 지역변수 임시로 만들어서 원래있는 문자열을 지역변수에 저장하고 뒤이어들어오는 +=를 뒤에 붙여서 연결시킨다.
void Str::operator+=(const wchar_t* _Str)
{
	// 뒤에 붙을 문자열의 문자 개수(길이) 파악
	int len = 0;
	while ('\0' != _Str[len]) { ++len; }

	// 원래 문자열 길이 + 새로 뒤에 붙을 문자열의 길이가 최대 저장 크기를 벗어나는지 확인
	while (m_MaxLength < m_Length + len)
	{
		Realloc();
	}

	// 뒤에붙을 문자열을 가져오기
	for (int i = 0; i < len; ++i)
	{
		m_pStr[i + m_Length] = _Str[i];
	}

	// 저장하고 있는 문자열 길이 갱신
	m_Length += len;
	m_pStr[m_Length] = '\0';
}
  • 문자열 += operator구현 코드다.
  • abc /0 이였던거에 def를 저장하면 /0 자리에 d 뒤에 e 뒤에 f 하고 뒤에 /0 한다.
  • 합친 문자열이 공간 벗어나면 재할당 시킨다.

map에 우리가 만든 클래스 사용하기

	map<Str, int> mapString;
  • 첫번째 템플릿으로 Str(우리가만든 문자열 클래스) 넣고 뒤에 대충 int
	mapString.insert(make_pair(L"Father", 0));
	mapString.insert(make_pair(L"Mother", 1));
	mapString.insert(make_pair(L"Brother", 2));
	mapString.insert(make_pair(L"Sister", 3));
  • 문자열을 키값으로 하는 map을 만들었당.
  • 데이터 입력한것.
  • make_pair입장에서는 첫번째 타입으로는 문자열을 넣음 실제로 저장할 fisrt타입은 cosnt wchar_t* 타입이 아니라 우리가 만든 Str은 문자열이랑 서로 타입이 다르다.
Str::Str(const wchar_t* _str)
	: m_pStr(nullptr)
	, m_MaxLength(10)
	, m_Length(0)
{
	m_pStr = new wchar_t[m_MaxLength + 1];
	(*this) = _str;
}
  • 상관이 없는 이유: 문자열을 인자로 받는 생성자가 있어서 오버로딩되기때문에 괜찮다.
    • 자기가 관리하는 힙 메모리 영역으로 동적할당해서 그곳에 저장하는 식으로 만들었기 때문이다.
    • 대입연산자라던지 입력되면서 생성자들이 구현이 되어있기 때문에 애는 만들어진거는 pair안에 잇는 Str객체 타입이지만 이런게 입력으로 들어오면 본인의 맴버중에 힙메모리를 가리키는 포인터가 있었어서 이 포인터는 힙메모리 공간을 관리하는 여석인데 이 놈은 문자열이 들어오면 자기가 하나씩 가리켜서 공간에 복사해두는 식으로 설계가 되있어서 가능하다.
      • Father이 들어오면 F,a,t,h,e,r,\0이런식으로 관리한다.
      • Mother는 M,o,t,h,e,r,\0
  • 근데 대소 비교를 위해서는 Str클래스에도 비교 연산의 기준을 내가 만들어서 비교 연산자를 구현을 해놔야 문자열을 비교 가능해진다.
    • 비교 연산자를 안만들어 놓고 빌드를 하면 Str끼리 템플릿이 만들어줘서 만들어주면 Str 템플릿 끼리의 비교 연산자가 없어서 오류가 난다.
public:
	void operator = (const wchar_t* _str);
	Str operator+ (const Str& _string);
	Str operator+ (const char* _Str);
	void operator +=(const wchar_t* _Str);

	bool operator ==(const Str& _Other) const;
	bool operator !=(const Str& _Other) const;
	bool operator <(const Str& _Other) const;
	bool operator >(const Str& _Other) const;
	bool operator <=(const Str& _Other) const;
	bool operator >=(const Str& _Other) const;
  • 헤더파일에 선언
bool Str::operator==(const Str& _Other) const
{
	return false;
}

bool Str::operator!=(const Str& _Other)const
{
	return false;
}

bool Str::operator<(const Str& _Other)const
{
	return false;
}

bool Str::operator>(const Str& _Other)const
{
	return false;
}

bool Str::operator<=(const Str& _Other)const
{
	return false;
}

bool Str::operator>=(const Str& _Other)const
{
	return false;
}
  • 아직 구현은 안햇지만 구현할 부분.
  • 그러면 우리는 어떻게 매칭을 할것이냐
    • ==는 일대일 매칭해보고 다 같으면 같다, 아니면 틀리다.
    • 이럴떄 너가 더 크다. 쌍따음표나 배열로 검색을 해도 Str타입으로 관리하니까 find할떄 검색을 해도 괜찮다.
    • 문자열 대소는 아스키코드로 대소를 비교할듯.?
  • 내가 Str클래스 안에 기준을 정확하게 만들어두면 내가 만든 문자열 관리 클래스로 문자열을 키값으로 사용가능하다.

강의 코드

main.cpp

#include <iostream>

#include "Str.h"

#include <map>
using std::map;
using std::make_pair;

int main()
{
	const wchar_t* pChar = L"asdasd";

	map<const wchar_t*, int> mapData;
	mapData.insert(make_pair(L"Father", 0));
	mapData.insert(make_pair(L"Mother", 1));
	mapData.insert(make_pair(L"Brother", 2));
	mapData.insert(make_pair(L"Sister", 3));

	map<const wchar_t*, int>::iterator iter = mapData.find(L"Father");
	iter->first;
	iter->second;
	wchar_t szName[20] = L"Father";
	mapData.find(szName);

	map<Str, int> mapString;
	mapString.insert(make_pair(L"Father", 0));
	mapString.insert(make_pair(L"Mother", 1));
	mapString.insert(make_pair(L"Brother", 2));
	mapString.insert(make_pair(L"Sister", 3));

	Str str(L"Father");

	return 0;
}

Str.h

#pragma once

class Str
{
private:
	wchar_t* m_pStr;			// 동적할당한 문자열의 주소
	int			m_MaxLength;	// 문자열을 저장할 수 있는 최대 길이
	int			m_Length;		// 문자열의 길이

public:
	int Length() { return m_Length; }
	const wchar_t* GetStr() { return m_pStr; }

private:
	void Realloc();

	// 연산자 오버로딩
public:
	void operator = (const wchar_t* _str);
	Str operator+ (const Str& _string);
	Str operator+ (const char* _Str);
	void operator +=(const wchar_t* _Str);

	bool operator ==(const Str& _Other) const;
	bool operator !=(const Str& _Other) const;
	bool operator <(const Str& _Other) const;
	bool operator >(const Str& _Other) const;
	bool operator <=(const Str& _Other) const;
	bool operator >=(const Str& _Other) const;


public:
	Str();
	Str(const wchar_t* _str);
	~Str();
};

Str.cpp

#include "Str.h"

#include <iostream>

Str::Str()
	: m_pStr(nullptr)
	, m_MaxLength(10)
	, m_Length(0)
{
	m_pStr = new wchar_t[m_MaxLength + 1];
}

Str::Str(const wchar_t* _str)
	: m_pStr(nullptr)
	, m_MaxLength(10)
	, m_Length(0)
{
	m_pStr = new wchar_t[m_MaxLength + 1];
	(*this) = _str;
}

Str::~Str()
{
	if (nullptr != m_pStr)
		delete m_pStr;
}

void Str::Realloc()
{
	m_MaxLength *= 2;

	wchar_t* pNew = new wchar_t[m_MaxLength + 1];

	for (int i = 0; i < m_Length; ++i)
	{
		pNew[i] = m_pStr[i];
	}
	pNew[m_Length] = '\0';

	delete m_pStr;

	m_pStr = pNew;
}

void Str::operator=(const wchar_t* _str)
{
	int len = 0;
	while ('\0' != _str[len]) { ++len; }

	while (m_MaxLength < len)
	{
		Realloc();
	}

	int i = 0;
	for (; i < len; ++i)
	{
		m_pStr[i] = _str[i];
	}

	m_pStr[i] = '\0';

	m_Length = len;
}

Str Str::operator+(const Str& _string)
{
	Str strNew;
	strNew = m_pStr;
	strNew += _string.m_pStr;

	return strNew;
}

Str Str::operator+(const char* _Str)
{
	Str strNew;
	return strNew;
}

void Str::operator+=(const wchar_t* _Str)
{
	int len = 0;
	while ('\0' != _Str[len]) { ++len; }

	while (m_MaxLength < m_Length + len)
	{
		Realloc();
	}

	for (int i = 0; i < len; ++i)
	{
		m_pStr[i + m_Length] = _Str[i];
	}

	m_Length += len;
	m_pStr[m_Length] = '\0';
}

bool Str::operator==(const Str& _Other) const
{
	return false;
}

bool Str::operator!=(const Str& _Other)const
{
	return false;
}

bool Str::operator<(const Str& _Other)const
{
	return false;
}

bool Str::operator>(const Str& _Other)const
{
	return false;
}

bool Str::operator<=(const Str& _Other)const
{
	return false;
}

bool Str::operator>=(const Str& _Other)const
{
	return false;
}

1차 24.01.10
2차 24.01.11
3차 24.01.12
4차 24.01.15
5차 24.01.16

0개의 댓글