int arr2d[3][3];

위의 2차원 배열은 다음과 같은 모양을 갖는다.

[0][0] [0][1] [0][2]
[1][0] [1][1] [1][2]
[2][0] [2][1] [2][2]

2차원 배열의 경우 arr2d[0], arr2d[1], arr2d[2]도 각각 1행, 2행, 3행의 첫 번째 요소를 가리킨다.

또한 2차원 배열의 첫 번째 요소의 주소 값을 출력할 때는 다음 두 가지 형태로 동일하게 출력이 가능하다.

printf("%p\n", arr2d);
printf("%p\n", arr2d[0]);
#include <stdio.h>

int main(void)
{
    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;
}
/* output
 -272632624
 -272632624
 -272632624

 -272632612
 -272632612

 -272632600
 -272632600

 sizeof(arr2d) : 36
 sizeof(arr2d[0]) : 12
 sizeof(arr2d[1]) : 12
 sizeof(arr2d[2]) : 12
 */

 위 코드와 같이 arr2d는 첫 번째 요소를 가리키며, 배열 전체를 의미한다.  arr2d[0]은 첫 번째 요소를 가리키며 1행만을 의미한다. 그래서 sizeof 연산 결과 arr2d는 배열 전체의 크기인 36이 출력되었고, arr2d[0]은 첫 번째 행의 크기인 12가 출력되었다.

 

1차원 배열의 경우 다음 코드에서 iarr은 int형 포인터 이기 때문에 iarr+sizeof(int)의 계산 결과가 출력되고,  darr은 double형 포인터 이므로 darr+sizeof(double)이 출력된다.

int iarr[3];
double darr[7];

printf("%p\n", iarr+1);
printf("%p\n", darr+1);

또한 2차원 배열을 대상으로 증가 연산을 진행해보면 다음과 같다.

#include <stdio.h>

int main(void)
{
    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\n", arr1+2);

    printf("arr2 : %p\n", arr2);
    printf("arr2+1 : %p\n", arr2+1);
    return 0;
}
/* output : 
@"arr1 : 0x7ffeefbff7c0\r\n"
@"arr1+1 : 0x7ffeefbff7c8\r\n"
@"arr1+2 : 0x7ffeefbff7d0\r\n"
@"\r\n"
@"arr2 : 0x7ffeefbff7a0\r\n"
@"arr2+1 : 0x7ffeefbff7ac\r\n"
*/

첫 번째 배열의 경우 1씩 증가시켰을 때 8이 증가하였고, 두 번째 배열의 경우 1을 증가시키면 12가 증가하였다. 2차원 배열 이름을 대상으로 증가 및 감소 연산을 할 경우 각 행의 첫번째 요소를 가리킨다. arr1은 1행의 첫번째 요소를 가리키며, arr1+1은 두번째 행의 첫번째 요소를 가리킨다. arr1은 가로가 한 행에 두 칸이기 때문에 8이 증가한 것이다. 2차원 배열의 포인터형은 가로의 길이에 따라서 달라진다.

2차원 배열은 포인트 연산시 sizeof(type) x 가로길이 만큼 값이 증가한다.

 

위와 같은 유형의 포인트 변수 선언은 int형이며, sizeof(int)x4의 크기 단위로 증가 및 감소하는 포인터 변수 선언은 다음과 같다.

int (*ptr)[4];

 

#include <stdio.h>

int main(void)
{
    int arr1[2][2] = {
        {1,2}, {3,4}
    };
    int arr2[3][2] = {
        {1,2}, {3,4}, {5,6}
    };
    int arr3[4][2] = {
        {1,2}, {3,4}, {5,6}, {7,8}
    };

    int (*ptr)[2];
    int i;

    ptr = arr1;
    printf("** Show 2,2 arr1 **\n");
    for(i = 0; i < 2; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);

    ptr = arr2;
    printf("** Show 3,2 arr2 **\n");
    for(i = 0; i < 3; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);
    
    ptr = arr3;
    printf("** Show 4,2 arr3 **\n");
    for(i = 0; i < 4; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);
      
}
/* output : 
@"1 2\r\n"
@"3 4\r\n"
@"** Show 3,2 arr2 **\r\n"
@"1 2\r\n"
@"3 4\r\n"
@"5 6\r\n"
@"** Show 4,2 arr3 **\r\n"
@"1 2\r\n"
@"3 4\r\n"
@"5 6\r\n"
@"7 8\r\n"
*/

위 코드와 같이 포인터 변수를 선언하여 2차원 배열에 접근할 수 있다.

 

2차원 배열의 주소 값을 인자로 전달 받는 함수를 정의할 때 매개 변수는 다음과 같이 선언할 수 있다.

void Function(int (*parr1)[7], double (*parr2)[5]) {...}
void Function(int parr[][7], double parr[][5]) {...}

위 두 방식의 매개변수 선언은 동일한 방식이다.

#include <stdio.h>

void ShowArr2DStyle(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");
    }
    printf("\n");
}

int Sum2DArr(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(void)
{
    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};

    ShowArr2DStyle(arr1, sizeof(arr1)/sizeof(arr1[0]));
    ShowArr2DStyle(arr2, sizeof(arr2)/sizeof(arr2[0]));
    printf("arr1의 합 : %d\n", Sum2DArr(arr1, sizeof(arr1)/sizeof(arr1[0])));
    printf("arr2의 합 : %d\n", Sum2DArr(arr2, sizeof(arr2)/sizeof(arr2[0])));
    return 0;
}
/* output : 
1 2 3 4 
5 6 7 8 

1 1 1 1 
3 3 3 3 
5 5 5 5 

arr1의 합 : 36
arr2의 합 : 36
*/

