본문 바로가기

강의자료/C/C++

023. 포인터변수에 대해서 이해하자.

◈ 이 글은 강의를 위하여 제가 직접 작성한 내용입니다. 따라서 퍼가실 경우, 출처를 명확히 해주시기 바랍니다!!
◈ This ariticle was written by me for teaching. So if you want to copy this article, please clarify the source!!


포인터 변수에 대해서 이해하자.
#include 
using namespace std;

void main()
{
	// 변수란? 메모리이다.
	// 타입마다 메모리의 크기와 용도(무엇을 저장하느냐)가 다르다.
	int a = 100;
	char b = 'a';
	double c = 3.14;

	// 포인터 변수. -> 변수이므로 메모리를 사용.
	// 포인터는 타입을 의미한다.

	// int -> 4byte, 정수를 저장.
	// int* -> 4byte, 정수를 저장하고 있는 int형 변수(메모리)의 주소를 저장.
	int* pa = &a;
	/*
	int* paa = 100;		// X : 100은 일반적인 값으로 분류되므로 불가능.
	int* paa = a;		// X : a역시 일반적인 값으로 분류되므로 불가능.
	int* paa = pa;		// O : pa가 가지고 있는 값은 주소로 분류되므로 가능.
	int* paa = (int*)a;	// O : a의 값을 주소인것처럼 속이면 가능.
	*/

	// char -> 1byte, 문자를 저장.
	// char* -> 4byte, 문자를 저장하고 있는 char형 변수(메모리)의 주소를 저장.
	char* pb = &b;

	// double -> 8byte, 실수를 저장.
	// double* -> 4byte, 실수를 저장하고 있는 double형 변수(메모리)의 주소를 저장.
	double* pc = &c;

	// 포인터 타입 변수들의 2가지 공통점.
	// 1. 주소를 저장한다. -> 다른 변수를 가위함이다.
	//   - 일반적인 값은 저장할 수 없다. ( int* pa = 100;은 불가능 )
	//   - 일반적인 값과 주소(번지수)를 구분할 수 있어야 한다.
	//   - 예외) 주소외에 저장할 수 있는 유일한 수 : 0(NULL)
	// 2. 4byte의 크기를 가진다.
	//   - 메모리의 주소의 최대값을 저장하기 위해 4byte가 필요하므로.

	//int normal_var = &a;		// 일반 변수는 주소를 저장할 수 없다.
	int normal_var = (int)&a;	// 주소가 아닌 것처럼 속이면 가능하다.

	int abc = 1024;
	int* pabc = &abc;	// *(타입지정자) -> pabc변수를 포인터 타입 변수로 만들어라.

	abc = 2048;
	*pabc = 4096;		// *(연산자) -> 해당 주소로 찾아가라!!
						// *(연산자)다음에는 무조건 주소만 와야된다.
						// pabc[0] = 4096;

	// (int*)* -> 4byte, 
	// int형 변수의 주소를 저장하고 있는 int*형 변수(메모리)의 주소를 저장.
	// 포인터의 포인터는 주소의 주소가 절대 아니다.(이런건 있을 수 없다. 단, 포인터 변수의 주소를 의미할 뿐이다.)
	// 예를 들어 일반 변수 int a = 100;이 있을 때, &&a와 같이 주소의 주소라는 건 존재할 수 없다.
	// 포인터의 포인터가 가능한 이유?? 포인터변수도 하나의 독립적인 변수이기 때문에 자기 자신만의 메모리를 가지고 있다.
	int** ppabc = &pabc;
	// (int**)* -> 4byte, 
	// int*형 변수의 주소를 저장하고 있는 int**형 변수(메모리)의 주소를 저장.
	int*** pppabc = &ppabc;

	int ary[] = {1,12,23,34,45};
	int* pary = &ary[0]; //&ary[0] -> ary.

	// 배열과 포인터의 공통점 : 이름자체가 주소를 의미한다.
	// 배열과 포인터의 차이점 : 포인터는 변수지만 배열은 변수가 아니다.
	cout << pary << endl;	// 배열의 시작주소가 출력된다.
	cout << ary << endl;	// 배열의 시작주소가 출력된다.
	cout << *pary << endl;	// '1' 이 출력된다.

	cout << sizeof(ary) << endl;		// 20 출력.
	cout << sizeof(pary) << endl;		// 4  출력.

	for(int i=0; i < 5; i++)
	{
		cout << ary[i] << endl;
		cout << pary[i] << endl;
		cout << *(pary+i) << endl;	// 100 + 1 = 104.
	}

	int inc_num = 100;
	cout << inc_num << " / " << inc_num+1 << endl;	// 100 / 101 출력.

	int* inc_pnum = &inc_num;
	cout << inc_pnum << " / " << inc_pnum+1 << endl; // 주소 / 주소+4 출력.

	int var = 100;		// var변수는 주소가 1000, 값은 100
	int* pvar = &a;		// pvar변수는 주소가 2000, 값은 1000
	int** ppvar = &pa;	// ppvar변수는 주소가 3000, 값은 2000
}
아래 코드를 실행하기 전에 그 결과를 예측해보자.
#include 
using namespace std;
int main()
{
	int num[]={1,2,3,4,5,6,7,8,9,0}; 
	int *copy;
	int *d;
	int a=5;
	int c=a;       //기본 타입 --> 깊은 복사 
	int *e=&a;     //기본 타입의 *와 &--> 얕은 복사 
	double f=10.0; 
	double *g;
	g=&f;          //기본 타입의 *와 &--> 얕은 복사 
	copy=num;      //참조타입 []와 * --> 얕은 복사  
	d=num;
	cout << "num[0] 값: " << num[0] << "    주소: " << &num[0] << "  =  " << num << endl;
	cout << "num[1] 값: " << num[1] << "    주소: " << &num[1] << endl;
	cout << "num[2] 값: " << num[2] << "    주소: " << &num[2] << endl;
	cout << "num[9] 값: " << num[9] << "    주소: " << &num[9] << endl;
	cout << "*num 값: " << *num << "    주소: " << &num << "  =  " << num << endl;
	cout << "a 값: " << a << "    주소: " << &a << endl;
	cout << "c 값: " << c << "    주소: " << &c << endl;
	cout << "*e 값: " << *e << "    주소: " << &e << "   주소: " << e << endl;
	cout << "f 값: " << f << "   주소: " << &f << endl;
	cout << "*g 값: " << *g << "   주소: " << &g << "   주소: " << g << endl;
	cout << "*copy 값: " << *copy << "    주소: " << © << "  !=  " << copy << endl;
	cout << "*d 값: " << *d << "    주소: " << &d << "  !=  " << d << endl;

	return 0;
}
연습문제 1.
/*
1. int형 변수 num과 int형 포인터 변수 refNum을 선언하시오.
2. refNum을 이용해서 num변수에 숫자 1004를 입력하시오.
3. 출력화면은 아래와 같이 되도록 작성하시오.

num의 값 : 1004
num의 주소 : 0012FF60
refNum의 값 : 0012FF60
refNum의 주소 : 0012FF54
refNum이 참조하는 값 : 1004
*/

