안녕하세요!
이틀 째 비가 내리고 있어 이제 "여름이 왔구나" 느끼고 있습니다.
글을 쓰기 전, 진행 현황 확인과 복습을 위해 프로젝트를 다시 한 번 훑어보았습니다.
현재 프로젝트에 들어간 기능은 지난 글로 모두 정리가 끝난 것 같아 빠뜨린 기능 설명이나 추가적인 설명이 필요하시다면 댓글 남겨주시면 확인 즉시 답변 드리겠습니다!
구현 기능 목록
BP_Character
- Set Mapping Context
- Create Player HUD
- Move Control
- Look Control
- Zoom In & Zoom Out
- Fire Mechanism
- Reload Mechanism
- Player Damage Mechanism
BP_Ant
- Random Move Mechanism
- Chase Mechanism (make Function)
- Enemy Attack Mechanism
- Enemy Damage Mechanism
BP_MainGameMode
- Create Main HUD
- Update Remaining Time Logic
- On Player Killed Logic (UpdateRemainingAlive Function)
- On Ant Killed Logic
BP_Item_Health & BP_Item_Ammo
- On Component Begin Overlap
- Add Health Function & Add Ammo Function (BP_Character)
WBP_MainHUD & WBP_PlayerHUD
- On Clicked (Exit Button & Restart Button)
글로 정리하면 이 정도인 것 같습니다!
이제 오늘 부터 본격적으로 캠프 2주차에 들어왔습니다.
2주차 부터는 C++를 배우게 된다고 합니다.
오늘 학습한 내용에 대해 정리 해보도록 하겠습니다.
C++ 첫 시간이라서 지금까지 학습하였던 C언어 기초와 대부분 같은 내용을 담고 있었습니다.
다만 오늘 강의에서는 포인터에 대해 더 자세히 다뤄, 포인터에 대해 조금 더 깊게 학습하는 시간이 되었습니다.
그래서 포인터에 대해 다시 한 번 짚고 넘어가겠습니다.
포인터
일반적인 변수는 메모리 공간을 할당하여 값을 저장한다면 포인터 변수는 할당된 메모리 공간에 주소 값을 저장합니다.
기본 형태는 자료형 *포인터명 = &(메모리 주소를 가져올 변수의 변수명); 의 형태를 갖춥니다.
기본 형태에서 *연산자는 이 변수가 주소 값을 받는 변수임을 나타내는 역할을 합니다.
그리고 &연산자는 현재 값이 &연산자 뒤에 오는 변수의 주소임을 나타내는 역할을 합니다.
결국 자료형 *포인터명 = &(메모리 주소를 가져올 변수의 변수명); 은 메모리 주소를 가져올 변수의 주소를 포인터 변수에 저장하겠다는 의미가 됩니다.
ex)
int a = 5;
int *p = &a;
//변수 a의 주소
printf("%p\n", &a);
//포인터 변수 p에 저장된 주소
printf("%p\n", p);
//변수 a의 값
printf("%d\n", a);
//포인터 변수 p에 저장된 주소 안의 값
printf("%d\n", *p);
실행 결과 값
0x01 <= 임의로 지어낸 주소 값입니다..
0x01
5
5
추가적으로 설명하면, 각 자료형 마다 메모리에 할당되는 크기(용량)이 다르고 자료형 마다 자료를 읽는 방법이 다르므로 자료형을 꼭 표기해주어야 합니다.
그리고 포인터 변수를 선언할 때는 *연산자는 해당 변수가 포인터 변수임을 나타내는 역할을 했다면 포인터 변수를 호출할 때는 *연산자가 해당 포인터 변수가 가지고 있는 주소 안의 값을 가져오겠다는 역참조의 역할을 합니다.
*연산자는 애스터리스크(Asterisk)라고 읽으며 &연산자는 앰퍼센드(Ampersand)라고 읽습니다.
배열과 포인터 변수
배열은 자료형 배열명[배열의 크기] = {첫 번째 값, 두 번째 값, ..., 마지막 값}; 의 형태를 갖춘다고 이전 글에서 말씀드렸습니다.
이렇게 배열을 선언했을 때, 사실 배열명에는 배열의 첫 번째 값이 들어있는 주소 값(배열의 시작 주소 값)을 저장하고 있습니다.
그래서 자료형 *포인터명 = 배열명; 으로 초기화가 가능합니다. (배열명 앞에 &연산자가 없어도 됩니다.)
*포인터명 으로 호출할 경우, 배열의 첫 번째 값이 호출되게 됩니다. 배열명에는 배열의 첫 번째 값 주소가 들어가 있기 때문입니다.
ex)
int arr[4] = {1, 2, 3, 4};
int *p = arr;
printf("%d\n", arr[0]);
printf("%d\n", *p);
실행 결과 값
1
1
두 값이 같은 것을 확인할 수 있고 배열은 메모리 공간을 연속해서 할당하기 때문에 i 번째 배열의 값을 호출하고 싶을 때는 *(p + i)로 해당 위치의 배열의 값을 호출할 수 있습니다.
즉, 배열 arr의 i 번째 값 arr[i]는 *(p + i)로도 표현이 가능합니다.
추가적으로 arr[i]로 i 번째 값을 호출할 수 있는 것 처럼 포인터를 이용해 p[i]로도 i 번째 값을 호출 할수 있습니다.
배열과 포인터 변수의 차이
그럼 배열도 배열명을 호출할 때, 배열의 첫 번째 값 주소가 저장되어있으면 "배열과 포인터는 같은 것이 아닌가?"라는 의문을 가질 수 있습니다.
다만 배열은 배열의 첫 번째 값 주소가 저장되어 있고 저장된 주소 값을 바꿀 수 없다는 점과 동시에 배열의 크기도 저장되어 있기 때문에 엄연히 다릅니다. 단지 배열은 호출할 때, 편의성을 위해서 배열의 시작 주소를 호출한다고 이해하시면 될 것 같습니다.
ex)
int arr[4] = {1, 2, 3, 4};
int *p = arr;
int sizeArr = sizeof(arr);
int sizeP = sizeof(p);
printf("%d\n", sizeArr);
printf("%d,\n", sizeP);
실행 결과 값
16
8(또는 4)
arr의 크기는 배열이 할당 받은 메모리의 크기 즉, int 자료형의 크기(4 byte) * 4 즉, 16이기 때문에 16이 나옵니다.
그럼 sizeP의 값이 8이 나오신 분께서는 "int 자료형의 포인터 p의 크기는 int 자료형의 크기(4 byte)가 아닌가?"라는 의문을 가질 수 있습니다.
8이 나오는 이유는 포인터 변수는 주소 값을 저장하기 때문에 현재 컴퓨터의 OS(운영체제) bit의 모든 주소 값을 저장할 수 있는 크기를 갖습니다.
즉 32bit 운영체제 에서는 포인터 변수의 크기를 4 byte로 할당하고 64bit 운영체제에서는 포인터 변수의 크기를 8 byte로 할당하는 것을 확인 하실 수 있습니다.
포인터 배열과 배열 포인터
먼저 포인터 배열은 각각의 메모리 공간에 주소 값을 저장하는 배열을 포인터 배열이라고 합니다.
기본 형태는 자료형 *포인터명[배열의 크기] = {&(첫 번째 변수명), &(첫 번째 변수명), ..., &(마지막 변수명) }; 의 형태를 갖춥니다.
배열 포인터는 배열의 크기 값까지 저장하는 포인터 입니다. 다르게 말씀드리면 배열 자체를 저장하는 포인터라고 표현할 수 있습니다.
기본 형태는 자료형 (*포인터명)[배열의 크기] = &배열명; 의 형태를 갖춥니다.
따라서 int arr[3]의 배열이 있고 int (*arrP)[3] = &arr; 로 배열 포인터를 선언 했다면, arr[1]의 값과 (*arrP)[1]의 값은 같게 나옵니다.
**배열 포인터는 주로 다차원 배열에서 쓰입니다.**
레퍼런스
포인터와 레퍼런스의 차이점은 포인터는 주소 값을 가지고 있고 그 주소 값을 활용하여 주소 안의 값을 호출할 수 있다면 레퍼런스는 처음부터 대입한 변수와 같은 주소를 가집니다. 즉, 레퍼런스는 변수의 별명을 만들어주는 것이라고 할 수 있습니다.
ex)
int a = 4;
int& ref = a;
printf("%p\n", &a);
printf("%p\n", &ref);
ref = 10;
printf("%d\n", a);
printf("%d\n", ref);
실행 결과 값
0x03 <= 임의의 주소 값
0x03
10
10
포인터와의 차이점은 레퍼런스는 선언과 동시에 초기화 해주어야 합니다.
그리고 한번 초기화되면 가리키고 있는 주소를 변경할 수 없습니다. 즉, 다른 대상에 재연결 할 수 없습니다.
또한, 레퍼런스는 무조건 값을 가지고 있어야하기 때문에 NULL / nullptr를 사용할 수 없습니다. 반면, 포인터는 nullptr를 통해 값을 가지지 않을 수 있습니다.
마지막으로 포인터 변수는 메모리 주소 안의 값을 호출하기 위해서 *연산자를 통해 역참조 해야되지만 레퍼런스는 변수를 호출하듯 레퍼런스명을 통해 값을 호출할 수 있습니다.
상수 레퍼런스는 변수의 값을 호출할 수 있지만 값을 변경할 수 없는 레퍼런스 입니다.
즉, 읽기 전용으로 다른 곳에서 변수의 값을 사용할 때, 값이 변하지 않도록 안전하게 호출할 수 있도록 사용할 수 있습니다.
ex)
int a = 5;
const int& ref = a;
printf("%d\n", a);
printf("%d\n", ref);
a = 10;
// ref = 20; <= 오류가 발생합니다. 상수 레퍼런스이기 때문입니다.
printf("%d\n", a);
printf("%d\n", ref);
실행 결과 값
5
5
10
10
상수 레퍼런스의 경우, 당연하지만 읽기만 가능하고 값을 변경할 때는 원본 변수를 호출해야 합니다.
오늘은 여기까지 학습하였습니다.
혹시라도 제가 학습한 내용 중 빠뜨린 내용이나 더 추가하면 좋겠다고 느끼는 내용이 있다면 추후 언제든 내용 수정을 통해 더 추가하도록 하겠습니다!
오늘도 고생 많으셨고 내일도 힘내서 열심히 공부하겠습니다!
'[내일배움캠프] 본 과정 학습내용' 카테고리의 다른 글
| [내배캠] 9일차 C++ 학습 내용 정리 (0) | 2026.07.08 |
|---|---|
| [내배캠] 8일차 C++ 학습 내용 정리 (0) | 2026.07.07 |
| [내배캠] 5일차 Unreal Blueprint 내용 정리(1) (0) | 2026.07.03 |
| [내배캠] 4일차 Unreal Blueprint로 적 구현과 C언어 기초 (0) | 2026.07.01 |
| [내배캠] 3일차 Unreal Blueprint로 총 기능 구현과 C언어 기초 (0) | 2026.06.30 |