34~35. 핵심 정리

9669 단어 CC

포인터와 메모리

포인터

  • 포인터는 메모리의 특정 위치를 가리킬 때 사용하며, 정수형으로 된 메모리 주소가 저장되어 있다.
  • 포인터는 * (애스터리스크)를 사용하여 선언한다.
  • 이미 선언된 포인터에 *(역참조 연산자)를 사용하면 포인터에 저장된 메모리 주소에 접근(역참조)하여 값을 가져오거나 저장할 수 있다.

자료형 * 포인터이름;   // 포인터 선언 (*의 위치는 자료형 쪽, 포인터 쪽, 중간 어디든 무관)
* 포인터;   // 포인터를 역참조하여 값을 가져옴
* 포인터 = 값;   // 포인터를 역참조하여 값을 저장

[포인터와 포인터 역참조]

변수의 메모리 주소

  • 변수의 메모리 주소를 구할 때는 주소 연산자 &를 사용한다.
  • &로 구한 주호는 포인터에 할당할 수 있다.
  • 즉, 포인터와 변수의 메모리 주소는 자료형이 같다.

포인터 = &변수;   // 변수의 메모리 주소를 포인터에 저장


포인터, 역참조 연산자(*), 주소 연산자(&)의 관계



포인터와 주소의 자료형

  • int * a;는 ponter to int라고 읽으며, *a와 같이 변수를 역참조하면 pointer to를 제거하여 int로 만든다.
  • int b;에서 &b와 같이 변수의 주소를 구한 것을 address of int라고 읽는다. address of int는 pointer to int와 자표형이 같으므로 포인터에 주소를 할당할 수 있다.
  • 포인터와 주노는 표기법만 차이가 있을 뿐 본질은 같다.

포인터의 자료형과 역참조

포인터는 포인터를 선언한 자료형의 크기만틈 역참조하는 크기가 결전된다.

char *cPtr1;          // char형 포인터 선언
*cPtr1 = 'a';         // char의 크기 1바이트만큼 역참조하여 값을 저장

short *numPtr1;       // short형 포인터 선언
*numPtr1 = 100;       // short의 크기 2바이트만큼 역참조하여 값을 저장

int *numPtr2;         // int형 포인터 선언
*numPtr2 = 100;       // int의 크기 4바이트만큼 역참조하여 값을 저장

long long *numPtr3;   // long long형 포인터 선언
*numPtr3 = 100;       // long long의 크기 8바이트만큼 역참조하여 값을 저장

void 포인터

  • void 포인터는 어떤 자료형으로 된 포인터든 모두 저장할 수 있다.
  • 반대로 다양한 자료형으로 된 포인터에도 void 포인터를 저장할 수 있다.
  • 이러한 특성 때문에 void 포인터는 범용 포인터라고 한다.
  • 단, 자료형의 크기가 정해지지 않았기 때문에 역참조 할 수 없다.

이중 포인터

  • 포인터도 일반 변수이므로 다른 포인터의 메모리 주소를 저장할 수 있다.
  • 포인터의 메모리 주소를 담고 있ㄴ느 포인터를 이중 포인터라고 한다.
  • 이중 포인털르 선언할 때는 *를 두 개 사용하며, 역참조할 때도 *를 두 개 사용한다.
  • int **a;ponter to pointer to int이다.

자료형 ** 포인터이름;   // 이중 포인터 선언
**포인터;   // 이중 포인터를 역참조하여 값을 가져옴
**포인터 = 값;   // 이중 포인터를 역참조하여 값을 저장



메모리

메모리 할당하기

  • mallco 함수를 사용하면 메모리를 바이트 단위로 할당할 수 있다.
  • malloc 함수는 힙(heap) 부분의 메모리를 사용하며, 일반 변수와 다르게 메모리 사용 후 반드시 해제를 해주어야 한다.
  • free 함수로 메모리를 해제할 수 있다.
  • 메모리를 해제하지 않으면 메모리 누수현상이 발생할 수 있다.

