[TIL] 23-12-15

Lev·2023년 12월 15일
0

📓TIL Archive

목록 보기
5/33

조건문

게임은 조건문으로 이루어져 있다
e.g. HP가 0이라면, 사망 애니메이션을 출력한다.
e.g. 물건을 사고 싶은데 돈이 모자라다면, 경고창을 띄운다.
e.g. 물건을 사고 싶을 때 돈이 있다면, 인벤토리로 물건을 옮긴다.

명사 ⇒ 변수 ⇒ 메모리영역 ⇒ 램의 x 위치에서 y 만큼의 크기로 존재한다는 것을 유념하기

if, else if, else문

메모리 영역을 검사해서
⇒ 참이면 실행코드를 실행시키고
⇒ 참이 아니라면 실행코드를 실행시키지 않는다.

/*
if (메모리영역)
{
	실행코드
}
*/

int GetHp()
{
	return 100;
}

int main()
{
	int Hp = 100;
	if (Hp)	// true
	{
		int a = 0;
	}

	if (GetHp()) // true
	{
		int a = 0;
	}
		
	if (Hp <= 0) // 비교연산자
	{
		int a = 0;
	}
	
	if (Hp += 10, Hp <= 0) // 괄호 안에 여러 구문을 넣을 수 있다
	// 하지만 코드를 읽는 법이 어려워져 사용하지 않는 것이 좋을지도...
	{
		int a = 0;
	}
}
  • if문은 실행될 수 있는 함수의 {}(메모리 영역) 안에서만 사용할 수 있다.
  • if문은 비교연산자와 함께 사용될 때가 많다.
/*
HP가 100 이상일 때 정상
HP가 50~99 사이일 때 부상
HP가 10~49 사이일 때 중상
HP가 1~9 사이일 때 사망직전
HP가 0 이하일 때 사망
*/

if (Hp >= 100)
{
	int a = 0;	// 정상
}
else if (Hp >= 50)
{
	int a = 0;	// 부상
}
else if (Hp >= 10)
{
	int a = 0;	// 중상
}
else if (Hp >= 1)
{
	int a = 0;	// 사망직전
}
else
{
	int a = 0;	// 사망
}
  • 위 조건이 false일 때 아래 조건으로 넘어간다.
  • 모든 조건문을 if문으로 작성하는 것보다 효율적이다.
// if문을 이렇게 사용하지 말자!

// 1. 값이 정확하게 일치하는 경우는 잘 없으므로 == 연산자 사용은 지양하자
if (Hp == 100)
{
	int a = 0;
}

// 2. if문의 끝에 ;을 붙여버리면 if문은 바로 종료되어버리고, {}는 이름없는 공간이 되어 무조건 실행된다
int Damage = 200;

if (Damage >= 300);
{
	int a = 0;
}

// 3. {} 없는 한 줄 if문은 메모리 공간이 명시적이지 않으므로 지양하자
if (true)
	int a = 0;

switch문

switch (A)
{
case 0:
	break;
case 10:
	break;	
case 20:
	break;
default:
	break;
}

/*
switch (A)
{
case 10:
	break;
default:
	break;
}

if (A == 10)
{
	int a = 0;
}
else
{
	int a = 0;
}
*/
  • case /*상수*/ 과 같은 형식의 조건문이기 때문에, 사실 if문으로 완전히 대체할 수 있다.
  • 그럼에도 여러 자동완성 등과 같은 편리함으로 자주 사용된다.
char Ch = 'A'

switch (A)
{
case 10:
	int a = 0; // (1) 불가능
	break;
case 10:
{
	int a = 0; // (1) 가능
	break;
}

case Ch; // (2) 불가능
	break;

default:
	break;
}

switch (Ch)
{
case 'A': // (2) 가능
	break;
default:
	break;
}
  • 지역변수를 사용할 수 있나? (1)
    • switch문은 메모리를 사용하는 방법이 다르기 때문에(?) 메모리 공간을 별도로 만들어주지 않고서는 지역번수를 사용할 수 없다.
  • break가 없다면?
    • switch문을 중도에 탈출하지 못하고 다음 case가 실행되어버린다.
    • 꼭 붙일 필요는 없지만, 상황에 맞춰 붙여주어야 한다.
  • 변수가 조건에 올 수 있나? (2)
    • 없다, 상수만 가능하다.

💡 char 자료형
⇒ 1byte 문자형
'' 안에서 초기화 해야 한다.
⇒ 문자임에도 숫자로 표현돼서, 참과 거짓을 구분하는 데에 사용할 수 있다. e.g. ‘A’ = 65

char Ch = 'A';
char T = 'B';

문자열

'A';	// 문자 상수표현식
"AAAAAA";	// 문자열 상수표현식

