기초 CS - 포인터 8

킴스코딩클럽·2022년 10월 20일
1

CS기초 시리즈

목록 보기
42/71

Variable Life Cycle

  • automatic memory allocation
    • 자동 메모리 할당
    • 지역 변수, 함수
    • 변수의 크기는 고정
    • 배열의 크기는 한번 만들면 고정됨
  • static memory allocation
    • static,global 변수 (한번 만들어 지면 초기화 되지 않고 쭉)
    • 만들어지면 살아남는
  • dynamic memory allocation :
    • 내가 원할 때 만들고 원할 때 없앨 수 있는 메모리 관리 기능
    • 사용자가 직접 만든 메모리를 가리키는 기능도 있음
    • 동적 메모리 할당
    • 메모리 물리적 손상 or 공간이없을 때 못만들기도함

c++ dynamic memory allocation

동적 메모리 할당 연산자(operator)

  • new : 생성
  • delete : 삭제
  • 포인터 변수 = new 만들고싶은 타입;
  • 포인터 변수 = new 타입[크기];
  • delete 포인터변수;
  • delete[ ] 포인터 변수;

HEAP 메모리

//int를 동적으로 만들고 싶을 때

int* pNew = new int;
	//인티저를 가리키는 포인터로 동적 메모리 곳을 할당
	//메모리(런타임)에 운영체제가 int의 공간을 잡음
	//동적 메모리는 이름이 없어도 접근 가능함 : HEAP
	//HEAP이라는 공간에 만들어짐
	//포인터로 HEAP에 접근

*pNew = 1;
std::cout << *pNew << std::endl;
	//일반 변수처럼 사용 가능함
delete pNew;
	//지움

struct Student 
   {
    	int number;
        int score;
   };

Student* p = new studnet;
    //heap공간에 메모리 생성
delete p;
    //student 포인터만큼 메모리를 지움
    //하지만, 포인터는 사라지지 않음
    
구조체 사용법
Student* p = new studnet;
   
p->number = 1; 
   //구조체 포인터는 화살표 연산자 필요
(*p).number = 1;
   //역참조와 멤버 연산자를 하나로 묶음 화살표 연산자
  
배열 동적 메모리 사용법

	//int array[3];
    //identifier : array
    //type : int[3]
    
int* p = new int[3];


(*p)[0] = 1; 
	//p를 역참조해서 int타입에 배열을 붙임으로 성립x
*p = 1;
p[0] = 1; 
	//포인터는 배열 

delete p; 
//int* p를 지우게 됨

delete[] p; 
//배열임을 확인시켜줌

배열로 만든 구조체


struct Student
	{
		int number;
		int score;
	};

Student* p = new Student[5];
	//p의 첫번째 원소의 number 멤버를 1로 세팅

p[0].number = 1;
	
(*p).number = 1;
p->number = 1;

p[1].number = 1;

(*(p+1)).number = 1;
(p + 1)->number = 1;  
int x = 1;
	//int scores[x]; 변수를 사용해서 크기 지정 불가

int * p =new int[x];
	//변수로 원하는 만큼 만들기 가능함
delete[] p;
}

주의사항

  • memory leak(메모리 누수)
    • 해제를 제대로 해주지 않는 경우 (delete를 하지않은)
    • 프로그램이 튕기는 오류 가능
    • 메모리 부족 현상
    • new를 써놓고 delete를 안하는(함수를 사용해 만드는 경우
    • 프로그램 작성할 때 new가 나오면 바로 delete를 써놓기
    • 주석을 많이 활용하기 : 만약에 둘을 분리시킨다면
  • new도 실패할 수 있음

int* p = new int;
	//new가 실패한 경우 체크 방법
	//nullpointer사용
	if (p) // (p!=NULL)
		// 거짓 : null
		//그 이외는 참: 정상
		//여기에 들어오는 것은 성공
		//(!p): 실패 
	}

if (p)
{
    *p = 1;
}
else
{
std::cout << "메모리없음" << std::endl;
}
delete p;
  • dangling pointer (허상 포인터) 위태로운 포인터
    + 이미 해제한 메모리
    + delete한 후에는 반드시 nullptr을 할당해 주기
     delete p;
     p = nullptr; 할당하기

    사용 방법

  if(p)
  {
  	//p가 할당되었을 때
  }
  
  delete p;
  //할당되지 않았는데(실패했을때) delete가 불릴 수도 있음
  p = nullptr;
 
 가장 안전한 방법(c에서 사용)
 
 if(p)
 {
  delete p;
  p = nullptr;
 }

메모리 leak

 int* p = new int;

	p = new int;

	delete p;
	//meory leak
	//heap은 이름이 붙지 않고 주소만 있는 공간이기 때문

지우고 다시 만들어야 안전함

int* p = new int;
	delete p;
	p = new int;
	delete p;
아니면 백업
int* p = new int;
int* p1 = p;
p = new int;
delete p;
 

동적 할당 시 초기화 자동
int*p = new int;
int();생략되어있음

메모리 할당 그려보기

void Function1();
void Function2();
const char gString[] = "MEMORY";
int gInteger = 1;
//전역변수는 data영역에 저장

int main() //프로그램이 시작하는 entry point
{
	
	int* pAllocated = new int;//heap 영역에 만들어짐
	//pallocated는 stack에 만들어진 포인터
	
	Function1();//stack에 쌓임
	{

	delete pAllocated; 
	pAllocated = nullptr;

}//main이 빠짐

void Function1()
{
	int local;
	Function2;

	
}

void Function2()
{
	int local;
}

동적 메모리 할당 정리

사용방법 + 유니폼 초기화 식

	int* p = new int;
	int* pArray = new int[3];
	int* p{ new int{3} };
	int* pArray{ new int[3] {1,2,3} };

	if (p)
	{
		//메모리를 정상적으로 할당 받은 경우
	}
	if (pArray)
	{
		//메모리를 정상적으로 할당 받은 경우
	}

	delete p;
	p = nullptr;
	delete[]pArray;
	pArray = nullptr;

heap memory의 필요성

  • 데이터가 크면 heap사용 = 동적 할당

  • 스택 메모리는 늘리는 방법도 있지만 권장하지는 않음

    int main()
    {
    	int array[1000 * 1000];
    	//stack overflow
    	//지역 변수는 stack에 만들어짐
    	//큰 데이터는 반드시 heap에 담아야함
    	//함수는 스택의 constant_1 바이트를 사용합니다.
    	//analyze:stacksize constant_2 초과합니다.
    	//일부 데이터를 힙으로 이동하는 것이 좋습니다.
    }


profile
공부 기록용

0개의 댓글