1차원 배열이름의 포인터 형과 2차원 배열이름의 포인터 형은 다르기 때문에, 연장선이라고 생각하면 큰일난다. 


지금 하는 것은 앞 서 본 적이 없는 새로운 내용이다. 나도 공부하면서 헷갈렸다. 꼭 머릿속에 박힐 때 까지 복습 또 복습을 하고 넘어가자 !


2차원 배열이름이 가리키는 것들


int arr2d[3][3];


위처럼 선언된 2차원 배열이 있다. 배열이름 arr2d가 가리키는 것은 인덱스 기준으로 [0][0]에 위치한 첫 번째 요소이다.



그런데 2차원 배열의 경우는 arr2d[0], arr2d[1], arr2d[2]도 의미를 갖는다. 이들은 각각 1행, 2행, 3행의 첫 번째 요소를 가리킨다.



따라서 주소값을 출력해보면 arr2d와 arr2d[0]의 주소값은 동일하다. 


그럼 arr2d와 arr2d[0]은 같은 것인가 의문이 들 수 있다.


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
 
int main()
{
    int arr2d[3][3];
    printf("%d \n", arr2d);
    printf("%d \n", arr2d[0]);
    printf("%d \n\n"&arr2d[0][0]);
    
    printf("%d \n", arr2d[1]);
    printf("%d \n\n", arr2d[1][0]);
    
    printf("%d \n", arr2d[2]);
    printf("%d \n\n", arr2d[2][0]);
    
    printf("sizeof(arr2d): %d \n"sizeof(arr2d));
    printf("sizeof(arr2d[0]): %d \n"sizeof(arr2d[0]));
    printf("sizeof(arr2d)[1]: %d \n"sizeof(arr2d[1]));
    printf("sizeof(arr2d)[2]: %d \n"sizeof(arr2d[2]));
    
    
    return 0;
}
 
cs

출력결과

4585464

4585464

4585464


4585476

4585476


4585488

4585488


sizeof(arr2d): 36 

sizeof(arr2d[0]): 12 

sizeof(arr2d)[1]: 12 

sizeof(arr2d)[2]: 12 


배열이름 arr2d를 대상으로 sizeof연산을 하는 경우 배열 전체의 크기를 반환


arr2d[0],arr2d[1],arr2d[2]를 대상으로 sizeof 연산을 하는 경우 각 행의 크기를 반환


arr2d는 첫번째 요소를 가리키면서 배열 전체를 의미하지만, arr2d[0]는 첫번째 요소를 가리키되 배열의 1행만을 의미한다. 그래서 sizeof 연산의 결과가 다른 것이다.


배열이름에 1을 더한 결과


int iarr[3];    // iarr은 int형 포인터


double darr[7];    // darr은 double형 포인터


위의 두 문장은 저번에 공부했던 내용이다. printf("%p %p", iarr+1, darr+1);을 하면 각각 sizeof(int), sizeof(double)의 계산결과가 출력된다.


이렇듯 포인터 형은 포인터 대상의 증가 및 감소연산의 결과를 결정짓는 중요한 요소이다.


"두 포인터의 포인터 형이 같다면, 두 포인터를 대상으로 하는 증가 및 감소연산의 결과로 증가 및 감소하는 값의 크기는 동일하다."


ex) 그렇다면 2차원 배열이름을 대상으로 증가 연산을 진행해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
 
int main()
{
    int arr1[3][2];
    int arr2[2][3];
    
    printf("arr1: %p \n", arr1);
    printf("arr1+1: %p \n", arr1+1);
    printf("arr1+2: %p \n", arr1+2);
    
    printf("arr2 %p \n", arr2);
    printf("arr2+1: %p \n", arr2+1);
    
    return 0;
}
 
cs

출력결과

arr1: 0x7ffeefbff5a0 

arr1+1: 0x7ffeefbff5a8 

arr1+2: 0x7ffeefbff5b0 

arr2 0x7ffeefbff580 

arr2+1: 0x7ffeefbff58c


arr1은 8씩 증가하였고, arr2는 12가 증가하였다. arr1과 arr2 대상의 포인터 연산결과는 다음과 같다.



이렇게 2차원 배열이름을 대상으로 증가 및 감소연산을 할 경우, 각 행의 첫 번째 요소의 주소 값이 된다.

즉 arr1이 1행의 첫 번째 요소를 가리키면, arr1+1이 반환하는 주소 값은 2행의 첫 번째 요소를 가리키게 된다.

때문에 2차원 배열을 이루는 요소의 자료형이 동일하더라도 배열의 가로길이가 다르면 배열이름을 대상으로 하는 포인터 연산의 결과가 달라진다. 즉 포인터 형은 가로의 길이에 따라서도 달라진다!!


int arr[3][4];


위의 배열이름의 포인터 형을 묻는다면,


arr은 가리키는 대상이 int형 변수이고, 포인터 연산 시 sizeof(int) * 4의 크기단위로 값이 증가 및 감소하는 포인터 형이다.

그렇다면 포인터 변수의 선언을 해보자. 


int (*ptr) [4];


ptr은 int형 변수를 가리키면서, 포인터 연산 시 sizeof(int) * 4(가로길이)의 크기단위로 값이 증가 및 감소하는 포인터 변수


이것이 포인터 변수의 선언이다.


ex)

char (*arr1) [4];