위 코드의 다음과 같은 연산은 배열의 세로길이를 계산하는 것이다.

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

sizeof(arr1)은 배열의 전체 크기를 나타내고, sizeof(arr1[0])은 배열의 가로의 크기를 나타내기 때문에 위 코드는 배열의 세로 길이를 의미한다.

 

int arr[3][2] = { {1,2}, {3,4}, {5,6} };

2차원 배열이 위와 같이 선언되어 있을 때, 인덱스 [2][1]의 위치의 값을 4로 변경하려면 다음의 코드들을 이용할 수 있다.

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

 

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

[C] void 포인터  (0) 2021.01.08
[C] 함수 포인터  (0) 2021.01.08
[C] 삼중 포인터  (0) 2020.12.28
[C] 더블 포인터  (0) 2020.12.28
[C] 3차원 배열  (0) 2020.12.26

2차원 배열은 다음과 같이 선언한다.

int arr[3][4];	// 세로가 3, 가로가 2인 int형 2차원 배열

2차원 배열의 선언 방식은 세로와 가로의 길이를 각각 명시한다. 이 선언으로 할당되는 배열의 모습은 다음과 같다.

  1열  2열 3열 4열
1행 [0][0] [0][1] [0][2] [0][3]
2행 [1][0] [1][1] [1][2] [1][3]
3행 [2][0] [2][1] [2][2] [2][3]

위 표에서 삽입된 두개의 숫자는 배열에 접근할 때 사용하게 되는 인덱스값이다. 배열의 이름이 arr이고 배열의 자료형이 TYPE라 할 때 2차원 배열의 선언 형태는 다음과 같다.

TYPE arr[세로길이][가로길이];

 

sizeof 연산자를 이용하여 2차원 배열의 크기를 확인해보면 다음과 같다.

#include <stdio.h>

int main(void)
{
    int arr[3][4];
    printf("2차원 배열 크기 : %d\n", sizeof(arr));
    return 0;
}
// output : 2차원 배열 크기 : 48

int 형 배열이기 때문에 한 칸에 4씩 계산하여 48이 나온다.

 

2차원 배열은 다음과 같이 접근하여 값을 저장할 수 있다.

arr[2][1] = 5;
arr[0][1] = 3;

 

2차원 배열의 메모리 주소값도 1차원 배열과 동일한 구조이다. 예를 들어 세로3, 가로2인 2차원 배열을 선언하여 메모리 주소를 확인하면 다음과 같다. 

#include <stdio.h>

int main(void)
{
    int arr[3][2];
    
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 2; j++)
        {
            printf("%p \n", &arr[i][j]);
        }
    }

    return 0;
}
/* output :
0061FF00 
0061FF04 
0061FF08
0061FF0C
0061FF10
0061FF14
*/

int 형 2차원 배열이기 때문에 4바이트 만큼 차이가 나는 상태로 1열로 할당되어 있다.

 

2차원 배열도 선언과 동시에 초기화가 가능하다. 

int arr[3][3] = {
    {1,2,3},
    {4,5,6},
    {7,8,9}
};

위 코드처럼 행 단위로 초기화 할 값들을 별도의 중괄호로 명시해야 한다. 

다음 코드와 같이 초기화를 생략한 요소가 있다면 빈 공간은 0으로 초기화 된다.

int arr[3][3] = {
    {1},
    {4,5},
    {7,8,9}
};

다음 코드와 같이 한 줄로 초기화 하는 것도 가능하다. 

int arr[3][3] = {1,2,3,4,5,6,7};

위 코드와 같이 부족한 부분이 있다면 마찬가지로 0으로 채워진다.

#include <stdio.h>

int main(void)
{
    int arr1[3][3] = {
        {1,2,3},
        {4,5,6},
        {7,8,9}
    };

    int arr2[3][3] = {
        {1,2,3},
        {4,5},
        {7}
    };

    int arr3[3][3] = {1,2,3,4,5,6};

    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            printf("%d ", arr1[i][j]);
        }
        printf("\n");
    }
    printf("\n");

    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            printf("%d ", arr2[i][j]);
        }
        printf("\n");
    }
    printf("\n");

    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            printf("%d ", arr3[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}
/* output : 
1 2 3 
4 5 6
7 8 9

1 2 3
4 5 0
7 0 0

1 2 3
4 5 6
0 0 0
*/

 

1차원 배열처럼 배열의 길이를 명시하지 않고 초기화 하는것도 가능하다. 그러나 다음과 같이 가로와 세로의 길이를 모두 명시하지 않는 것은 불가능하다.

int arr[][] = {1,2,3,4,5,6,7,8};

배열의 요소가 8개 이므로 1x8, 2x4, 4x2, 8x1의 경우로 여러개의 경우가 있기 때문이다.  그래서 하나를 알려줘야 하는데, 다음과 같이 세로의 길이는 생략이 가능하다. 가로 길이는 생략이 불가능하다. 가로의 길이를 생략하면 위 코드와 같이 컴파일러에서 에러를 발생한다.

int arr[][4] = {1,2,3,4,5,6,7,8};
int arr2[][2] = {1,2,3,4,5,6,7,8};

 

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

[C] 더블 포인터  (0) 2020.12.28
[C] 3차원 배열  (0) 2020.12.26
[C] 포인터에서 const 사용  (0) 2020.12.20
[C] Call - by - value, Call - by - reference  (0) 2020.12.20
[C] 함수 인자로 배열 전달  (0) 2020.12.20

+ Recent posts