Skip to content

30. 2차원 배열


1. 키워드

  • 2차원 배열


2. 2차원 배열 사용하기

  • 2차원 배열은 다음과 같이 행과 열 형태로 이루어져 있으며 행과 열 모두 0부터 시작한다.


001


3. 2차원 배열을 선언하고 요소에 접근하기

  • 2차원 배열은 [](대괄호)를 두 번 사용하여 선언하며 첫 번째 []에는 행 크기, 두 번째 []에는 열 크기을 지정한다.


자료형 배열이름[행크기][열크기];
자료형 배열이름[행크기][열크기] = {{, , }, {, , }};


  • 다음은 행 크기가 3, 열 크기가 4int 타입 2차원 배열을 선언하는 방법이다.
  • 2차원 배열을 선언하면서 초기화하려면 {}(중괄호)를 사용하는데 열을 먼저 묶어주고, 열을 행 크기만큼 다시 묶어준다.
  • {} 안의 값과 줄 개수는 행, 열 크기보다 작아도 되지만 크면 안 된다.


int numArr[3][4] = {
    {  요소 4 },
    {  요소 4 },
    {  요소 4 }
}; //     ↑ 행 3줄


  • {}를 사용하여 배열에 값을 할당하는 방법은 배열을 선언할 때만 사용할 수 있으며, 이미 선언된 배열에는 사용할 수 없다.


  • 2차원 배열의 요소에 접근하려면 배열 뒤에 []를 두 번 사용하며 [] 안에 행 인덱스와 열 인덱스를 지정해 주면 된다.


배열[행인덱스][열인덱스]


  • 즉, 다음과 같이 2차원 배열에서 행 인덱스 1, 열 인덱스 2인 요소의 값을 가져올 수 있다.


int num1 = numArr[1][2]; // 2차원 배열에서 행 인덱스 1, 열 인덱스 2인 요소에 접근


  • 이제 2차원 배열을 선언하고 요소의 값을 출력해 보자.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

//                        ↓ 행 인덱스
    printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
    printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 2인 요소 출력
//                           ↑ 열 인덱스

    return 0;
}

// 11
// 77
// 99
// 132


  • 행 크기 3, 열 크기 4int 타입 2차원 배열은 선언하고, 값을 초기화했다.


int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
    {11, 22, 33, 44},
    {55, 66, 77, 88},
    {99, 110, 121, 132}
};


  • 2차원 배열도 인덱스는 0부터 시작한다.
  • 따라서 배열 numArr의 행 첫 번째, 열 첫 번째 요소는 numArr[0][0]이 된다.


002


배열의 초기화

  • 다음과 같이 2차원 배열을 초기화할 때 열 요소를 {}로 묶지 않아도 컴파일은 잘 되고, 결과도 열 요소를 {}로 묶었을 때와 같다.
  • 하지만 이렇게 작성하면 이해하기가 어려워서 잘 쓰이지 않는 방법이다.


int numArr[3][4] = {11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121, 132};


4. 2차원 배열을 초기화하기

  • 2차원 배열의 요소를 간단하게 0으로 초기화해 보자.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 2차원 배열의 요소를 모두 0으로 초기화
        0,
    };

//                        ↓ 행 인덱스
    printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
    printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 2인 요소 출력
//                           ↑ 열 인덱스

    return 0;
}

// 0
// 0
// 0
// 0


  • 2차원 배열을 선언할 때 {0,}을 할당하여 배열의 요소를 모두 0으로 초기화했다.
  • 이렇게 하면 초기화할 때 0을 일일이 나열하지 않아도 된다.


5. 2차원 배열의 요소에 값 할당하기

  • 이번에는 배열을 선언할 때 값을 초기화하지 않고, 배열의 요소에 각각 할당해 보자.


배열[행인덱스][열인덱스] = ;
#include <stdio.h>