자료형 *포인터이름 = malloc(크기);   // 일정 크기만큼 동적 메모리 할당
free(포인터);   // 동적 메모리 해제


메모리를 특정 값으로 설정하기

  • memset 함수를 사용하면 메모리의 내용을 한꺼번에 특정 값으로 설정할 수 있다.
  • 값을 설정하는 단위는 바이트 단위이다.
  • 주로 메모리 값을 0으로 초기화 할 때 사용한다.

memset(포인터, 설정값, 크기);


널 포인터

  • 포인터가 아무것도 가리키고 있지 않는 상태를 __널 포인터(null pointer)라 한다.
  • 포인터에 HULL을 할당하면 된다.

자료형 * 포인터이름 = NULL;   // 포인터에 HULL 할당


잘못된 포인터 사용

  • 포인터에 임의의 값을 할당하면 안된다.
  • ⭐ 반드시 이미 있는 변수의 메모리 주소를 구해서 할당하거나, mallco 함수로 메모리를 할당해야 한다.
int *numPtr = 0x100;    // 잘못된 포인터 사용, 임의의 값을 할당하면 안 됨

int num1;
int *numPtr = &num1;    // 변수 num1의 메모리 주소를 포인터 변수에 저장

int *numPtr = malloc(sizeof(int));    // int의 크기만큼 동적 메모리 할당


Q&A

효율적인 메모리 할당 크기는?

오래 전의 컴퓨터나 일부 임베디드 시스템 등 메모리 크기가 작은 플랫폼은 2의 배수 크기를 권장했다. 하지만 지금은 메모리 크기가 커졌고, 운영체제에서 다양한 알고리즘을 사용하여 메모리를 효율적으로 관리해주므로 이 부분은 크게 신경쓰지 않아도 된다. 메모리를 할당한 뒤 해제를 철저히 해주는 것만으로도 충분하다.


malloc 함수에 음수를 지정하면?

그냥 NULL이 반환된다. malloc 함수는 양수만 사용해야 하낟.


const 포인터를 읽는 방법은?

포인터는 무조건 역순으로 읽으면 쉽다.

  • int *: pointer to int
  • int const *: pointer to const int
  • int * const: const pointer to int
  • int const * const: const pointer to const int
  • int ** const: const pointer to pointer to int
  • int * const * const: const pointer to const pointer to int

const ponter는 포인터의 주소가 바뀌지 않는다는 의미
const int는 int 변수의 값이 바뀌지 않는다는 의미


두 포인터가 같다는 것은 어떤 의미?

포인터에 저장된 것은 메모리 주소이다. 메모리 주소도 정수이므로 두 포인터를 비교할 수 있다.

int *ptr1;
int *ptr2;

// 생략 ...

if (ptr1 == ptr2) { ... }    // 포인터는 ==로 비교할 수 있음

두 포인터가 서로 같다면 메모리 주소가 같다는 뜻이다.
같은 메모리 공간을 가리키게 되므로 두 포인터를 역참조했을 때의 값도 서로 같다


메모리 주소가 아닌 을 바로 비교하고 싶다면 포인터를 역참조한 뒤 비교하면 된다.

int *ptr1;
int *ptr2;

// 생략 ...

if (*ptr1 == *ptr2) { ... }   // 포인터를 역참조하여 ==로 비교

쓰레기 값이란?

변수, 배열을 선언하거나 메모리를 할당하면 사용이 끝난 메모리를 다시 사용하게 된다. 쓰레기 값은 이전에 메모리를 사용할 때 저장된 값을 뜻하며, 메모리를 다시 사용하는 시점에서는 필요없는 값이므로 쓰레기 값이라 부른다. 따라서 변수, 배열을 선언하거나 메모리를 사용할 때 쓰레기 값이 다시 사용되자 않도록 내용을 초기화해야 한다.



출처

https://dojang.io/mod/page/view.php?id=605
https://dojang.io/mod/page/view.php?id=606

좋은 웹페이지 즐겨찾기