포인터 변수란 무엇인가?
▶ 포인터변수란 data가 저장되어있는 메모리의 시작주소를 값으로 갖는 변수이다.
▶ <typeName *PointerVariableName> 와 같은 형식으로 선언한다.
▶ 주소를 얻어오기 위해서는 '&' 연산자를 변수 앞에 붙인다.
▶ 주소가 주어졌을 때, 그 주소가 가리키는 곳의 값을 얻어오기 위해서는 *연산자를 사용한다.
#include<iostream>
using namespace std;
void main() {
int x = 100;
int *xp = &x; // 포인터 변수 xp에 x가 저장되어있는 메모리의 시작 주소값을 저장합니다.
cout << "xp는 x의 주소값입니다.:" << xp << endl;
//xp는 주소값이므로 맨 처음의 주소값 출력
cout << "&x는 x의 주소값입니다.:" << &x << endl;
//&x는 x의 주소를 나타내므로 맨 처음의 주소값 출력
cout << "xp가 가르키는 값입니다 : " << *xp << endl;
//*xp는 x를 나태내므로 x의 값이 출력
}
포인터변수로 두 변수의 값을 변환하는 예제
#include<iostream>
using namespace std;
void swap(int a, int b) {
int t;
int* ap = &a;
//a의 주솟값을 &을 이용하여 불러옴
int* bp = &b;
//b의 주솟값을 &을 이용하여 불러옴
t = *ap;
//t라는 새로운 변수를 만들어 문자를 저장할 하나의 저장소 생성
*ap = *bp;
*bp = t;
cout << "a:"<< a <<","<<"b:"<< b << endl;
}
void main() {
cout << "변환할 두 수를 입력하세요" << endl;
int a, b;
cin >> a >> b;
swap(a, b);
}
배열에서의 포인터
▶ 배열의 포인터변수를 알아보자
아래와 같이 변수를 정의했다고 가정하고 이 때의 메모리 구성은 다음과 같다.
int arr[4] = {1,3,5,7};
int* ip = arr;
▶ 배열의 시작 주소만 알면 배열의 모든 원소의 값을 알 수 있다.
▶ 배열을 사용할 때는 매개변수로 배열의 시작 주소만을 전달해주기 때문이다.
#include<iostream>
using namespace std;
void main() {
int a[] = { 1,2,3,4,5 };
cout << "a=>" << a << "," << "a[0] =>" << &a[0] << endl;
//a의 주소값과 a[0]의 주소값을 출력한다.
//배열의 시작 주소를 전달하기 때문에 일치한다.
cout << "a=>" << a+1 << "," << "a[0] =>" << &a[1] << endl;
cout << "a=>" << a+2 << "," << "a[0] =>" << &a[2] << endl;
cout << "a=>" << a+3 << "," << "a[0] =>" << &a[3] << endl;
cout << "a=>" << a+4 << "," << "a[0] =>" << &a[4] << endl;
}
포인터 변수에 메모리 할당/ 해제
▶ 포인터 변수에 메모리를 할당하는 경우
다음과 같은 형식으로 할당한다.
typeName *pointerVariableName = new typeName;
int*ip = new int // ip라는 포인터 변수에 int 형의 메모리 할당
▶ int형과 double형 메모리를 할당하는 예제를 보자
#include<iostream>
using namespace std;
int main() {
int* ip = new int; //ip에 int형 메모리 할당
*ip = 999; //ip 값에 999이라는 정수 값을 대입
cout << "ip의 주소 : " << ip << endl;
cout << "ip의 크기 : " << sizeof ip << endl;
cout << "ip의 값 : " << *ip << endl;
cout << "ip값의 크기 : " << sizeof * ip << endl;
double* dp = new double; //dp에 double형 메모리 할당
*dp = 777.77; //dp 값에 777.77이라는 유리수 값 대입
cout << "dp의 주소 : " << dp << endl;
cout << "dp의 크기 : " << sizeof dp << endl;
cout << "dp의 값 : " << *dp << endl;
cout << "dp값의 크기 : " << sizeof * dp << endl;
}
▶ 메모리 할당을 한 결과, ip는 int형이기 때문에 4byte 크기의 메모리가 할당되었고, dp는 double형이기 때문에 8byte 크기의 메모리가 할당되었음을 알 수 있다.
▶ 다음은 포인터 변수에 할당된 메모리를 해제하는 경우이다.
다음과 같은 형식으로 할당한다.
delete pointerVariableName;
int *ip = new int; //ip에 int형 메모리 할당
delete ip; // ip에 할당된 메모리 해제
▶ 할당된 int형 메모리를 해제하는 예제를 보자
#include<iostream>
using namespace std;
int main() {
int* ip1 = new int;//ip1에 int형의 메모리 할당
*ip1 = 999;
cout << "ip1의 주소값 : " << ip1 << endl;
cout << "ip1의 값" << *ip1 << endl;
delete ip1; //ip1에 할당된 메모리를 해제
int* ip2 = new int;//ip1에 int형의 메모리 할당
*ip2 = 777;
cout << "ip2의 주소값 : " << ip2 << endl;
cout << "ip2의 값" << *ip2 << endl;
}
▶ ip1 값에 할당된 메모리를 해제하고, ip2 값에 다시 int형의 메모리를 할당한 결과, ip2의 포인터가 ip1의 자리에 할당되었음을 알 수 있다.
동적 배열의 생성/ 해제
▶ 동적 배열은 다음과 같은 형식으로 생성한다.
typeName *pointerVariableName = new typeName [num of elements];
int *ip = new int [10]; // ip에 int형의 메모리 10개 할당
▶ 동적 배열 생성 예제
#include<iostream>
using namespace std;
int main() {
int* ip = new int[3];
ip[0] = 333;
ip[1] = 777;
ip[2] = 999;
cout << "ip[0] = " << ip[0] << endl;
cout << "ip[1] = " << ip[1] << endl;
cout << "ip[2] = " << ip[2] << endl;
ip++;
cout << "ip[0] = " << ip[0] << endl;
cout << "ip[1] = " << ip[1] << endl;
cout << "ip[2] = " << ip[2] << endl; //None
}
▶ ip에 배열을 할당하고, ip++을 취한 결과, 값이 뒤쪽으로 밀려났음을 알 수 있다.
▶ 동적 배열 해제 형식은 다음과 같다 .
delete [] pointerVariableName;
int *ip = new int[10]; // ip에 int형의 메모리 10개 할당
delete[] ip; // ip에 할당된 10개의 메모리를 해제
▶ 동적 배열 생성 예제
#include<iostream>
using namespace std;
int main() {
int* ip = new int[3];
ip[0] = 333;
ip[1] = 777;
ip[2] = 999;
cout << "ip[0] = " << ip[0] << endl;
cout << "ip[1] = " << ip[1] << endl;
cout << "ip[2] = " << ip[2] << endl;
ip++;
cout << "ip[0] = " << ip[0] << endl;
cout << "ip[1] = " << ip[1] << endl;
cout << "ip[2] = " << ip[2] << endl; //None
delete[]ip; //ip에 할당된 메모리 해제
cout << "ip[0] = " << ip[0]; //error
}
▶ delete를 통해 해제된 ip 배열을 출력한 결과, 메모리가 없기 때문에 에러가 발생했음을 알 수 있다.
다중 포인터
▶ 포인터의 포인터, 즉 포인터 변수의 주소 값을 가지는 포인터 변수라고 보면 된다.
▶ 이를 다중포인터라고도 하는데, *를 여러번 이용하여 다중 포인터 변수를 선언한다.
#include<iostream>
using namespace std;
void main() {
int x = 100;
int* xp = &x;
int** xpp = &xp;
cout << "x의 주소값은 xp입니다." << "xp => " << xp << endl;;
cout << "xp의 주소값은 xpp입니다" << "xpp=>" << xpp << endl;
}
객체 포인터
▶ C언어의 포인터와 동일하다
▶ 위에서 언급했던 것처럼, 객체의 주소 값을 가지는 변수라고 생각하면 된다.
▶ 객체 배열을 선언할 때는 기본 타입 배열을 선언하는 형식과 동일하다.
▶ 객체 배열 선언은 객체 배열을 위한 공간을 생성하여 주고, 배열의 각 원소 객체마다 생성자를 실행하여 준다.
=> Circle이라는 클래스를 생성하고, Circle의 객체 배열 이름을 c라고 선언했을 때, c[0]의 생성자, c[1]의 생성자, 그리고 c[2]의 생성자를 각각 실행하여 준다.
▶ 매개변수가 있는 생성자는 호출할 수 없다.
▶ 배열의 각 객체마다 소멸자를 호출하여 배열을 소멸하는데 이때는 생성의 반대순으로 소멸한다.
=> c[2]의 소멸자, c[1]의 소멸자, c[0]의 소멸자
문제를 통한 정리(main메소드로 클래스 맞추기)
1. 객체 포인터 선언 및 활용 예제
#include<iostream>
using namespace std;
class Circle {
//채워보시오
};
int main() {
Circle donut;
Circle pizza;
cout << donut.getArea() << endl;
Circle* p;
p = &donut;
cout << p->getArea() << endl;
cout << (*p).getArea() << endl;
p = &pizza;
cout << p->getArea() << endl;
cout << (*p).getArea() << endl;
}
2. 클래스의 배열 선언 및 활용
#include<iostream>
using namespace std;
class Circle {
int radius;
public:
Circle() { radius = 1;}
Circle(int r) {
radius = r;
}
void setRadius(int r) {
radius = r;
}
double getArea() {
return 3.14 * radius * radius;
}
};
void main() {
Circle circleArray[3];
//채워보시오
}
3. Circle클래스의 2차원 배열 선언 및 활용
#include<iostream>
using namespace std;
class Circle {
//채워보시오
};
void main() {
Circle circles[2][3];
//채워보시오
}
'💻 개인공부 💻 > C | C++' 카테고리의 다른 글
[C++] 프랜드 함수 (0) | 2020.06.19 |
---|---|
[C++] 생성자와 소멸자 (0) | 2020.06.18 |
[C++] 조건문 (feat. if 문과 switch 문) (0) | 2020.06.17 |
[C++] 포맷 플래그 (0) | 2020.06.12 |
[C++] vector Container (0) | 2020.06.10 |