본문 바로가기

개발/C&C++

(C/C++ 속성 정리) 15일 차 : 포인터와 동적할당

안녕하세요 넬다이입니다.

 

오늘은 15일 차 정리입니다. 포인터와 동적 할당입니다.

 

다들 어려운 파트지만 파이팅해주시길 기원할게요.

 


포인터 변수

일반 변수는 값을 저장하기 위해서 사용했고 포인터 변수는 주소를 저장하기 위해서 사용한다.
자료형과 관계없이 4바이트의 크기를 가지며 증감 연산을 하게 되면 해당 자료형의 크기만큼 바이트 이동이 발생한다.
포인터 변수는 선언과 동시에 초기화해야 하며 즉시 값을 채우던지 아니면 NULL로 반드시 초기화 해야 한다.
초기화하지 않으면 위험의 소지가 굉장히 크다.

배열과 포인터의 상관관계를 잘 알고 있어야 합니다.

 

메모리

메모리는 Ram, hdd, cache, register 등을 말하며 이러한 메모리들을 합쳐서 가상 메모리라고 한다.
가상 메모리는 stack, heap, code, data 영역으로 구분할 수 있다.

 

stack 영역은 함수 내부 {} 중괄호 영역에서 할당되는 메모리들에 해당한다.
지역이 생성될 때 할당되고 지역이 종료되면서 메모리에서 해제되는 것들을 말한다.
지역변수, 매개변수들이 여기에 해당한다.

heap 영역은 프로그래머가 직접 할당하고, 해제할 수 있는 메모리 영역이다.
stack이나 data 영역은 컴퓨터가(운영체제) 알아서 할당하고 해제하지만
heap 영역은 그렇지 않다.

예를 들어서 포인터 변수를 100 개 만들었는 데 사용 후 필요가 없어진 변수를 

지우지 않는다면은 사용하지 않아도 100개의 포인터 변수는 데이터 공간에 남아있으므로

메모리 낭비가 심할 것입니다.

heap 영역은 malloc(), calloc(), 함수 혹은 new라는 연산자를 통해서 할당을 하게 된다.

할당을 하게 되면 해제를 해야 된다고 했는데 malloc이나 calloc을 통해 할당한 메모리는
free()라는 함수를 통해서 해제를 하고

new를 통해서 할당한 메모리는 delete를 통해서 해제를 한다.

 

실행파일이 생성되는 과정

전처리기 -> 컴파일러 -> 링크 -> 실행파일 생성(원시 코드) ->
전처리기 -> 컴파일러 -> 목적 코드 -> 시동 코드 -> 링크 -> 실행파일 생성..

동적 할당해보자
배열은 지역공간(stack 메모리) stack 공간의 메모리 할당은 컴파일 타임에 결정이 된다.

런타임 시에 가변적이 배열 생성을 할 수 있도록 해준다.
heap 공간은 런타임 시에 할당하고 해제 시점을 우리가 직접 결정할 수 있다.

heap 공간에 할당하는 것을 동적 할당이라고 부른다.

 

void* malloc(size_t size); 이게 malloc의 구조체 형태이다.

 

하나의 int형의 사이즈를 동적 할당하는 형태

int*	p = (int*)malloc(sizeof(int));

*p = 10;

cout << *p << endl;
cout << p << endl;

free(p);

10개의 int형 사이즈를 동적 할당하는 형태

int*	pArray = (int*)malloc(sizeof(int) * 10);

for(int i = 0; i < 10; ++i)
{
	pArray[i] = i;
}

for(int i = 0; i < 10; ++i)
{
	cout << *(pArray + i) << endl;
}

free(pArray);

위에 구문과 같이 malloc를 하게 된다면은 꼭 free를 해줘야 한다.

이는 동적으로 메모리를 힙 메모리에 할당을 한 것이며 

힙 메모리는 직접 해제해 주거나 컴퓨터가 재부팅 시에 초기화가 된다.

그렇기 때문에 직접 해제를 해주지 않으면은 힙 메모리는 계속해서 쌓이게 되고 메모리 부족이 일어날 것이다.

 

int*	pArray = (int*)calloc(10, sizeof(int));

for(int i = 0; i < 10; ++i)
{
	cout << pArray[i] << endl;
}

free(pArray);

void* calloc(size_t num, size_t size); 

 

c스타일에서 어떤 포인터를 반환할지 명시하지 않아도 묵시적인 형 변환이 발생했었다.
c++에서는 엄격한 형 변환 규칙을 적용하기 때문에 명시적으로 형 변환(casting)을 해야 한다. 

 

calloc와 malloc 은 둘 다 heap 영역을 할당해 주는 것은 같지만
malloc 은 쓰레기 값이 들어가 있고 calloc 0이 들어가 있다는 차이가 있다.

int*	p = new int;

*p = 5;

cout << *p << endl;
cout << p << endl;

//해제
delete p;


c++에서는 new라는 연산자를 사용해서 동적 할당을 할 수 있는데 클래스 문법을 배우게 되면 더 잘 이해가 될 것이다.

 

int*	pArray = new int[10];

for(int i = 0; i < 10; ++i)
{
	pArray[i] = i;
}

for(int i = 0; i < 10; ++i)
{
	cout << pArray[i] << endl;
}

delete [] pArray;

new 연산자를 통해서 블록 단위 할당이 가능하다.

 

포인터의 동적 할당에 대해서 간략하게 정리를 해보았는데

포인터의 동적 할당은 많은 분들이 어려워하는 내용이라서 자세하게 적어야 되는 게 아닌가라는 생각을 했습니다.

하지만 저는 포인터의 동적 할당은 그냥 사용하다 보면은 이런녀석이구나라고 알게 되면서 익히게 된 케이스라서

자세하게 설명하는 것도 좋지만 어떤 형태를 가지고 있는지에 대해서 중점적으로 다루게 되었습니다.

 

자세하게 설명하면은 내용은 비대해지고 읽으시는 분이나 저 또한 힘들 거라고 생각을 했고

자연스럽게 다음 주차 또 그다음 주차를 하시다 보면은 점점 이해가 되고 있을 여러분을 상상하며 

여기에서 설명을 마칠꼐요~~ ㅎ

 

[개발/C&C++] - (C/C++ 속성 정리) 14일 차 : 함수의 사용방법

[개발/C&C++] - (C/C++ 속성 정리) 13일 차 : typedef , 구조체

[개발/C&C++] - (C/C++ 속성 정리) 12일 차 : string 컨테이너

[개발/C&C++] - (C/C++ 속성 정리) 11일 차 : 문자열 및 문자열 함수

[개발/C&C++] - (C/C++ 속성 정리) 10일 차 : 포인터 심화 및 2차원 배열

[개발/C&C++] - (C/C++ 속성 정리) 9일 차 : 포인터와 배열