언어/C++

포인터

빨대도둑 2022. 11. 7. 13:31

포인터

동적 메모리에서 할당하는 메모리를 주소로 참조해야 할 때 사용하는 것

int* p;
double *p;
char *p;
short *p;

> 포인터는 생성된 직후에 초기화되어있지 않아, 사용하기 전에 반드시 초기화를 해 주어야 한다.

 

주소 연산자

p=&number;


int price=86600;
int *p;
p=&price;
  1. 변수정의
  2. 포인터 정의
  3. 변수의 주소에 포인터 저장

 

간접 참조 연산자

포인터는 포인터가 가리키는 메모리 공간의 값을 읽어오거나 변경할 수 있기 때문에 유용하다. 그리고 내용을 가져오려면 *p라고 하면 된다. 이것을 간접참조라고 한다.

int price=86600;
int *p=&price;

> 포인터가 아무것도 가리키고 있지 않을 때는 nullptr로 설정하는 것이 좋다. nullptr을 사용하면 어디선가 접근을 시도하면 시스템에서 오류를 감지하고 이것을 자동으로 해결해 주기 때문이다. 

주의점 > 포인터 타입과 변수의 타입은 일치해야 한다. 

#include <iostream>
using namespace std;

int main(){
	int number=10;
    //변수 number의 주소를 계산해서 p에 대입
    
    //p가 가리키는 공간에 저장된 값을 출력
    cout<<*p<<endl;
   	return 0;
}

 

nullptr

만약 포인터가 선언만 되고 초기화되지 않았다면 포인터는 임의의 주소를 가리키게 된다. 이 상태에서 포인터를 이용하여 메모리의 내용을 변경하면 문제가 발생한다.

//ex
int *p;
*p=100;

//따라서
int *p=nullptr;

> nullptr을 사용하여서 어딘가에 접근하려고 시도하면 시스템에서 자동적으로 오류를 감지하고 해결하기 때문이다. 

#include <iostream>
using namespace std;

void f(int i){
	cout<<"f(int)"<<endl;
}

void f(char *p){
	cout<<"f(char *)"<<endl;
}

int main(){
	f(NULL);
    return 0;
}

/*main()문 ->*/
int main(){
	f(nullptr);
    return 0;
)

 


동적 메모리 할당

- 프로그램이 실행도중에 동적으로 메모리를 할당받는 것

> 아직 사용하지 않은 메모리공간을 관리하는 것을 히프라고 한다. 동적메모리는 히프에서 할당받는 메모리이다

> 프로그램은 메모리를 얼마나 할당 받을 것인지를 결정하고 라이브러리 함수를 호출하여 운영체제에게 메모리를 요청하는 단계가 필요하다. 만약 충분한 메모리가 존재하면 그 요청은 승인되고 메모리가 할당된다. 

> 프로그램은 할당된 메모리를 사용하여 작업을 하고, 사용이 끝나면 메모리를 다시 운영체제에 반납한다. 만약 메모리를 반납하지 않으면 다른 프로그램이 동적메모리를 사용할 수 없다. 그래서 반드시 동적 메모리는 명시적으로 반납을 해주어야 한다. 

/*new 연산자*/
p=new T;//동적 메모리 타입
p=new T[N];//동적 메모리 개수
p=new T[n] {initializer1,....,initializerN};//동적메모리 초기값

-> 
int *p;
p=new int[5];

/*특정한 값으로 초기화 방법*/
int *p=new int[5] {1,2,3,4,5};


/*delete 연산자*/
delete p;
delete [] p;

 > 할당받은 공간은 해제할 때 반드시 delete [] p;를 사용해야 한다.

#include <iostream>
#include <time.h>
using namespace std;

int main() {
	int* ptr;

	srand(time(NULL));
	ptr = new int[10];

	for (int i = 0; i < 10; i++)
		ptr[i] = rand();

	for (int i = 0; i < 10; i++)
		cout << ptr[i] << "";

	delete[]ptr;
	cout << endl;
	return 0;
}

 

스마트 포인터

/*정적 변수를 가리키는 포인터*/
#include <iostream>
#include <memory>
using namespace std;

int main() {
	unique_ptr<int> p(new int);
	//nuique_ptr: 포인터의 자료형
	//new int: 포인터의 초기값

	*p = 99;
	//p를 사용하며, p가 삭제되면 동적메모리도 같이 삭제
	//삭제 이유: 메모리 누수 발생을 막기 위해
}
/*정수형 배열을 동적으로 생성하여 스마트 포인터로 가리킴*/
#include <iostream>
#include <memory>
using namespace std;

int main() {
	unique_ptr<int[]>buf(new int[10]);

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

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

	cout << endl;
	return 0;
}

- 다른 스마트 포인터 종류

  • *unique_ptr
  • *shared_ptr

 

const

//1
const int *p1;

//2
int *const p2;

//3
const int * const p3;
  • p1은 변경되지 않는 정수를 가리키는 포인터이다. 이 포인터를 통하여 참조되는 값은 변경이 불가능하다
  • p2는 정수에 대한 상수 포인터이다. 정수는 변경될 수 있지만 p2는 다른 것을 가리킬 수 없다. 상수 포인터는 재할당 될 수 없다. 
  • p3는 상수에 대한 상수 포인터이다. 포인터가 가리키는 값도 변경이 불가능하고 포인터 p3도 다른 것을 가리키게끔 변경될 수 없다.

 

> 멤버 함수를 const로 정의하면 함수 안에서 멤버 변수를 변경하는 것은 금지된다. const 객체를 가리키는 포인터를 정의하면 이 포인터로 호출할 수 있는 함수는 const 뿐이다.

#include <iostream>
using namespace std;

class Circle {
private:
	int radius;

public:
	Circle() :radius(10){}
	~Circle() {}
	void setRadius(int radius) { this->radius = radius; }
	int getRadius()const { return radius; }
};

int main() {
	Circle* p = new Circle();
	const Circle* pConstObj = new Circle();
	Circle* const pConstPtr = new Circle();

	cout << "pRect->radius:" << p->getRadius() << endl;
	cout << "pConstObj->radius: "pConstObj->getRadius() << endl;
	cout << "pConstPtr->radius: "pConstPtr->getRadius() << endl << endl;

	p->setRadius(30);
	pConstPtr->setRadius(30);

	cout << "pRect->radius:" << p->getRadius() << endl;
	cout << "pConstObj->radius: "pConstObj->getRadius() << endl;
	cout << "pConstPtr->radius: "pConstPtr->getRadius() << endl;
	return 0;
	
}

 

 

'언어 > C++' 카테고리의 다른 글

상속  (0) 2022.11.14
복사생성자  (0) 2022.11.14
생성자와 접근제어  (0) 2022.10.27
클래스와 객체  (0) 2022.10.27
함수  (0) 2022.10.22