문자열, const 포인터

Yama·2023년 12월 15일
0

어소트락 수업

목록 보기
14/55

리턴 값 을 안주고 함수값을 주는법?(포인터 활용)

void Add(int a, int b, int* _Out) // 1
{
	*_Out = a + b; // 2
}

int main()
{
	int Result = 0;
    
  	Add(100, 200, &Result);

	return 0;
}
  • // 1은 Add함수에서는 a,b값 받고 포인터 변수에는 주소값을 받는다.
  • // 2는 더한값을 주소값에 저장 한다.

포인터 주소를 이용해서 메모리 절약(최적화)

struct PlayerInfo
{
	int CurHP;
	int MaxHP;
	int CurMP;
	int MaxMP;

	int Att;
	int Def;
	int Int;
	int Dex;
	int Agi;
};

void Output(PlayerInfo _info)
{
	printf("플레이어 체력 %d / %d", _info.CurHP, _info.MaxHP);
	printf("플레이어 체력 %d / %d", _info.CurMP, _info.MaxMP);

	printf("플레이어 공격력 %d\n", _info.Att);
	printf("플레이어 방어력 %d\n", _info.Def);
}

int main()
{
	PlayerInfo info = {};

	info.CurHP = 40;
	info.MaxHP = 100;

	info.CurMP = 40;
	info.MaxMP = 50;

	info.Att = 10;
	info.Def = 8;

	Output(info);
 }
  • 문제점
    1. info를 받을떄 너무 큰 크기의 데이터를 받는다. int가 무려 9개(36바이트)
    2. 저 변수들을 바꾸면 안되는 값들인데 접근해서 바꾸기 가능하다.
      • 전달 방식이 비효율적(이런 방식의 설계가 쌓이면 성능저하 발생.)
struct PlayerInfo
{
  // 위의 구조체랑 동일
};

void OutputPlayerInfo(const PlayerInfo* _pInfo)
{
	// 1
	// const를 무시해서 값을 바꿔버린것.
	//PlayerInfo* pInfo = (PlayerInfo*)_pInfo;
	//pInfo->CurHP += 10;

	printf("플레이어 체력 %d / %d", _pInfo->CurHP, _pInfo->MaxHP);
	printf("플레이어 체력 %d / %d", _pInfo->CurMP, _pInfo->MaxMP);

	printf("플레이어 공격력 %d\n", _pInfo->Att);
	printf("플레이어 방어력 %d\n", _pInfo->Def);
}

int main()
{
	PlayerInfo info = {};
    
	// 위의 변수들 값이랑 동일.

	OutputPlayerInfo(&info);
    OutputPlayerInfo(&info);
	OutputPlayerInfo(&info);
 }
  • 문제점 해결 코드
    • 내가 만든 만든 주소값으로 포인터의 주소값만 가져오는게 전에 다 가져오는거보다 싸게 먹힌다.
    • const*를 붙여서 안묵적으로 원본값을 바꿀필요가 없고 주소값만 받기만하겠다는 코드
  • const로 기능을 제한하는것 또한 기능이다.
    • const*을 붙여서 값을 변경할려는 시도를 막는다.
      • // 1 처럼 뚫을 수는있지만 저렇게 하는 사람있으면 짤라버려야됨.
      • 뚫어 버린 코드를 사용하면 저런식으로 바꿀수있긴함..

단축키 추가

  • Ctrl + Shift + 스페이스 : 파라미터의 정보 표시
    • 오버로딩된 메소드의 매개변수 정보들을 빠르게 확인할 수 있습니다.

문자열

char szString[10] = "abcdef";

int szData[10] = "abc"; // 1 오류
  • 스택메모리에 배열을 만들고 ROM에서 문자열을 복사해서 스택 메모리에 있는 배열에 값에 채워넣는것.
    • ROM에 있는 "abcdef"의 주소값이랑 다르다.
  • // 1 문자 전용 자료가 아니므로 오류.
const char* pString = "abcdef"; 

