2023_12_14

조정우·2023년 12월 14일

tip) 무언가 존재한다면 그것은 위치가 있어야함
-> 공짜는 없고 모든건 메모리를 사용해야 한다 -> 위치가 있어야 한다

R-Value && L-Value

  • L-Value : 왼쪽에 올 수 있는 타입
    -> 명시적 이름(주소)이 있어서 메모리에 접근이 가능해야 함
  • R-Value : 오른쪽에 올 수 있는 타입
    -> 명시적 이름(주소)가 없어서 메모리에 접근 불가능
    -> 연산을 통해 나온 값 등...

ex)

int main()
{
	int Left = 1;
    int Right = 2;
    // Left -> L-Value
    // Right -> L-Value   
    // 눈에 보이지 않는 결과값이 존재
    (Left +Right);	// -> R-Value
}

변수

  • ex)
int main()
{
	int Left = 1;
}
  1. 위치 : main 실행 스택안에 들어있음
    1-1. 위치 : 1000번지(예시)
  2. 크기 : 4 바이트
  3. 형태 : 정수
  4. 값 : 1

return

  • 한번에 하나만 가능
    -> 보충 설명

함수

  • 함수 내부의 return
    -> 값을 리턴하고 함수를 즉각 종료 = 스택 메모리 반환
int Test()
{
	return 10;
}

int main()
{
	int Left = 1;
    
    Left = Test();
}

  • 인자 (Parameter)
    -> 외부의 값을 복사받아서 내부에서 사용하는 것
    -> 지역 변수로 처리
    -> 함수의 인자는 n개 넣을 수 있음
void ParameterStart(int Value)
{
	Value = 9999;
}

int main()
{
	int TestValue = 10;
    ParameterStart(TestValue);
}




Casting (형변환)

  • 형변환이 일어나면 값의 손실변형이 일어 날 수도 있다
  1. 자료형이 다르면 대입이 되면 안되야 한다 (기본)

  2. 될때가 있고 안될때가 있음
    2-1. 암시적 형변환 = 자료형이 다른데 대입이 문법적으로 혀용되는 것
    -> 최대한 피할 것

  3. 명시적 형변환

  • 3-1. C스타일 캐스팅 방식
    -> ()안에 자료형을 적어줌
int main()
{
	int Value = 0;
    bool Check = (bool)Value;
}
  • 3-2. C++ 스타일 캐스팅 방식
    -> 값 <-> 값 형변환 (static_cast<>)= 바이트 크기만 다름
int main()
{
	int Value = 0;
    bool Check = static_cast<int>(Value);
}

-> 값 <-> 참조형 (reinterpret_cast<>)

int main()
{
	int Value = 100;
    int* ptr = &Valaue;
    
    __int64 Address = reinterpret_cast<__int64>(Ptr);
}

cf) Char

  • 1바이트 문자형

cf) bool

  • 1바이트 논리형

cf) 참조형 &

  • 참조형 : 포인터, 레퍼런스 등...
  • 값 : 일반적인 변수

tip) 자료형이 다른데 대입했다 -> 어떤일이 벌어지는지 확실히 알고 해야함\

ex)

int main()	
{
	// 자료형이 다를때 안되게 막는 예시
    int Value = 0;
    int* IntPtr = Value;	// (오류)
    // 자료형이 달라도 대입이 가능한 예시
    int ;
    int64;
}

포인터

  • 변수의 주소값을 저장하기 위한 변수
  • 어떤 변수나 메모리의 램의 정수 위치
    -> 포인터를 위한 연산자와 문법이 별개로 존재
    -> int* 통체로 자료형
    --> int 자료형의 크기보다 크다 (주소값은 int로 표현할 수 없음 주소값이 훨씬 더 큼)
    ---> ex) 16GB는 100억이 넘는다 -> int의 최대값 21억으로 표현 불가능
    -> 자료형 뒤에 * 를 붙이면 해당 자료형의 포인터형이 된다
    cf) 주소값 : 무조건 정수 (16진수 표기법으로 표시)
  • 일반적인 대입이 안된다.
    -> 특정 메모리 영역의 주소값을 리턴해 달라는 단항 연산자(&)를 사용해야 함

