Memory & Address

  • 메모리에는 1byte 단위로 위치를 식별 가능한 물리적인 주소값이 존재한다.
  • 주소 범위: 0 - 232(32bits) 또는 0 - 264(64bits)
  • 주소 표기: 16진수(e.g. 0x100, 0x104, …)
  • 주소 특성: 주소는 이미 정해진 값으로, 변경할 수 없기 때문에 상수이다.
  • 메모리에 접근하는 방법 2가지
    1. 식별자 사용
      • 식별자는 메모리 공간에 붙여진 이름(변수명, 배열명, 구조체명, 함수명 등)이다.
      • 이름을 사용하여 메모리에 값을 저장하거나 저장된 값을 꺼내어 사용할 수 있다.
    2. 실제 주소값(포인터) 사용
      • 프로그램을 실행할 때마다 로딩 위치가 달라지기 때문에 직접 주소를 고정시킬 수는 없다.
      • & 연산자를 사용해 식별자가 가진 시작 주소값(첫 번째 byte)을 얻을 수 있다.

Variable

// int형 변수 선언(4byte 차지)
int a = 10;
int b = 11; 

// 1️⃣ 변수의 포인터 구하기 → 변수명 앞에 주소연산자 &
printf("a의 포인터 : %p\n", &a);    // 100 (a의 시작 주소값)
printf("b의 포인터 : %p\n", &b);    // 104 (b의 시작 주소값)

// 2️⃣ 포인터가 가리키는 메모리를 사용(참조)하기 → 포인터 앞에 참조연산자 *
*&b = 20;
printf("b에 저장된 값 : %d\n", b);   // 20 (포인터로 저장된 값)

int c = *&b;
printf("c에 저장된 값 : &d\n", c);   // 20 (포인터로 꺼내온 값)

// 3️⃣ 포인터 저장하기 → 주소를 저장하는 포인터 변수 만들기
int *pa;                          // int형을 가리키는 포인터 변수
pa = &a;                          // a의 주소를 pa에 배정
*pa = 1;                          // pa가 가리키는 메모리(a)에 값 저장

printf("a의 주소 : %d\n", pa);     // pa 자체는 a의 주소(100번지) 출력
printf("a의 값 : %d\n", *pa);     // *pa로 a의 값(1) 출력
                                 // ⭐️ 별(*pa)을 보고 찾아가면 보석(a)의 값을 알 수 있다

*️⃣

포인터 변수 선언 시 *

  • 해당 변수의 타입을 포인터 타입으로 승격
  • * 개수에 따라 주소 단계(레벨) 결정
// 일반 int 변수
int a = 10;    // (사원a, 100번지)
int b = 50;    // (사원b, 150번지)

// 포인터
int *pa;       //  (대리, 200번지) 1단계 포인터 → int형 변수 주소 저장 
int **ppa;     //  (과장, 300번지) 2단계 포인터 → int* 주소 저장
int ***pppa;   //  (부장, 400번지) 3단계 포인터 → int** 주소 저장

int *pa = &a;       // pa   → 대리는 사원a의 주소(100번지)를 기억
int **ppa = &pa;    // ppa  → 과장은 대리의  주소(200번지)를 기억
int ***pppa = &ppa; // pppa → 부장은 과장의  주소(300번지)를 기억


포인터 사용(접근) 시 *

  • 간접 참조(dereference) 연산자
  • 포인터가 가리키는 값에 접근
  • * 개수만큼 주소 단계(레벨)를 풀어 내려가 실제 값에 도달
*pa = 20;          // *pa    → a(값 변경)  / 대리에서 사원a로 1단계 다운
*ppa = &b;         // *ppa   → pa → &b   / 과장에서 대리로 1단계 다운 후 사원b 주소 저장
**ppa = 30;        // **ppa  → b(값 변경)  / 과장에서 사원b로 2단계 다운
***pppa = 40;      // ***ppa → b(값 변경)  / 과장에서 사원b로 3단계 다운


1d Array

// 길이 3 1차원 배열 arr 선언
int arr[3] = {1,2,3};

// 배열 첫 번째 원소를 가리키는 포인터 변수 선언
int* p;             

// 포인터 변수에 주소 배정하는 2가지 방법
p = &arr[0];  // 1. 주소 연산자로 'arr의 첫 번째 원소'의 주소 넘기기
p = arr;      // 2. 배열명 'arr'는 배열의 시작 주소 '&arr[0]'로 자동 변환됨
       100번지  104번지  108번지 
arr  [   1   |   2   |   3   ]
       4byte   4byte   4byte
------------------------------

<arr+i → i번째 원소의 주소>
arr   == p   == &arr[0] == 100번지
arr+1 == p+1 == &arr[1] == 104번지
arr+2 == p+2 == &arr[2] == 108번지

<주소 arr+i가 가리키는 값 간접 참조 → i번째 원소 값>
*(arr+0) == *(p+0) == arr[0] == 1  == *arr
*(arr+1) == *(p+1) == arr[1] == 2
*(arr+2) == *(p+2) == arr[2] == 3

Array Pointer with 2d Array

// 2행 3열 2차원 배열 arr2 선언
int arr2[2][3] = { {1, 2, 3}, {4, 5, 6} };

int (*pp)[3];  // 열 3개짜리 배열 포인터 (길이가 3인 행 하나를 가리켜야 하기 때문)
pp = arr2;     // arr2 == &arr2[0] (2차원 배열에서 인덱스 1개만 사용 시 행 시작 주소를 뜻함)
           0열         1열          2열
0행   [[ 1(100번지) | 2(104번지) | 3(108번지) ]
1행    [ 4(112번지) | 5(116번지) | 6(120번지) ]]
--------------------------------------------

    pp       == &arr2[0] == 0행 시작 주소
    pp+1     == &arr2[1] == 1행 시작 주소 (int열 3개짜리, 12byte만큼 증가)

  *(pp)      == 0행 자체 == 0행 시작 주소
  *(pp+1)    == 1행 자체 == 1행 시작 주소

  *(pp+1)+0  == &arr2[1][0] == 1행 0열 주소
  *(pp+1)+1  == &arr2[1][1] == 1행 1열 주소

*(*(pp+1)+0) == arr2[1][0] == 1행 0열 값 = 4
*(*(pp+1)+1) == arr2[1][1] == 1행 1열 값 = 5
       ↑  ↑
      행   열

Pointer Array & Double Pointer

// 길이 3인 포인터 배열 선언(배열 포인터 선언 형식에서 괄호만 뺀 형태)
char *ary[3] = {"fig", "pear", "apple"};

// 이중 포인터 → 배열의 원소(포인터) → 문자열
char **ptr_ary = ary;   // ary의 첫 번째 원소를 가리키는 char**
       100번지
ary  [ 200번지 | 300번지 | 400번지 ]
         ↓        ↓        ↓
        fig      pear    apple
---------------------------------

    ptr_ary       == &ary[0] == 100번지
    ptr_ary+1     == &ary[1]

  *(ptr_ary)      == ary[0] == 200번지("fig" 의 시작 주소)
  *(ptr_ary+1)    == ary[1] == 300번지("pear"의 시작 주소)

  *(ptr_ary)+1    == &ary[0][1] == "fig" 의 2번째 문자 주소 == 201번지
  *(ptr_ary+1)+2  == &ary[1][2] == "pear"의 3번째 문자 주소 == 302번지

*(*(ptr_ary)+1)   == ary[0][1] == 201번지의 값 == 'i' 
*(*(ptr_ary+1)+2) == ary[1][2] == 302번지의 값 == 'a'

Tags:

Categories:

Updated:

Leave a comment