F.R.I.D.A.Y.

포인터 배열? 배열 포인터? 본문

DEV/C C++

포인터 배열? 배열 포인터?

F.R.I.D.A.Y. 2020. 1. 26. 22:39
반응형

 모든 자료형은 배열로 만들 수 있습니다. 그리고 동시에 포인터로 가리킬 수 있죠. 이번 시간에는 자주 헷갈리는 문법, 포인터 배열과 배열 포인터를 알아봅니다.


배열

 배열 속에 들어있는 각 요소의 자료형은 배열 선언 당시 변수 이름 앞의 자료형입니다.

int   arr1[10];
char  arr2[10];
float arr3[10];
struct data1 arr4[10];
union data2 arr5[10];

 각 배열은 [int, char, float, struct data1, union data2] 타입을 필두로 선언되었습니다. 그럼 포인터를 자료형으로 하는 배열은 어떻게 만들어야 할까요?


헷갈리는 표현

 자, 배열 포인터와 포인터 배열이 있습니다. 다음 코드 중 어느 것이 배열 포인터이고 어느 것이 포인터 배열인지 맞춰보세요.

int *arr1[10];   // CASE 1
int (*arr2)[10]; // CASE 2

답:

    CASE 1 : 정답은[#각주에 포인터 배열]

    CASE 2 : 정답은[#각주에 배열 포인터]

 

 맞히셨나요? 비슷하지만 다른 이 표현은 연산자 우선순위에 의해 자료형의 크기가 달라집니다. 아래 연산자 우선순위 표를 보겠습니다.

https://docs.microsoft.com/ko-kr/cpp/c-language/precedence-and-order-of-evaluation?view=vs-2019

 가장 먼저 대괄호 연산자가 나와 있습니다. 그렇습니다. 배열 연산자는 그 어떤 연산자보다도 우선하여 식을 평가합니다.

 

포인터 배열

CASE 1의 코드 평가는 아래와 같이 이루어집니다.

 

int *arr1[10];   // CASE 1
  1.  arr[10]이 먼저 평가됩니다. 이 코드는 선언하는 코드이므로, arr이라는 변수가 길이 10인 배열이라는 것을 컴파일러가 평가했습니다.
  2.  (1)에서 평가된 arr1[10][# 배열로 평가되었음]의 앞에 int *이 있습니다. arr1 배열 각 요소 자료형이 int *로 평가되었습니다.

배열 포인터

 두 번째, CASE 2의 평가를 보겠습니다.

int (*arr2)[10]; // CASE 2
  1.  소괄호와 대괄호는 우선순위가 같습니다. 평가 방향[# 왼쪽에서 오른쪽]에 의해 소괄호 안을 평가합니다. arr2가 선언되었으며 해당 변수가 포인터임을 알리기 위해 포인터 문자(*)가 붙었습니다.
  2.  (1)에서 평가된 식 오른쪽에 [10]이 있습니다. 따라서 arr2는 길이 10인 배열을 가리킵니다.
  3.  (2)에서 평가된 식 앞에 int가 붙어 있습니다. arr2가 가리키는 배열의 요소가 int임을 알려줍니다.

 헷갈릴 것입니다. 어째서 갑자기 양쪽을 함께 판단하는지 말이죠. 여태까지는 변수를 선언할 때 모든 자료형이 변수 이름보다 앞서서 작성되었습니다. 그러나 배열 포인터의 경우에는 변수명을 사이에 두고 자료형이 나눠집니다. 이 점 유념하기 바랍니다.


배열 포인터, 포인터 배열 크기 비교

 그럼 위 표현들이 어떤 차이를 가지는지 알아보겠습니다. 눈썰미가 좋으신 분이라면 미리 알려준 내용으로 알 수 있을 것입니다.

 

 포인터 배열부터 보겠습니다.

int *arr1[10];   // CASE 1

 앞선 설명을 토대로, 이 코드에서 우리는 arr1이 배열임을 알고 있습니다. 그리고 각 요소의 자료형이 int*. 즉, 자료형이 포인터인 것도 알고 있습니다. 다르게 생각하면 우리는 프로세스의 스택 안에 10개의 포인터 변수를 배열로 선언한 것입니다. 즉, 40Byte[# x86 기준. 이하 같음]를 소비한 것을 알 수 있습니다. 때문에 sizeof 연산자를 이용해 값을 열어보면 40이라는 값이 출력될 것입니다.

 

int (*arr2)[10]; // CASE 2

 또한, CASE 2의 코드는 배열을 가리키는 포인터 변수라고 배웠습니다. 따라서 프로세스 스택 공간에 4Byte를 차지하게 됩니다. 이렇게 선언된 포인터 변수가 가리키는 공간은 40Byte 공간입니다.

#include <stdio.h>

int main(void){
	int *arr1[10], (*arr2)[10];
	
	printf("int   *arr1[10] size: %ld\n", sizeof(arr1));
	printf("int (*arr1)[10] size: %ld\n", sizeof(arr2));
	
	return 0;
}

goorm ide

 goorm ide가 x64 환경인지 포인터의 크기가 8Byte입니다. VS로 프로젝트를 만들고 따로 설정을 변경하지 않았다면 각각 40, 4가 출력될 것입니다.

 

 만일 배열 포인터와 포인터 배열의 생성 구조가 이해가 되지 않으신다면 아래 이미지를 보세요.

 포스트의 처음에 있던 이미지입니다. pointer array라고 이름된 것이 포인터 배열, pointer to array로 이름된 것이 배열 포인터의 구상도입니다.


Reference.

 

우선 순위 및 식 평가 순서

우선 순위 및 식 평가 순서Precedence and order of evaluation 이 문서의 내용 --> C 연산자의 우선 순위와 결합성은 식의 피연산자 그룹화 및 계산에 영향을 줍니다.The precedence and associativity of C operators affect the grouping and evaluation of operands in expressions. 연산자의 우선 순위는 우선 순위가 더 높거나 낮은 다른 연산자가 있

docs.microsoft.com

# index

728x90
반응형

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

공용체(union) part1. default  (0) 2020.01.28
포인터의 크기  (0) 2020.01.26
다차원 배열의 요소 값 교환하기  (0) 2020.01.25
포인터와 배열  (0) 2020.01.24
Designated Initializer  (0) 2020.01.21
Comments