int main()
{
    int numArr[3][4];

    numArr[0][0] = 11; // 행 인덱스 0, 열 인덱스 0인 요소에 값 할당
    numArr[0][1] = 22; // 행 인덱스 0, 열 인덱스 1인 요소에 값 할당
    numArr[0][2] = 33; // 행 인덱스 0, 열 인덱스 2인 요소에 값 할당
    numArr[0][3] = 44; // 행 인덱스 0, 열 인덱스 3인 요소에 값 할당

    numArr[1][0] = 55; // 행 인덱스 1, 열 인덱스 0인 요소에 값 할당
    numArr[1][1] = 66; // 행 인덱스 1, 열 인덱스 1인 요소에 값 할당
    numArr[1][2] = 77; // 행 인덱스 1, 열 인덱스 2인 요소에 값 할당
    numArr[1][3] = 88; // 행 인덱스 1, 열 인덱스 3인 요소에 값 할당

    numArr[2][0] = 99;  // 행 인덱스 2, 열 인덱스 0인 요소에 값 할당
    numArr[2][1] = 110; // 행 인덱스 2, 열 인덱스 1인 요소에 값 할당
    numArr[2][2] = 121; // 행 인덱스 2, 열 인덱스 2인 요소에 값 할당
    numArr[2][3] = 132; // 행 인덱스 2, 열 인덱스 3인 요소에 값 할당

    printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
    printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
    printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 3인 요소 출력

    return 0;
}

// 11
// 77
// 99
// 132


  • 2차원 배열의 요소를 출력할 때와 마찬가지로 []에 인덱스를 지정한 뒤 값을 할당하면 된다.


  • 2차원 배열에서 범위를 벗어난 인덱스에 접근하면 어떻게 되는지 확인해 보자.


#include <stdio.h>

int main()
{
    int numArr[3][4];

    numArr[0][0] = 11; // 행 인덱스 0, 열 인덱스 0인 요소에 값 할당
    numArr[0][1] = 22; // 행 인덱스 0, 열 인덱스 1인 요소에 값 할당
    numArr[0][2] = 33; // 행 인덱스 0, 열 인덱스 2인 요소에 값 할당
    numArr[0][3] = 44; // 행 인덱스 0, 열 인덱스 3인 요소에 값 할당

    numArr[1][0] = 55; // 행 인덱스 1, 열 인덱스 0인 요소에 값 할당
    numArr[1][1] = 66; // 행 인덱스 1, 열 인덱스 1인 요소에 값 할당
    numArr[1][2] = 77; // 행 인덱스 1, 열 인덱스 2인 요소에 값 할당
    numArr[1][3] = 88; // 행 인덱스 1, 열 인덱스 3인 요소에 값 할당

    numArr[2][0] = 99;  // 행 인덱스 2, 열 인덱스 0인 요소에 값 할당
    numArr[2][1] = 110; // 행 인덱스 2, 열 인덱스 1인 요소에 값 할당
    numArr[2][2] = 121; // 행 인덱스 2, 열 인덱스 2인 요소에 값 할당
    numArr[2][3] = 132; // 행 인덱스 2, 열 인덱스 3인 요소에 값 할당

    printf("%d\n", numArr[-1][-1]); // 음수이므로 잘못된 인덱스
    printf("%d\n", numArr[0][4]);   // 열 인덱스가 배열의 범위를 벗어남
    printf("%d\n", numArr[4][0]);   // 행 인덱스가 배열의 범위를 벗어남
    printf("%d\n", numArr[5][5]);   // 행, 열 인덱스 모두 배열의 범위를 벗어남

    return 0;
}

// -858993460 (쓰레기 값)
// 55         (원하지 않는 요소 [1][0]에 접근)
// 4687800    (쓰레기 값)
// 2359296    (쓰레기 값)


  • 2차원 배열의 요소에 접근할 때 인덱스로 음수를 지정하거나, 배열의 크기를 벗어난 인덱스를 지정해도 컴파일 에러가 발생하지 않는다.
  • 하지만 실행을 해보면 쓰레기 값이 출력된다.
  • 즉, 배열의 범위를 벗어난 인덱스에 접근하면 배열이 아닌 다른 메모리 공간에 접근하게 된다.
  • 특히 2차원 배열은 값이 일렬로 쭉 늘어서 있으므로 numArr[0][4]와 같이 열 인덱스가 범위를 벗어나도록 지정하면 그다음 행 인덱스 요소인 numArr[1][0]에 접근하게 된다.


6. 2차원 배열의 크기 구하기

  • 2차원 배열을 선언한 뒤 배열의 행, 열 크기를 늘려야 할 경우 관련된 반복문의 조건식도 함께 수정해야 하는데 빠뜨리고 넘어갈 수가 있다.
  • 따라서 2차원 배열의 행, 열 크기를 구해놓고 반복문에 사용하면 실수를 방지할 수 있다.


  • 2차원 배열이 차지하는 전체 공간과 행, 열 요소의 개수는 sizeof 연산자로 구할 수 있다.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

    printf("%d\n", sizeof(numArr)); // 4바이트 크기의 요소가 12(4*3)개이므로 48

    int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
                                               // 행 한 줄의 크기를 요소의 크기로 나눠줌

    int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
                                                  // 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌

    printf("%d\n", col);
    printf("%d\n", row);

    return 0;
}

