Ctrl + K + F
: VS 자동 줄바꿈
저번에 배운 가변인자 등의 개념과 저번에 만든 NumberToString함수를 활용해서 printf함수를 만들 수 있다.
함수의 인자들의 주소(위치)는 8바이트씩 차이난다. 그 점을 이용해서 가변인자를 사용할 수 있다.
__int64 Address = reinterpret_cast<__int64>(&_Format);
const int* Ptr = reinterpret_cast<int*>(Address);
Ptr += 2;
__int64 Address = reinterpret_cast<__int64>(&_Format);
Address += 8;
const int* Ptr = reinterpret_cast<int*>(Address);
이외에도 다양할 수 있다.
#include <iostream>
void NumberToString(int Number, char* _Ptr) {
//어떤 함수든 원본값을 보존해 놓는게 좋습니다.
int CalNumber = Number;
int NumberCount = 0;
const char* CPtr = _Ptr;
//정수가 몇자리인지 알아야 합니다.
//10나누기를 합니다.
while (CalNumber) {
CalNumber /= 10;
++NumberCount;
}
int power = 1;
for (int j = 0; j < NumberCount - 1; j++) {
power *= 10;
}
//숫자를 분해하기 시작
//0 나누기가 허용되지 않는다.
int Value = 0;
CalNumber = Number;
for (int i = 0; i < NumberCount; i++) {
Value = CalNumber / power;
_Ptr[i] = Value + '0';
CalNumber -= Value * power;
power /= 10;
}
}
int MyPrintf(const char* const _Format, ...) {
int Count = 0;
__int64 Address = reinterpret_cast<__int64>(&_Format);
while (_Format[Count]) {
char Ch = _Format[Count];
// 포맷팅이 아닐경우 글자를 출력하고 다시 반복한다.
if (Ch != '%') {
putchar(Ch);
Count++;
continue;
}
// 포맷팅 문자인 %를 만났을 경우.
char NextCh = _Format[Count + 1];
switch (NextCh) {
case 'd':
{
// 인자를 끌어내야 합니다.
//int* Ptr = reinterpret_cast<int*>(&_Format); // 1. const char* const인데 값을 바꿀수있게되어버리므로 안됨
// 2. 바로 주소를 포인터로 바꾸는 것은 C스타일임
Address += 8;
const int* Ptr = reinterpret_cast<int*>(Address);
char Arr[100] = {};
NumberToString(*Ptr, Arr);
int Index = 0;
while (Arr[Index]) {
putchar(Arr[Index]);
Count++;
Index++;
}
break;
}
default:
{
int a = 0;
break;
}
}
}
return Count;
}
int main()
{
int Return = MyPrintf("aaabbb %d", 123); //aaabbb 123
return 0;
}
하나씩 차근차근 가리키는 다중 포인터에 대해서는 이해했다. 그런데 이해할 수 없는 부분이 생겼다.
int***
형으로 변환시킨 경우 *Ptr
, **ptr
, ***Ptr
은 각각 어딜 가리키지?? __int64 Value = 1;
__int64*** Ptr = reinterpret_cast<__int64***>(&Value);
확인해보기위한 코드.
__int64** Ptr2 = *Ptr;
__int64* Ptr3 = **Ptr;
__int64 Ptr4 = ***Ptr;
예외가 발생한다.
**Ptr 예외 | ***Ptr 예외 |
---|---|
![]() | ![]() |
*Ptr
에 Value의 1이 들어있다. **Ptr
에는 주소 1이 가리키는 곳의 값이 있지만 램의 주소 1번지는 접근하는 의미가 없으므로 거의 null같은 느낌이다. ***ptr
는 또 (**ptr
)번지의 값을 가리킨다. 1이 아닌 다른 주소를 넣어도 비슷하게 무의미하다.
결론 :
Ptr
에 Value의 주소가 들어가있고,*Ptr
에 바로 1이 있다.**Ptr
,***Ptr
에 각각 쓰레기값이 들어간 것이 아니라, 포인터로서 차근차근 앞을 가리키고 있기는 하다. 하지만 주소를 강제로 다중포인터로 바꾼 것은 거의 아무데나 가리키는 수준이므로 의미없는 행동이다.
#include <iostream>
int CharConvert(char* _String, char _PrevCh, char _NextCh)
{
// 바뀐 글자수를 리턴합니다.
int count = 0; // 바뀐 글자수 세기
int index = 0; // 인덱스
while (_String[index]) {
if (_String[index] == _PrevCh) {
_String[index] = _NextCh;
count++;
}
index++;
}
return count;
}
int main()
{
char Arr[10] = "aaabbbccb";
int Result = CharConvert(Arr, 'b', 'd'); //두번째 문자를 세번째 문자로 바꾸기.
// "aaadddccc"
return 0;
}
// _Start번째부터 전부다 왼쪽으로 한칸이동
void LeftMoveString2(char* _Ptr, int _Start)
{
// 이것도 방어 코드
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];
}
}
// _Start번째부터 전부다 왼쪽으로 한칸이동
void LeftMoveString(char* _Ptr, int _Start)
{
char NewArr[100] = {};
int Count = StringCount(_Ptr);
for (int i = 0; i < _Start - 1; i++) {
NewArr[i] = _Ptr[i];
}
for (int i = _Start - 1; i < Count; i++) {
NewArr[i] = _Ptr[i + 1];
}
// 전체 복사해주기
for (int i = 0; i < Count; i++) {
_Ptr[i] = NewArr[i];
}
}
// _DeleteCh를 지우기
void DeleteChar(char* _Ptr, char _DeleteCh)
{
int Count = StringCount(_Ptr);
for (int i = 0; i < Count; i++) {
if (_Ptr[i] == _DeleteCh) {
LeftMoveString(_Ptr, i + 1);
i--; // 왼쪽으로 옮기고 나면 글자수 전체가 줄기 때문에 i를 같이 땡겨줘야함.
}
}
}
내가 알지 못하는 메모리를 침범하려고 하는 코드 등이 있을 때, 그런 코드를 막기 위해서 사용하는 것을 방어 코드라고 부른다.
int ArrayEx[99];
Function(ArrayEx);
// "Fighter_Ang_Status"
// "{
// <FighterStatus>
// <Att>10</Att>
// <Def>10</Def>
// </FighterStatus>
// }"
}
// Ptr : 500번지, "ABC" : 100번지 라고 할 때
char Ptr[10] = "ABC";
if (Ptr == "ABC") { // false -> 주소값 때문 (500번지와 100번지 비교하는 것)
}
주소를 비교하는 것이기 때문에 Ptr과 "ABC"는 같지 않다. 그래서 strcmp라는 문자열을 비교해주는 함수가 따로 있다.
strlen 문자열 길이
strcmp 문자열 비교
strcpy_s 문자열 복사
int를 char*로 변환했는데 4바이트가 1바이트씩 들어가있을것으로 예상했으나 거꾸로 쪼개져(?) 있다....... 값을 애초부터 뒤집혀서 넣는다.
(사실은 이게 뒤집힌 게 아니라 정상적인 거다.)
바이트의 순서가 우리 눈에 뒤집혀 보이는 이 현상의 이름을 알아오세요..
// 숙제 이 현상을 뭐라고 부를까요?
// 정수의 바이트가 뒤집혀서 보이는 현상.
// 0b00000000 00000000 00000000 00000001
int Value = 0b00000000000000000000000000000001;
// 0b00010001 00000010 00000000 00000000 이렇게 들어감
char* Ptr = reinterpret_cast<char*>(&Value);
// Ptr[0] Ptr[1] Ptr[2] Ptr[3]
// char* 0b 00000001 00001100 00000000 00000000
char Test0 = Ptr[0];
char Test1 = Ptr[1];
char Test2 = Ptr[2];
char Test3 = Ptr[3];