- arr1은 char형 변수를 가리키면서, 포인터 연산 시 sizeof(char) * 4의 크기단위로 값이 증가 및 감소하는 포인터 변수


double (*arr2) [7];

- arr2는 double형 변수를 가리키면서, 포인터 연산 시 sizeof(double) * 8의 크기단위로 값이 증가 및 감소하는 포인터 변수


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
 
int main()
{
    int arr1[2][2]={1,2,3,4};
    int arr2[3][2]={1,2,3,4,5,6};
    int i;
    int (*ptr)[2];
    
    ptr = arr1;
    
    for(i=0;i<2;i++)
    {
        printf("%d %d \n", ptr[i][0], ptr[i][1]);
    }
    
    ptr = arr2;
    
    for(i=0;i<3;i++)
    {
        printf("%d %d \n", ptr[i][0], ptr[i][1]);
    }
    
    return 0;
}
cs

출력결과

1 2 

3 4 


1 2 

3 4 

5 6 


8행 : 가로 길이가 동일하니, 이들 배열이름의 포인터 형은 모두 동일하다.


2차원 배열이름의 특성과 주의사항


1. 배열포인터와 포인터배열


int *arr1[5];        // 포인터배열

int(*arr2) [5];     // 배열포인터


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdio.h>
 
int main()
{
    int num1=10, num2=20, num3=30;
    int arr2d[2][4]={1,2,3,4,5,6,7,8};
    int i,j;
    
    int *arr1[]={&num1,&num2,&num3};    // 포인터 배열
    int (*arr2)[4]=arr2d; // 배열 포인터
    
    printf("%d %d %d \n"*arr1[0], *arr1[1], *arr1[2]);
    
    for(i=0;i<2;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d", arr2[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}
 
 
cs
출력결과

10 20 30 

1234

5678


포인터배열과 배열포인터가 헷갈릴 때 참조하면 좋겠다!


2. 2차원 배열을 함수의 인자로 전달하기


int main()

{

int arr1[2][5];

double arr[4][3];

Simple(arr1, arr2);

. . . .

}


이처럼 작성되었다면, 매개변수는 다음과 같이 선언되어야 한다.


void Simple(int (*parr1)[5], double (*parr2)[3]) { . . . . }


이를 대신해 이처럼 작성이 가능하다.


void Simple(int parr1[][5], double parr2[][3]) { . . . . }


두 문장은 완전히 같은 것이다. 


ex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
 
void ShowArr(int (*arr)[4],int column)  // 배열요소 전체출력
{
    int i,j;
    
    for(i=0;i<column;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d",arr[i][j]);
        }
        printf("\n");
    }
}
 
int Sum(int arr[][4],int column)    // 배열요소의 합 반환
{
    int i,j,sum=0;
    
    for(i=0;i<column;i++)
    {
        for(j=0;j<4;j++)
        {
            sum += arr[i][j];
        }
    }
    return sum;
}
 
int main()
{
    int arr1[2][4]={1,2,3,4,5,6,7,8};
    int arr2[3][4]={1,1,1,1,3,3,3,3,5,5,5,5};
    
    ShowArr(arr1,sizeof(arr1)/sizeof(arr1[0]));
    ShowArr(arr2,sizeof(arr2)/sizeof(arr2[0]));
    
    printf("arr1의 합: %d \n", Sum(arr1,sizeof(arr1)/sizeof(arr1[0])));
    printf("arr2의 합: %d \n", Sum(arr2,sizeof(arr1)/sizeof(arr1[0])));
    
    return 0;
}
 
 
cs
출력결과

1234

5678

1111

3333

5555

arr1 : 36 

arr2 : 16 


3행, 17행 : 두 매개변수의 선언에 주목하면, 첫 번째 매개변수는 전달을 받을 때 받는 방법이고, 두번째를 유심히 봐야한다. 두 번째 매개변수를 통해 배열의 세로길이를 전달받는다. 때문에 위 두 함수 모두 가로길이가 4인 int형 2차원 배열이라면 세로길이에 상관없이 인자로 전달이 가능하며, 또 그에 따라서 적절히 동작하도록 함수가 정의되었다.


sizeof(arr1) / sizeof(arr1[0])

sizeof(arr2) / sizeof(arr2[0])


sizeof(arr1)과 sizeof(arr2)의 반환 값은 배열의 전체크기이고, sizeof(arr1[0])와 sizeof(arr2[0])의 반환 값은 배열의 가로크기 이다. 따라서 위의 연산과정을 통해 배열의 세로길이가 계산된다.


3. 2차원 배열에서도 arr[i] == *(arr+i) 는 같다.


arr[2][1] = 4;


1) >> (arr[2])[1]) = 4; >> (*(arr+2))[1] = 4;

2) >> (*(arr+2))[1] = 4; >> A[1] = 4; >> *(A+1) = 4; >> *(*(arr+2)+1) = 4;

3) >> arr[2][1] = 4; >> A[1] = 4; >> *(A+1) = 4; >> *(arr[2]+1) = 4;


'programming > C' 카테고리의 다른 글

C // 문자와 문자열관련함수  (0) 2017.12.28
C // 함수포인터와 void포인터  (0) 2017.12.27
C // 포인터의 포인터  (0) 2017.12.23
C // 다차원배열  (0) 2017.12.22
C // 포인터와 함수  (0) 2017.12.21

+ Recent posts