// 48
// 4
// 3


  • sizeof로 2차원 배열의 크기를 구해 보면 배열이 차지하는 전체 공간이 출력된다.


printf("%d\n", sizeof(numArr)); // 4바이트 크기의 요소가 12(4*3)개이므로 48


  • 열의 요소 개수를 구하려면 sizeof(numArr[0])와 같이 행 한 줄의 크기를 구한 뒤 요소의 크기로 나누면 된다.


int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
                                           // 행 한 줄의 크기를 요소의 크기로 나눠줌


  • 행의 요소 개수는 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠주면 된다.


int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
                                              // 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌


7. 반복문으로 2차원 배열의 요소를 모두 출력하기

  • 반복문을 사용하여 2차원 배열의 요소를 모두 출력해 보자.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

    int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
                                               // 행 한 줄의 크기를 요소의 크기로 나눠줌

    int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
                                                  // 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌

    for (int i = 0; i < row; i++) // 2차원 배열의 행 크기만큼 반복
    {
        for (int j = 0; j < col; j++) // 2차원 배열의 열 크기만큼 반복
        {
            printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
        }

        printf("\n"); // 열 요소를 출력한 뒤 다음 줄로 넘어감
    }

    return 0;
}

// 11 22 33 44
// 55 66 77 88
// 99 110 121 132


  • 먼저 배열의 행 크기와 열 크기를 구해 준다.
  • 그리고 for 반복문으로 행부터 반복한 뒤 열를 반복하면서 2차원 배열의 요소를 출력한다.