ex) 정수라고 해서 정수를 넣어주면 대입이 안된다

int Value = 0;
int* ValuePtr = Value; 	// 틀린것
int * ValuePtr = &Value;	// 맞는것

cf)

int Value = 0;
int* ValuePtr = Value; 	// 틀린것
int** ValuePtrPtr = &ValuePtr;

ex)

int main()
{
	// 포인터
	int* ValuePtr;
}
#include <iostream>

// 함수 밖에서는 아무런 영향이 없음
void Damage(int _Hp, int_Att)
{
	_Hp = _Hp - _Att;
}

int main()
{
	{
    	int MonsterHp = 100;
        Damage(MonsterHp, 10);
    }
}

-> Damage 내부의 변수는 바깥에 존재하는 MonsterHp와 완전히 다른 개체(복제한 것)

  • 이녀석은 이녀석이다 라고 할 수 있는것은 주소가 같은 것

  • 포인터는 변경이 가능하다
    -> 중간에 자신이 가리키는 대상을 바꿀수 있음

int main()
{
	int Value0 = 10;
    int Value1 = 20;
    
    int* Ptr = &Value0;
    *Ptr = 1000;
    // Value0 = 1000;
    
    Ptr = &Value1;
    *Ptr = 2000;
    // Value1 = 2000;
}

Pointer Operator

  • 변수명 앞에 *
#include <iostream>

int main()
{
	// 위치100번지
    // 크기 4바이트
    // 형태 int
    // 값 200
	int MonsterHp = 200;
    
    // 위치 120번지
    // 크기 8바이트
    // 형태 int*
    // 값 100번지
    int* MonsterHpPtr = &MontserHp;
   	
    *MonsterHpPtr = 50;
    // 내가 가진 번지 값의 값이 된다
    // 변수명 앞에 *을 붙이면 해당 변수의 자료형에서 *을 뺀다.
    // ex) int* MonsterHpPtr (int*형)
    // 		-> *MonsterHp (int형)
}
  • 배열이 사용할 수 있는 문법은 포인터도 사용 가능
    -> 포인터는 배열 처럼 사용할 수 있음
int main()
{
	int MonsterHps[5] = { 11, 22, 33, 44, 55 };
    int* Ptr = MonsterHps;
    
    int MonsterHp1 = Ptr[0];
    int MonsterHp2 = Ptr[1];
    int MonsterHp3 = Ptr[2];
    int MonsterHp4 = Ptr[3];
    int MonsterHp5 = Ptr[4];
}
  • 포인터의 주소 이동
    -> Ptr + n = Ptr 주소 + (sizeof(int) * n) 번지
int main()
{
	int MonsterHps[5] = { 11, 22, 33, 44, 55 };
    int* Ptr = MonsterHps;
    
	int MonsterHp0 = *(Ptr + 0);
	int MonsterHp1 = *(Ptr + 1);
	int MonsterHp2 = *(Ptr + 2);
	int MonsterHp3 = *(Ptr + 3);
	int MonsterHp4 = *(Ptr + 4);
}

!!포인터는 배열이 아니다!!

int main()
{
	int MonsterHps[5] = { 11, 22, 33, 44, 55 };
    int* Ptr = MonsterHps;
    
    int ArrSize = sizeof(MonsterHps);	// 20Byte
    int PtrSize = sizeof(Ptr);			// 8Byte
}

Nullptr

-> 0번지
-> 자료형 : nullptr_t

  • C 스타일
    -> 사용하지 않는 포인터는 0으로 값을 넣음
    ->> 주소값이 0을 가리키는 것은 사용하지 않겠다라는 뜻