char c = *pString
  • "abcdef"의 주소값을 받은것.
  • 문자열은 이미 프로그램이 시작했을떄 정해진 값이 들어옴으로 상수다.?
  • 접근하면 a부터 있당.

일반적인 문자열

	char szString[10] = "abcdef";
    
    char c = 0;
    
    c = *(szString + 1); // c = szString[1]; 같은 의미.
    
    szString[1]  = 'a'
  • 문자열을 ROM에서 복사해서 가져오는것.
  • 문자열로 초기화 받은 배열의 두번쨰 문자를 읽어서 변수 c에 저장하는 경우.

포인터를 이용한 문자열

	const char* pString = "abcdef";
    
    char c = 0;
    
    c = *(pString + 1); // c = pString[1];
    
    pString[1] = 'a'; // 1 오류
  • 문자열이 존재하는 읽기 전용 메모리에 있는 ROM으로 가서 쓰는것.
  • 직접 문자열로 접근해서 두번째 문자를 읽어서 변수 C에 저장하는 경우다.
  • // 1 원인
    • const의 문자열의 주소를 주는것이기 때문에 전달해도 const로 받아서 수정을 막을려 한다.
    • 일반 포인터로 접근하면 접근해서 문자열을 수정할수 있기 때문에 const로 받아야한다.

참고 : ROM 1.코드, 2. 문자열 들어감.

ROM에 저장된 문자열

	const char* pString = "abcdef"; // 1
    
    const char* pString2 = "abcdef"; // 2
    
    char szString[10] = "abcdef"; // 3
    
    char sz[10] = "abcdef"; //4
  • 같은 구조의 문자열은 동일한 곳의 주소를 나타낸다.
  • 코드상에서 동일한 문자열이 여러번 나오더라도, 해당 문자열은 메모리상에 딱 1개만 존재한다.
    • 1,2는 ROM의 "abcdef"를 본것이고 3,4는 ROM의에 있는 "abcdef"를 복사해서 자기들 스택 메모리 주소값에 넣은것.

런타임 에러(실행도중에 문제 발생)

	const char* pString = "abcdef";
    
    ((char*)pString)[1] = 'a';
    
    char sz[10] = "abcdef" // 1
  • 일반 포인터로 강제 캐스팅해서 접근해서 수정한것(의도적으로 문법을 뚫은것)
  • 읽기 전용 메모리인데 수정할려고 해서 프로그램의 크래쉬 발생
  • ROM에 있는 초기화용 문자열 원본을 수정할려고 하기 때문이다.
    • 이런 문제 해결할려면 메모리 공부 열심히.
  • //1 만약 저 위의 코드가 런타임 에러안나고 //1 이 실행되면 문자열이 바뀐 주소값이 들어간다.

문자열의 끝 널 문자

  • 문자열의 끝을 알리는 널문자가 반드시 존재해야한다.
  • 문자열 중간에 0(\0) 널문자를 넣으면 문자열이 끊긴다.
	char data[6] = "abcdef";  // 1오류
	char data2[7] = "abcdef";
  • 1 오류 이유
    • 널문자를 포함해서 7칸인데 6칸짜리 공간에 7을 넣을려해서 오류발생.
printf("abcdef")
  • "abcdef"의 주소를 받아서 출력한 것.
  • 널 문자 존재이유
    • 문자열을 구분하기 위해
    • 문자열에 널문자가 없다면 printf함수가 무한으로 출력될것이다.
	char character = '\0'; 

문자열 정리

  • 문자열은 주소값이다.
  • 코드상에 존재하는 문자열의 정보는 ROM에 저장된다.
  • 문자열은 ROM에 있는 문자열 데이터의 주소를 의미한다.
  • char, wchar_t 타입 배열을 초기화 시 문자열을 대입하는 경우 배열의 각 요소를 문자열의 각 문자로 초기화 하겠다는 의미다.