char String0[5] = "AAAA";
char String1[5] = { 'A', 'A', 'A', 'A', 0 };
  • 문자열의 마지막 칸에는 반드시 0이 들어간다
  • char String1[5] = { 'A', 'A', 'A', 'A', 'A' }; => 이렇게 강제로 넣을 수도 있지만
    printf_s(String1);으로 출력하면 다섯번째 A 뒤에 이상한 글자들이 붙어 출력된다.
  • printf는 내부에서 0이 나올 때까지 글자를 출력하는 함수이기 때문이다.

💡 배열 초기화

int Arr[5] = { 10, 20, 30, 40, 50 };	// 직접 채워줘도 되지만
int Arr[5] = {};	// 생략하면 나머지를 0으로 채워준다
int Arr0[5];	// 하지만 이렇게 쓰면 쓰레기값으로 채워주므로 지양하자

📢 잊지 말자!
1. 모든 것은 위치와 크기가 있다. ⇒ 램에서의 위치와 크기
2. 내가 제어할 수 없는 부분에 대해서는 알려고 하지도, 사용하려 하지도 말자.
e.g. 5칸짜리 배열에서 6번째, 7번째 칸에는 무엇이 있을까?
3. 코드를 작성할 때에는 꼭 중단점을 걸어 확인하는 습관을 들이자.

반복문

while문

조건문의 메모리 영역을 검사해서
⇒ 참일 경우 → 실행코드 1번 실행 → 다시 조건문
⇒ 거짓일 경우 → while문 탈출

/*
while (메모리영역)	// 조건문
{
	실행코드
}
*/

#include <iostream>

int main()
{
	int Count = 5;

	while (Count)
	{
		putchar('A');	// 문자를 출력하는 함수
		Count = Count - 1;
	} // AAAAA

	/*
	이런 식으로 작성할 수도 있다.
	하지만 복잡해서 알아두기만 하면 될 듯

	Count = 5;

	while (Count = Count - 1, Count)
	{
		int num = Count;
		putchar('A');
	} // AAAA
	*/
}
// 문자열과 반복문!!!

#include <iostream>
/*
정적배열(크기가 상수로 정해진 배열)은 함수의 인자로 받을 수 없다
그래서 포인터로 받아야 하는데, 그러면 크기를 알 수가 없다
따라서 0을 만날 때까지 계속 가는 형태로 만들어준다
*/
void MyPrintf(char* _Ptr)
{
	int Count = 0;

	/*
	char* CurPtr = (_Ptr + 0);
	char CurPtr = *(_Ptr + 0);
	char CurPtr = _Ptr[0];
	셋 다 포인터로 배열에 접근하는 방법이지만, 마지막 방식이 가장 편하다!
	*/
	while (_Ptr[Count])
	{
		char Ch = _Ptr[Count];	// 중간중간 값을 받아서 확인해보는 습관을 들이면 좋다!!!
		putchar(static_cast<int>(Ch));
		Count = Count + 1;
	}
}

int main()
{
	char String0[5] = "AAAA";
	char String1[5] = { 'A', 'A', 'A', 'A', 'A' };

	MyPrintf(String0);	// AAAA
	MyPrintf(String1);	// 0을 만날 때까지 계속 출력함

	return 0;
}

do while문

일단 실행코드 1번 실행 → 조건문
⇒ 참일 경우 → 실행코드 1번 실행 → 다시 조건문
⇒ 거짓일 경우 → do while문 탈출

int main()
{
	int Count = 5;

	do
	{
		Count = Count - 1;
	} while (Count);
}

for문

초기화문 → 조건문
⇒ 참일 경우 → 실행코드 1번 실행 → 증감문 → 다시 조건문
⇒ 거짓일 경우 → for문 탈출

/*
for (size_t i = 0; i < length; i++)
{
	실행코드
}
*/

#include <iostream>

int main()
{
	int Value = 1;

	for (
		int i = 0;	// 초기화문
		i < 10;	// 조건문
		i++	// 증감문
		)
	{
		putchar('A');
	}

	/*
	for (; true;)
	{
		putchar('A');
	}
    
	while (true)
	{
		putchar('A');
	}
	*/
}
  • while문과 동일한데, 어떠한 변수를 초기화하는 초기화문과, 그 변수를 증감시키는 증감문이 합쳐진 형태
  • size_t는 배우지도 않았거니와, 언리얼에서 주로 int로 작성하므로 int로 사용하면 된다.

break

즉시 반복문을 종료하고 탈출하라는 의미

int Count = 0;
while (true)
{
	++Count;
	if (Count > 10)
	{
		break;
	}
}

int Hp = 100;
for (int i = 0; i < 5; i++)
{
	Hp -= 80;
	if (Hp <= 0)
	{
		break;
	}
}

continue

for문 ⇒ 즉시 증감문으로 넘어가라는 의미
while문 ⇒ 즉시 조건문으로 넘어가라는 의미