int main()
{
	int* Ptr = 0;
    
    *Ptr = 100;		// 오류 발생
}
  • 프로그램 메모리 크러쉬 1순이 (Nullptr Exception / Null Reference Exception)
    => 사용하지 말것! -> C++ 11버전 이후로 0 대신 nullptr을 사용

  • C++ 스타일

int main()
{
	int* Ptr = nullptr;
}

cf) 포인터 -> 주소값을 찾거나 아직 가리킬 대상을 찾지 못한 경우 존재

참조 (Reference)

  • 상시 *이 붙은 상태로 사용하는 포인터
int main()
{
	int Value = 0;
    int* Ptr = &Value;
    int SizePtr = sizeof(Ptr);	
    // 포인터의 크기 = 8Byte
    
    int& Ref = Value;
    int SizePtrValue = sizeof(*Ptr);	// 주소값 안에 들어 있는 int 크기 = 4Byte
    int SizeRef = sizeof(Ref);	// => *Ptr과 같은 뜻
    // *Ptr의 크기인 int의 크기 = 4Byte
}
  • 레퍼런스 = 무조건 값이 들어올 때만 사용 가능 (nullptr이 안됨)
    tip) 무조건 값이 있어야 한다고 강제 할 때 사용
int main()
{
	int& ErrorRef;	// 값이 들어오지 않아 오류
	int MonsterHp = 100;
    int& Ref = MontserHp;
    int* Ptr = &MonsterHp;
    
    // 항상 *이 붙어 있는 상태
    Ref = 100;	// -> *Ptr = 100;
    Ref = 200;	// -> *Ptr = 200;
    Ref = 300;	// -> *Ptr = 300;
}
  • 레퍼런스는 한번만 초기화 가능
    -> 1번 초기화되면 대상 변경 불가능
int main()
{
	int Value0 = 10;
    int Value1 = 20;
    
    int& Ref = Value0;
    Ref = 1000;
    // Value0 = 1000;
    
    // Value1은 변경되지 않음/
    Ref = Value1;
    Ref = 200;
}

배열 (Array)

  • int MonsterHps[5]
    -> MonsterHps는 int[]형(int 배열형)

  • 초기화 방법
    -> {}안에 값을 넣어서 초기화
    -> int MonsterHps[5] = { 11, 22, 33, 44, 55 };

  • 제로 베이스
    -> 배열의 시작은 0부터 시작

int main()
{
	int MonsterHps[5] = { 11, 22, 33, 44, 55 };
    
    int MonsterHp1 = MonsterHps[0];
    int MonsterHp2 = MonsterHps[1];
    int MonsterHp3 = MonsterHps[2];
    int MonsterHp4 = MonsterHps[3];
    int MonsterHp5 = MonsterHps[4];
}
  • 배열은 메모리가 이어져 있음 (데이터 형의 크기만큼 떨어져서 이어짐)
int main()
{
	int MonsterHps[5] = { 11, 22, 33, 44, 55 };
    
    // Ref == MonsterHps[0] -> MonsterHps[0] == int&
    int& Ref = MonsterHps[0];
}

과제

  • Parameter의 주소를 확인하기
void Test(int _Value0, int _Value1, int _Value2, int _Value3)
{
	__int64 Address0 = reinterpret_cast<__int64>(&_Value0);
    __int64 Address1 = reinterpret_cast<__int64>(&_Value1);
    __int64 Address2 = reinterpret_cast<__int64>(&_Value2);
    __int64 Address3 = reinterpret_cast<__int64>(&_Value3);
}

int main()
{
	int Value0 = 10;
 	int Value1 = 20;
 	int Value2 = 30;
 	int Value3 = 40;
    
    Test(Value0, Value1, Value2, Value3);
}

-> 주소가 이어져 있다 (int포인터의 크기 8바이트 씩 떨어져 있음)

profile
게임 개발

0개의 댓글