#include 
using namespace std;

void main()
{
	int num;
	int*refNum = &num;
	*refNum = 1004;
	cout << "num의 값 : " << num << endl;
	cout << "num의 주소 : " << &num << endl;
	cout << "refNum의 값 : " << refNum << endl;
	cout << "refNum의 주소 : " << &refNum << endl;
	cout << "refNum이 참조하는 값 : " << *refNum << endl;
}
연습문제 2.
/*
1. int형 변수 num1과 num2를 선언하고 각각 100과 200으로 초기화하시오.
2. int형 포인터변수 2개를 입력받아 그 값을 서로 스왑하는 Swap함수를 작성하시오.
3. Swap함수를 이용하여 아래와 같이 출력되도록 작성하시오.

스왑 전 : 100 / 200
스왑 후 : 200 / 100
*/

#include 
using namespace std;
void Swap(int* a, int* b);
void main()
{
	int num1 = 100, num2 = 200;
	cout << "스왑 전 : " << num1 << " / " << num2 << endl;
	Swap(&num1, &num2);
	cout << "스왑 후 : " << num1 << " / " << num2 << endl;
}
void Swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

연습문제 3.
/*
1. int형 배열 num1[5]과 num2[10]를 선언하시오.
2. 배열과 배열의 크기를 인자로 받아 배열을 [0, 1, 2, ..., 배열의크기-1]로 초기화 하는 함수 InitArray를 작성하시오.
3. InitArray를 이용하여 배열초기화 후 아래와 같이 출력되도록 작성하시오.

num1[0] = 0
num1[1] = 1
num1[2] = 2
num1[3] = 3
num1[4] = 4
-------------
num2[0] = 0
num2[1] = 1
num2[2] = 2
num2[3] = 3
num2[4] = 4
num2[5] = 5
num2[6] = 6
num2[7] = 7
num2[8] = 8
num2[9] = 9
*/

#include 
using namespace std;
void InitArray(int* ary,int counts );
void main()
{
	int num1[5];
	int num2[10];
	int n1=sizeof(num1)/sizeof(int);
	int n2=sizeof(num2)/sizeof(int);

	InitArray(num1, n1);
	InitArray(num2, n2);

	for(int i=0; i < n1; i++)
	{
		cout << "num1[" << i << "] = " << num1[i] << endl;
	}
	cout << "-------------" << endl;
	for(int i=0; i < n2; i++)
	{
		cout << "num2[" << i << "] = " << num2[i] << endl;
	}
}
void InitArray(int* ary,int counts )
{
	for(int i=0;i < counts;i++)
	{
		ary[i] = i;
	}
}