문제 1 Value 값은?

	int main()
	{
		short arrData[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

		int* pData = (int*)arrData;

		pData += 2;

		short Value = *((short*)pData); 
        
        return 0;
    }
  • 5
  • int로 강제 캐스팅해서 한걸 2번 옮기면 8바이트 옮겨진다.
  • 그걸 다시 short로 바꿔서 접근하면 short는 8바이트는 4칸 이동한거여서 5가나옴.

문제2 Value 값은?

	int main()
    {
		char data[2] = { 2, 1 };

		short* pData = (short*)data;

		Value = *pData;
        
        return 0;
    }    
  • 514, {2,1} == 513, {1,2} == 258
  • 2,2rk 1바이트로 있었는데 2바이트로 보니까 0000 00010 0000 0010 == 514(10)

버블 소트 함수화

void BubbleSort(int* _Data, int _ElementCount)
{
	bool bChange = false;

	for (int j = 0; j < _ElementCount; ++j)
	{
		for (int i = 0; i < _ElementCount - (1 + j); ++i)
		{
			if (_Data[i] > _Data[i + 1])
			{
				int Temp = _Data[i];
				_Data[i] = _Data[i + 1];
				_Data[i + 1] = Temp;

				bChange == true;
			}
		}

		if (bChange = true)
		{
			break;
		}
	}
}
int main()
{
	int Data[5] = { 27, 3, 99, 45, 94 };
    
    BubbleSort(Data, 5);
}

삽입정렬

#include <iostream>


void InsertionSort(int* _Arr, int _size)
{
	for (int i = 1; i < _size; ++i)
	{
		int Check = _Arr[i];

		for (int j = i; j >= 1; --j)
		{
			if (Check < _Arr[j - 1])
			{
				_Arr[j] = _Arr[j - 1];
				_Arr[j - 1] = Check;
			}
		}
	}
}

int main()
{
	//int Data[10] = { 27, 3, 99, 45, 94, 1, 44, 6745, 22, 14 };
	int Data[5] = { 5,13,6,7,8 };

	InsertionSort(Data, 5);

	int k = 0;

	return 0;
}

강의 코드

#include <iostream>

struct PlayerInfo
{
	int CurHP;
	int MaxHP;
	int CurMP;
	int MaxMP;

	int Att;
	int Def;
	int Int;
	int Dex;
	int Agi;
};


void Add(int a, int b, int* _Out)
{
	*_Out = a + b;
}

void OutputPlayerInfo(const PlayerInfo* _pInfo)
{
	//PlayerInfo* pInfo = (PlayerInfo*)_pInfo;
	//pInfo->CurHP += 10;

	printf("플레이어 체력 %d / %d\n", _pInfo->CurHP, _pInfo->MaxHP);
	printf("플레이어 마나 %d / %d\n", _pInfo->CurMP, _pInfo->MaxMP);

	printf("플레이어 공격력 %d\n", _pInfo->Att);
	printf("플레이어 방어력 %d\n", _pInfo->Def);
}

int main()
{
	int a = 0;

	int* p = &a;

	*p = 100;



	int Result = 0;

	Add(100, 200, &Result);

	PlayerInfo info = {};

	info.CurHP = 40;
	info.MaxHP = 100;

	info.CurMP = 40;
	info.MaxMP = 50;

	info.Att = 10;
	info.Def = 8;

	OutputPlayerInfo(&info);


	char szString[10] = "abcdef";

	const char* pString = "abcdef";

	char c = 0;

	// 문자열로 초기화 받은 배열의 두번째 문자를 읽어서 변수 c 에 저장하는 경우
	c = szString[1];
	szString[1] = 'a';

	// 직접 문자열로 접근해서 두번째 문자를 읽어서 변수 c 에 저장하는 경우
	c = pString[1];

	// 컴파일, 링크, -> 런타임 에러(실행도중에 문제 발생)
	//((char*)pString)[1] = 'a'; 


	char sz[10] = "abcdef";

	const char* pString2 = "abcdef";

	// 문자열의 끝 널문자
	char data[7] = "abcdef";

	printf("abcdef");

	char character = '\0';

	return 0;
}

1차 23.12.15
2차 23.12.17
3차 23.12.18
4차 23.12.19
5차 23.12.20
6차 23.12.25
7차 24.01.01
8차 24.01.24

0개의 댓글