📢 기억해두면 좋은 VS단축키
- Shift + Up or Down ⇒ 드래그와 같은 효과
- 범위 선택 + Alt + Up or Down ⇒ 범위 통째로 윗줄 또는 아랫줄로 이동
- Ctrl + K+ C ⇒ 주석
- 파일명 위에 커서 + Ctrl + Shift + G ⇒ 파일 열기?(iostream과 같은 파일 내용 확인 가능)
- Ctrl + A ⇒ 문서 코드 전체 선택
- Ctrl + K + F ⇒ 자동 줄맞춤
// < %d를 포함한 MyPrintf 구현 >
#include <iostream>
void NumberToString(int _Number, char* _Ptr)
{
int Cnt = 0;
for (int num = _Number; num > 0; num /= 10)
{
Cnt += 1;
}
for (int i = Cnt; i > 0; i--)
{
_Ptr[i - 1] = (_Number % 10) + '0';
_Number /= 10;
}
}
int MyPrintf(const char* const _Format, ...)
{
__int64 Address = reinterpret_cast<__int64>(&_Format); // 주소값
const int* Ptr = reinterpret_cast<int*>(Address); // 해당 주소값을 가리키는 포인터
// const char* const* Ptr = &_Format; => 위 두줄과 같은 의미
Ptr = Ptr + 2; // 8byte 뒤로 => 두번째 인자
int Count = 0;
// 문자열의 길이를 알아낸 다음 for문을 돌려도 좋지만,
// 0을 만날때까지 반복문이 동작하면 되므로 while문이 좋다
while (_Format[Count])
{
char Ch = _Format[Count];
// 1. 포매팅 문자인 %를 만나지 않을 경우
if (Ch != '%')
{
putchar(_Format[Count]);
++Count;
continue;
}
// Ch == '%' 라고 적지 않는 이유
// => 가장 깔끔하게 떨어지는 경우를 상단에 두는 것이 좋다
// 2. 포매팅 문자인 %를 만날 경우
char NextCh = _Format[Count + 1];
switch (NextCh)
{
case 'd':
{
char Arr[100] = {}; // 배열 초기화 잊지 말자!!!
NumberToString(*Ptr, Arr);
int Index = 0;
while (Arr[Index])
{
putchar(Arr[Index]);
++Index;
++Count;
}
break;
}
default:
break;
}
Ptr = Ptr + 2; // 8byte 뒤로 => 다음 인자
}
return Count;
}
int main()
{
int Return = MyPrintf("aaaa bbb");
Return = MyPrintf("aaaa bbb %d %d %d", 123, 345, 6789); // "aaaa bbb 1233456789"
}
포인터의 숙련도 == C++ 실력
#include <iostream>
void Function(int****** ptr, int _Value)
{
// 두번째 인자에 접근하는 방법 두 가지
{
int* IPtr = reinterpret_cast<int*>(&ptr);
char* CPtr = reinterpret_cast<char*>(&ptr);
IPtr = IPtr + 2; // 8byte 뒤로
CPtr = CPtr + 8; // 8byte 뒤로
}
{
__int64 Address = reinterpret_cast<__int64>(&ptr);
Address = Address + 8; // 주소값 8 뒤로
int* ValuePtr = reinterpret_cast<int*>(Address);
}
}
int main()
{
int Value = 1; // 100번지에 있는 1이라는 값
char* Ptr1 = reinterpret_cast<char*>(&Value); // ??에 있는 100번지라는 값
__int64 Address = reinterpret_cast<__int64>(Ptr1); // 100번지
char** Ptr2 = reinterpret_cast<char**>(&Value); // ??에 있는 100번지라는 값(?)
int* Ptr3 = reinterpret_cast<int*>(Ptr1); // ??에 있는 100번지라는 값(?)
*Ptr3 = 20; // 100번지에 있는 Value 값 : 1 -> 20
Function(nullptr, 20);
return 0;
}
*
가 몇 개 붙는지, 자료형이 어떤 것인지’가 아니라 ‘무엇이 메모리 어디에 위치하고, 크기가 얼마이며, 무엇을 가리키고 있는지’이다.#include <iostream>
// 정적배열을 인자로 받을 수 있을 것 같지만, 아니다
// 문법적으로 허용되지만 컴파일러가 아래와 같이 변경해버리기 때문
// void Funcion(int* _Ptr)
void Function(int _Ptr[10])
{
int Size = sizeof(_Ptr); // 40byte(X), 8byte(O)
}
int main()
{
{
int ArrayEx[99];
Function(ArrayEx);
// 인자를 넣어줄 때 암시적 형변환이 발생한다
// int[] -> int*
}
{
"aaaaa"; // const char [6]
// 문자열의 마지막에는 항상 0이 들어간다는 것을 잊지 말자
}
{
strlen("fdfadfdsdaf"); // => 문자열 길이
// strcpy_s(); => 문자열 복사
// strcmp(); => 문자열 비교
// 문자열은 전용 함수들이 따로 있고, 종류도 다양하다
// 직접 구현해보면 도움이 된다
}
{
char Ptr[10] = "ABC";
const char* LeftPtr = Ptr; // 스택영역 속 주소
const char* RightPtr = "ABC"; // 코드영역 속 주소
if (Ptr == "ABC")
{
// if (LeftPtr == RightPtr) 과 동일한 의미이므로 false이다
// 문자열을 비교할 때에는 strcmp() 함수를 사용
}
}
}
문자열 파싱
// Q) CharConvert()를 완성시키자
#include <iostream>
int CharConvert(char* _String, char _PrevCh, char _NextCh) // 바뀐 글자수를 리턴하는 함수
{
int Cnt = 0;
int Res = 0;
while (_String[Cnt])
{
if (_String[Cnt] == _PrevCh)
{
_String[Cnt] = _NextCh;
++Res;
}
++Cnt;
}
return Res;
}
int main()
{
char Arr[10] = "aaabbbccc";
int Result = CharConvert(Arr, 'b', 'd'); // 3
}
// Q) LeftMoveString()과 DeleteChar()를 완성시키자
#include <iostream>
int StringCount(char* _Ptr)
{
int Count = 0;
while (_Ptr[Count])
{
++Count;
}
return Count;
}
void LeftMoveString(char* _Ptr, int _Start) // start부터 왼쪽으로 한칸 미는 함수
{
int Cnt = StringCount(_Ptr);
if (_Start >= 2)
{
for (int i = _Start - 1; i < Cnt - 1; i++)
{
_Ptr[i] = _Ptr[i + 1];
}
}
else
{
for (int i = 0; i < Cnt - 1; i++)
{
_Ptr[i] = _Ptr[i + 1];
}
}
_Ptr[Cnt - 1] = 0;
/*
// 방어 코드
if (_Ptr == nullptr)
{
return;
}
int Count = StringCount(_Ptr);
// 방어 코드
if (_Start <= 0)
{
_Start = 1;
}
for (int i = _Start - 1; i < Count; i++)
{
_Ptr[i] = _Ptr[i + 1];
}
*/
}
void DeleteChar(char* _Ptr, char _Delete) // 특정 char를 삭제하는 함수
{
int Cnt = StringCount(_Ptr);
for (int i = 0; i < Cnt; i++)
{
if (_Ptr[i] == _Delete)
{
LeftMoveString(_Ptr, i + 1);
}
char ch = _Ptr[i];
}
}
int main()
{
{
char Arr[100] = "abcde";
// LeftMoveString(Arr, 0); // "bcde"
// LeftMoveString(Arr, 1); // "bcde"
LeftMoveString(Arr, 2); // "acde"
}
{
char Arr[100] = "a b c d e";
// DeleteChar(Arr, ' '); // "abcde"
DeleteChar(Arr, 'b'); // "a c d e"
}
}
방어코드(Defense Code)
int main()
{
int Value = 517;
char* Ptr = reinterpret_cast<char*>(&Value);
// Value 0b 00000000 00000000 00000010 00000101
// Ptr[0] Ptr[1] Ptr[2] Ptr[3]
// char* 0b 00000101 00000010 00000000 00000000
// 바이트 순서가 거꾸로 들어가는 현상의 이름은?
}