Learn business/C++

[C++]포인터와 배열2


[포인터 배열]

배열을 가리키는 포인터를 뜻한다. 그럼 초기화 방법을 보도록 하자

#include <iostream>
using namespace std;
int main(void) {
	int arr[3];
	int *p;
	p = arr; // 배열의 이름은 배열의 시작주소를 나타내는 상수 값
	cout << "arr: " << arr << endl;
	cout << "&arr[0]: " << arr << endl;
}

[예시 1]

다음 예시는 위에서 봤던 예시와 비슷한데 다만, 문자열 배열을 포인터로 테스트를 해본 것이다.

답을 보지 말고 어떤 출력 값이 나올지 생각해보자.

#include <iostream>
using namespace std;
int main(void) {
	char month[] = "December"; 
	char *pt = month;
	cout << "month: "<< month << endl;
	cout << "month[0]: " << month[0] << endl;
	cout << "*month: " << *month << endl;
	cout << "*(month+3): " << *(month + 3) << endl;
	cout << "pt: " << pt << endl;
	cout << "pt+1: " << pt + 1 << endl;
	cout << "*pt: " << *pt << endl;
	cout << "*(pt+4): " << *(pt + 4) << endl;
	printf("*(pt+1)+1: %c\n", *(pt + 1) + 1);
}

답은 아래와 같다!


[포인터의 사용]

출력 값이 주소가 나오는지 값이 나오는지 정리를 해보았다. 아래 표만 보더라도 충분한 이해가 될 것이라 생각한다.

배열(1차원 배열)과 포인터(4byte int형일 때)

주소

포인터

배열

주소

포인터 요소

배열 요소

배열 내의 값

p

a, &a[0]

1000

*p, *(p+0)

a[0]

a[0]번째 값

p+1

&a[1]

1004

*(p+1)

a[1]

a[1]번째 값

p+2

&a[2]

1008

*(p+2)

a[2]

a[2]번째 값

*p+10번째 주소내의 값에다가 1을 더한 값

*(p+1)1번째 주소내의 값


[n차원 형태의 배열을 포인터로 접근]

본격적으로 포인터 배열에 대해 알아보자.

표 아래 충분한 설명을 적었으니 정독하기 바란다.

다양한 배열을 위한 포인터!

포인터 형태

배열 형태

배열 요소형

int *p

int a

int

int *p

int a[4]

int형 배열

int (*p)[4]

int a[3][4]

int [4]형 배열

int (*p)[3][4]

int a[2][3][4]

int [3][4]형 배열

int a[4]

- int형 메모리가 3개 있는 배열이다.

- 각 요소가 int형 이므로 같은 형의 포인터(int *p)를 선언한다.

 

int a[3][4]

- int형 배열 메모리(int [4])3개 있는 2차원 배열을 뜻함

- 각 요소가 int[4] 이므로 int [4]를 가리키는 포인터(int (*p)[4])를 선언한다.

 

int a[2][3][4]

- int형 배열 메모리(int [3][4])2개 있는 3차원 배열을 뜻함

- 각 요소가 int[3][4] 이므로 int [3][4]를 가리키는 포인터(int (*p)[3][4])를 선언한다.


[예시 2]

#include <iostream>
using namespace std;
int main(void) {
	int a[2][3] = { 1, 2, 3, 4, 5, 6 };
	int(*p)[3] = a;
	for (int i = 0; i < 6; i++)
		cout << *(p[0] + i) << " "; 
}

5번째 라인의 초기화가 이해가 될 것이라 생각한다. 거듭 말하지만 a배열의 각 요소가 int[3]형 이므로 int[3]을 가리키는 포인터 int (*p)[4]로 초기화를 해야 한다.

7번째 라인은 2차원 배열이 사람이 이해하기 편하게 아래 표와 같지만, 실제 메모리상에는 연속된 메모리 공간이므로 첫 주소에 a배열의 크기까지 하나씩 이동하면서 출력이 가능하다.


[예시 3]

#include <iostream>
using namespace std;
int main(void) {
	int a[2][3] = { 1, 2, 3, 4, 5, 6 };
	int *p[2] = {a[0], a[1]};
	for (int i = 0; i < 6; i++)
		cout << *(p[0] + i) << " "; 
}

위 예시는 배열 포인터로 초기화를 해주었다. 언뜻 헷갈릴 수도 있다.

자세히 생각해보자. 위 배열 포인터(int *p[2])의 개념은 하나의 요소가 int (*)인 배열이 2개가 있다는 뜻이다.

아래 그림과 같은 모양이다.

int *p[2]하나의 공간에 int형 타입의 주소 값을 담을 수 있다.

그렇다면 int temp; 란 변수가 있을 때, p[0] = &temp; 로 선언이 가능하다.

그럼 int temp[3]; 이란 배열이 있을 때, p[0] = temp;로도 선언이 가능하다.

그럼 a[2][3]의 배열을 아래 그림으로 표현이 가능하다.

a[0]&a[0][0]의 표현과 같은 결과 주소 값이 나올 것이고, a[1]&a[1][0]과 같은 결과 주소 값이 나온다.

그렇다는 것은 p[0]=a[0]으로 a[1]=a[1]이 이해가 될 것이고, 위 예시의 5번째 줄이 이해가 될 것이다.


[예시 4]

• 다음 예시를 답을 보지 말고 맞춰보자.

#include <iostream>
using namespace std;
int main(void) {
	char *name[3] = { "choi", "kim", "park" };
	cout << "*name[2]: " << *name[2] << endl;
	cout << "name[2]: " << name[2] << endl;
	cout << "name[2][0]: " << name[2][0] << endl;
	cout << "*(name+1): " << *(name + 1) << endl;
	cout << "**(name+1): " << **(name + 1) << endl;
	printf("*(*(name+2)+2)+3: %c\n", *(*(name + 2) + 2) + 3);
}

답은 아래와 같다.

어렵다면, 포인터로 표현된 부분을 배열로 바꿔서 생각을 했으면 좋겠다.

위에서 *(a+1)에 대한 표현은 a[1]로 바꿔서 표현을 했다. 이 방식으로 몇 개만 바꿔서 생각해보자.

5번째 줄: *name[2] == *(name[2]+0) == name[2][0]

10번째 줄: *(*(name+2)+2)+3 == *(name[2]+2)+3 == name[2][2]+3 , parkr3을 더한 것이다.

 

[예시 5]

마지막 예시이다. 안보고 생각해보자.

#include <iostream>
using namespace std;
int main(void) {
	char * ptr[] = { "red", "orange", "pink", "white", "blue", "brown", "black", "gray" };
	cout << "**ptr: " << **ptr << endl;
	cout << "ptr[1]: " << ptr[1] << endl;
	cout << "ptr[1]+3: " << ptr[1] + 3 << endl;
	cout << "*(*(ptr+1)+1): " << *(*(ptr + 1) + 1) << endl;
	cout << "*(ptr[3]+2): " << *(ptr[3] + 2) << endl;
	return 0;
}

답은 아래와 같다. 설명이 반복되므로 이해가 안 된다면 위 내용을 정독하자.

'Learn business > C++' 카테고리의 다른 글

[C++]포인터와 배열3  (1) 2016.12.07
[C++]포인터와 배열1  (1) 2016.12.06
[C++]포인터  (0) 2016.12.04
[C++]new & delete  (0) 2016.11.29