[포인터 배열]
• 배열을 가리키는 포인터를 뜻한다. 그럼 초기화 방법을 보도록 하자.
#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+1은 0번째 주소내의 값에다가 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 즉, park의 r에 3을 더한 것이다.
[예시 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 |