for (int i = 0; i < row; i++) // 2차원 배열의 행 크기만큼 반복
{
    for (int j = 0; j < col; j++) // 2차원 배열의 열 크기만큼 반복
    {


  • 반복문의 변수 ij는 변화식을 통해 1씩 증가하므로 2차원 배열의 행 인덱스에는 i, 열 인덱스에는 j를 넣으면 배열의 요소를 순서대로 접근할 수 있다.


printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정


  • 다음과 같이 역순으로도 출력할 수 있다.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

    int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
                                               // 행 한 줄의 크기를 요소의 크기로 나눠줌

    int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
                                                  // 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌

    for (int i = row -1 ; i >= 0; i--) // 행 크기 - 1부터 역순으로 반복
    {
        for (int j = col - 1; j >= 0; j--) // 열 크기 - 1부터 역순으로 반복
        {
            printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
        }

        printf("\n"); // 열 요소를 출력한 뒤 다음 줄로 넘어감
    }

    return 0;
}

// 132 121 110 99
// 88 77 66 55
// 44 33 22 11


  • 반복문의 초깃값에 배열의 행 크기와 열 크기를 바로 넣어버리면 처음부터 배열의 인덱스를 벗어난 상태가 된다.
  • 즉, 배열의 인덱스는 0부터 시작하므로 마지막 요소의 인덱스는 요소의 개수에서 1을 빼준다.
  • 그리고 0까지 반복할 수 있도록 조건식을 i >= 0과 같이 지정하면 된다.


for (int i = row -1 ; i >= 0; i--) // 행 크기 - 1부터 역순으로 반복
{
    for (int j = col - 1; j >= 0; j--) // 열 크기 - 1부터 역순으로 반복
    {


8. 2차원 배열을 포인터에 넣기

  • 2차원 배열을 포인터에 담으려면 다음과 같이 특별한 방법이 필요하다.


자료형 (*포인터이름)[열크기];


  • 즉, 포인터를 선언할 때 *과 포인터 이름을 ()(괄호)로 묶어준 뒤 []에 열 크기를 지정한다.


int (*numPtr)[4];


  • 위의 코드를 풀어서 설명하면 열 크기가 4인 배열을 가리키는 포인터라는 뜻이다.


003


int *numPtr[4]

  • int (*numPtr)[4]에서()를 뺀 int *numPtr[4]int 타입 포인터 4개를 담을 수 있는 배열이라는 뜻이다.
  • 즉, ()가 있으면 배열을 가리키는 배열 포인터, ()가 없으면 포인터를 여러 개 담는 포인터 배열이다.


int num1, num2, num3, num4;
int *numPtr[4] = {&num1, &num2, &num3, &num4}; // int 타입 포인터를 4개 담는 배열


  • 이제 2차원 배열을 포인터에 할당해서 사용해 보자.


#include <stdio.h>

int main()
{
    int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

    int(*numPtr)[4] = numArr;

    printf("%p\n", *numPtr); // 2차원 배열 포인터를 역참조하면 행 첫 번째의 주소가 나옴
                             // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%p\n", *numArr); // 2차원 배열을 역참조하면 행 첫 번째의 주소가 나옴
                             // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%d\n", numPtr[2][1]); // 2차원 배열 포인터는 인덱스로 접근할 수 있음

    printf("%d\n", sizeof(numArr)); // sizeof로 2차원 배열의 크기를 구하면
                                    // 배열이 메모리에 차지하는 공간이 출력됨

    printf("%d\n", sizeof(numPtr)); // sizeof로 2차원 배열 포인터의 크기를 구하면
                                    // 포인터의 크기가 출력됨

    return 0;
}

// 0x002bfe5c
// 0x002bfe5c
// 110
// 48
// 4


  • int (*numPtr)[4] = numArr;와 같이 2차원 배열을 포인터에 바로 할당할 수 있다.
  • 단, 자료형과 열 크기가 일치해야 한다.


  • 2차원 배열을 포인터에 할당한 뒤 포인터를 역참조해 보면 배열의 행 첫 번째 주솟값이 나온다.
  • 즉, 배열이 시작하는 주소이다.
  • 마찬가지로 2차원 배열 자체도 역참조해 보면 배열의 행 첫 번째 주솟값이 나온다.


printf("%p\n", *numPtr); // 2차원 배열 포인터를 역참조하면 행 첫 번째의 주소가 나옴
                         // 컴퓨터마다, 실행할 때마다 달라짐

printf("%p\n", *numArr); // 2차원 배열을 역참조하면 행 첫 번째의 주소가 나옴
                         // 컴퓨터마다, 실행할 때마다 달라짐


  • 2차원 배열 포인터는 []를 두 번 사용하여 배열의 요소에 접근할 수 있다.


printf("%d\n", numPtr[2][1]); // 2차원 배열 포인터는 인덱스로 접근할 수 있음


  • 배열과 포인터가 다른 점은 sizeof로 크기를 계산했을 때이다.
  • sizeof로 배열의 크기를 구해 보면 배열이 메모리에 차지하는 공간이 출력되지만 sizeof로 배열의 주소가 들어있는 포인터의 크기를 구해 보면 그냥 포인터의 크기만 나온다.


3차원 배열

  • 3차원 배열은 다음과 같이 높이, 행, 열 형태로 이루어져 있다.


004


  • 3차원 배열은 []에 높이, 행 크기, 열 크기를 지정하여 선언한다.
  • 값을 초기화할 때는 면 단위로 {}를 묶어주면 편리하다.


자료형 배열이름[높이][행크기][열크기];
자료형 배열이름[높이][행크기][열크기] = {
    {
        {, , },
        {, , }
    },
    {
        {, , },
        {, , }
    }
}


  • 다음은 3차원 배열 예제이다.


int numArr[2][3][4] = {
        {{11, 22, 33, 44},
         {55, 66, 77, 88},
         {99, 110, 121, 132}},
        {{111, 122, 133, 144},
         {155, 166, 177, 188},
         {199, 1110, 1121, 1132}}};


  • 3차원 배열에 접근하려면 []를 세 번 사용하여 높이, 행, 열 인덱스를 지정해 주면 된다.


배열[높이인덱스][행인덱스][열인덱스];
배열[높이인덱스][행인덱스][열인덱스] = ;
printf("%d\n",numArr[0][2][1]); // 110
numArr[1][1][2] = 0;            // 요소에 값 저장


  • 3차원 배열의 높이, 행, 열을 구하는 방법은 다음과 같다.


int depth = sizeof(numArr) / sizeof(numArr[0]); // 3차원 배열이 차지하는 전체 공간을 면의 크기로 나눠줌

int row = sizeof(numArr[0]) / sizeof(numArr[0][0]); // 한 면의 크기를 행 한 줄의 크기로 나눠줌

int column = sizeof(numArr[0][0]) / sizeof(int); // 행 한 줄의 크기를 요소의 크기로 나눠줌


  • 3차원 배열을 포인터에 할당하려면 행과 열로 구성된 면을 가리키는 포인터를 선언하면 된다.


자료형 (*포인터이름)[행크기][열크기]
int (*numPtr)[3][4] = numArr; // 행 크기 3, 열 크기 4인 면을 가리키는 포인터 선언

References