for (int i = 0; i < 10; i++)
{
	if ((i % 2) != 0)
	{
		continue;
	}

	int a = i; // 짝수일 때만 실행
}

int Count = 0;
while (Count < 100)
{
	++Count;
	if ((Count % 2) != 0)
	{
		continue;
	}
	
	int a = Value; // 짝수일 때만 실행
}

연산자 (이어서)

함수로 구현해보면 제대로 이해할 수 있다.

복합 할당 연산자

int Plus(int _Left, int _Right)
{
	return _Left + _Right;
}

void PlusSub(int& _Left, int _Right)
{
	_Left + _Right;
}

int main()
{
	int Result = Plus(10, 10);	// 20
	// int Result = 10 + 10;

	// [덧셈 대입]
	int Value = 0;
	PlusSub(Value, 10);	// 10
	// Value += 10;
	// Value = Value + 10;
}

산술 연산자 (이어서)

int PPFirst(int& _Value)
{
	_Value = _Value + 1;
	return _Value;
}

int PPBack(int& _Value)
{
	int Result = _Value;
	_Value = _Value + 1;
	return Result;
}

int main()
{
	int Value = 0;
	int Result = 0;
	
	// [전위 증감]
	Result = PPFirst(Value);	// 2
	// Result = ++Value;

	// [후위 증감]
	Result = PPBack(Value);	// 1
	// Result = Value++;
}

printf

C에서 사용하던 출력함수

  • 내부 내용이 C 스타일로 작성되어 있다.
  • printf 위에 마우스를 갖다대면 나오는 extern "C" inline int __cdecl printf_s( const char* Format, ...
    • extern “C” ⇒ 해당 부분을 C 스타일로 컴파일 해달라는 뜻
    • inline ⇒ 컴파일러의 판단 하에 이 함수가 실행된 위치에서 함수의 내용을 복사하여 붙여넣고, 함수 자체는 지워버린다. (치환)

💡 인라인 함수

inline int Test()
{
	return 1 + 1;
}

int Value = Test();
int Value = 1 + 1;
// 치환에 성공할 경우, 이 둘이 완전히 동일한 의미가 된다
// 함수를 불러내어 스택영역을 사용하는 것보다 컴파일 속도가 빨라진다

과제

// Q) StringCount()와 StringReverse()를 완성시키자.

#include <iostream>

int StringCount(char* _Ptr)	// 글자 수를 세는 함수
{
	int i = 0;

	for (i = 0; _Ptr[i] != 0; i++)
	{
		char Ch = _Ptr[i];
	}

	return i;

	/*
	int Count = 0;

	while (_Ptr[Count])
	{
		++Count;
	}

	return Count;
	*/
}

void StringReverse(char* _Ptr)	// 글자의 순서를 역으로 바꾸는 함수
{
	int Count = StringCount(_Ptr);

	for (int i = 0; i < (Count / 2); i++)
	{
		putchar(static_cast<int>(_Ptr[Count - i - 1]));
	}

	if (Count % 2 != 0)
	{
		putchar(static_cast<int>(_Ptr[Count / 2]));
	}

	for (int i = 0; i < (Count / 2); i++)
	{
		putchar(static_cast<int>(_Ptr[(Count / 2) - i - 1]));
	}

	return;
    
    /*
    int Value = StringCount(_Ptr);
	int Count = Value / 2;

    for (int i = 0; i < Count; i++)
    {
        // 값을 확인하는 습관을 들이자
        char ChF = _Ptr[i];
        char ChB = _Ptr[(Value - 1) - i];

        char Temp = _Ptr[i];
        _Ptr[i] = _Ptr[(Value - 1) - i];
        _Ptr[(Value - 1) - i] = Temp;
    }

    return;
    */
}
// 아래에 있는 함수는 위에 있는 함수를 사용할 수 있다!!!

int main()
{
	{
		char Arr[10] = "ftz";
		int Result = StringCount(Arr);	// 3
		int a = 9;
	}
	{
		char Arr[10] = "ABCDE";
		StringReverse(Arr);	// "EDCBA"
	}
}

📢 코딩스탠다드
가급적 유지하자!

  1. 전역변수와 지역변수는 이름을 구분하여 작성하자
  2. 변수에는 반드시 초기값을 설정하자
  3. 함수의 인자 앞에는 언더바를 붙이자
  4. 포인터를 초기화할 때 절대 0을 사용하지 말고, nullptr을 사용하자
  5. 경로, 함수명, 변수명에 한글은 절대 쓰지 말자
  6. 프로젝트 생성 시 바탕화면은 절대 피하자
  7. if문을 사용할 때, 한 줄 코드일지라도 반드시 중괄호를 사용하자 (new!)
profile
⋆꙳⊹⋰ 𓇼⋆ 𝑻𝑰𝑳 𝑨𝑹𝑪𝑯𝑰𝑽𝑬 ⸝·⸝⋆꙳⊹⋰

0개의 댓글