전체 코드


🔹 1. 포인터 연산의 주요 개념

포인터 연산에는 다음과 같은 네 가지 연산이 있습니다.

  1. 주소 연산자 (&) : 변수의 메모리 주소를 가져옴
  2. 산술 연산자 (+, -) : 포인터의 주소를 이동함
  3. 간접 연산자 (*) : 포인터가 가리키는 값을 참조 (역참조)
  4. 간접 멤버 연산자 (->) : 구조체/클래스 포인터를 통해 멤버 변수에 접근

🔹 2. 코드 분석 및 설명

📌 2.1 #includestruct 선언

#include <iostream> 
using namespace std;

struct Player
{
    int hp;     // +0 (첫 번째 멤버 변수, 구조체의 시작 위치)
    int damage; // +4 (hp 이후의 4바이트 위치)
};
  • iostream: 표준 입출력을 위한 라이브러리 포함
  • using namespace std;: std::cout, std::endl을 간결하게 사용하기 위해 선언
  • struct Player: hpdamage라는 두 개의 int 멤버 변수를 가진 구조체
    • hp는 구조체 시작 주소에 위치하며, damagehp 뒤의 +4바이트 위치에 저장됨

📌 2.2 main() 함수

int main()
{
    int number = 1;
  • number라는 4바이트 크기의 정수형 변수를 선언하고, 1로 초기화

📌 2.3 주소 연산자 (&)

int* pointer = &number;
  • pointernumber의 주소를 저장하는 포인터
  • &number: number 변수의 주소를 가져옴
  • int* pointer: 포인터가 int 타입의 데이터를 가리킨다는 의미

📍 디버깅으로 확인할 수 있는 값

number = 1
&number = 0x1000  (가정, 메모리 주소)
pointer = 0x1000

📌 2.4 산술 연산자 (+, -)

number += 1;  // number = 2;
  • number 값이 1 증가하여 2가 됨
pointer += 1; // 포인터 이동 (4바이트 증가)

📍 여기서 중요한 개념

  • 포인터에 +1을 하면, 실제로 값이 1 증가하는 것이 아니라, 데이터 타입 크기만큼 주소가 증가합니다.
  • pointerint*이므로 int 크기(4바이트)만큼 증가
  • 따라서 pointer += 1; 실행 시, pointer는 기존 주소보다 4바이트 증가한 주소를 가리킴

📍 메모리 변화 예시 (32비트 시스템)

number = 2
pointer = 0x1000 → 0x1004 (4바이트 증가)

📌 2.5 간접 연산자 (*)

number = 3;
*pointer = 3;
  • *pointer = 3;pointer가 가리키는 주소에 있는 값을 3으로 변경하는 코드
  • 하지만, 현재 pointer0x1004를 가리키므로, 원래 number의 값은 변경되지 않음 (잘못된 접근 가능성 있음)

📍 메모리 구조 예시
| 주소 | 값 | 변수명 |
|----------|----|------|
| 0x1000 | 2 | number |
| 0x1004 | 3 | (잘못된 메모리 접근) |


📌 2.6 구조체와 포인터 활용

Player player;
player.hp = 100;
player.damage = 10;
  • Player 구조체 변수 player를 생성하고, hpdamage 값을 설정
Player* playerPtr = &player;
  • playerPtr 포인터가 player의 주소를 가리키도록 설정
(*playerPtr).hp = 200;
(*playerPtr).damage = 200;
  • (*playerPtr).hp: playerPtr이 가리키는 player 구조체의 hp 값을 200으로 변경
  • (*playerPtr).damage: playerPtr이 가리키는 player 구조체의 damage 값을 200으로 변경

📍 메모리 구조 예시
| 주소 | 값 | 변수명 |
|----------|----|------|
| 0x2000 | 200 | player.hp |
| 0x2004 | 200 | player.damage |


📌 2.7 간접 멤버 연산자 (->)

playerPtr->hp = 200;
playerPtr->damage = 200;
  • (*playerPtr).hp = 200; 대신 playerPtr->hp = 200; 형태로 사용할 수 있음
  • -> 연산자는 (*ptr).멤버 표현을 간소화한 문법

둘은 동일한 의미

(*playerPtr).hp = 200;
playerPtr->hp = 200;  // 동일한 코드

🔹 3. 포인터 연산과 어셈블리 코드 분석

어셈블리 코드를 통해 포인터 연산이 어떻게 처리되는지 확인할 수 있습니다.

lea    eax, [number]        ; number 변수의 주소를 eax 레지스터에 저장
mov    dword ptr [pointer], eax  ; pointer 변수에 number 주소 저장
mov    eax, dword ptr [pointer]  ; pointer가 가리키는 값을 eax에 저장
mov    dword ptr [eax], 3   ; eax가 가리키는 주소에 3 저장 (number = 3)

📍 어셈블리 분석
1. lea eax, [number]number 변수의 주소를 eax 레지스터에 저장
2. mov dword ptr [pointer], eaxpointer 변수에 number의 주소 저장
3. mov eax, dword ptr [pointer]pointer가 가리키는 주소의 값을 eax에 저장
4. mov dword ptr [eax], 3eax가 가리키는 주소에 3을 저장 (즉, number = 3)


🔹 4. 포인터 연산 정리 및 주의할 점

📍 포인터 연산 핵심 정리

연산자설명예제
&변수의 주소를 가져옴int* ptr = &num;
+ / -포인터를 타입 크기만큼 이동ptr += 1; (4바이트 증가)
*포인터가 가리키는 값을 참조*ptr = 10;
->구조체/클래스 멤버에 접근ptr->hp = 100;

📍 주의할 점

  1. 잘못된 메모리 접근

    • 포인터가 NULL이거나 초기화되지 않은 경우 런타임 오류 발생 가능
    int* ptr;
    *ptr = 10; // 오류 발생 (ptr이 유효한 주소를 가리키지 않음)
  2. 메모리 누수 방지

    • 동적 할당한 메모리는 반드시 delete 또는 free로 해제해야 함

profile
李家네_공부방

0개의 댓글