WinCNT

C 언어 - 13. 다차원 배열과 포인터 배열 본문

Study/C

C 언어 - 13. 다차원 배열과 포인터 배열

WinCNT_SSS 2021. 9. 8. 00:45

2차원 배열의 필요성

  1. 행렬 데이터를 표현할 때
  2. 그래프 알고리즘을 처리할 때
  3. 다수의 실생활 데이터를 처리할 때
    등등

2차원 배열의 특징

  • 2차원 배열은 표(Table) 구조와 흡사하다
  • C언어에서 2차원 배열은 []를 두 번 연속해서 선언한다
  • //자료형 배열 이름[행][렬] = { {값, 값, 값, ...}, {값, 값, 값, ... } }
    int a[10][10];
  • 1차원 배열과 마찬가지로 0인덱스부터 시작한다
    ※a[0][0], ... a[n][n]은 (n+1) x (n+1) 행렬
  • 행과 열을 사용한다는 특성으로 2중 FOR문과 함께 사용되는 경우가 많다
    #include<stdio.h>
    
    //행 ⇒ 열의 순서
    int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
    
    int main(void)
    {
        int i, j;
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                printf("%d ", a[i][j]);
            }
            printf("\n");
        }
    }​

 


다차원 배열

  • 2차원 배열 이상의 다차원 배열 또한 사용할 수 있다
  • 단, 컴퓨터는 기본적으로 화면에 2차원 배열의 형태만 출력할 수 있다
    (내부적인 처리는 다차원으로 동작함)
    #include<stdio.h>
    
    //3차원 행렬
    int a[2][3][3] =
        {
            { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} },
            { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }
        };
    
    int main(void)
    {
        int i, j, k;
        for (i = 0; i < 2; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    printf("%d ", a[i][j][k]);
                }
                printf("\n");
            }
            printf("\n");
        }
    }​

포인터 배열의 구조 분석

  • 배열은 포인터와 동일한 방식으로 동작한다
  • 배열의 이름배열의 원소의 첫 번째 주소이다
        int c[5] = { 1, 2, 3, 4, 5 };
        int *d = c;
        printf("%d\n", d[2]); //3
    
        //배열의 이름은 배열의 원소의 첫 번째 주소이기 때문에 위와 동일하게 작동함
        *d = &c[0];
        printf("%d\n", d[2]); //3​
  • 유일한 차이점포인터는 변수이며, 배열의 이름은 상수인 것이라 할 수 있다
    즉, 배열에 포인터 변수를 대입이 불가능하지만, 포인터는 배열처럼 사용 가능하다
    #include<stdio.h>
    
    int main(void)
    {
        int a = 10;
        int b[10];
    
        //Error) 식이 수정할 수 있는 lvalue여야 합니다.
        //상수에 데이터를 대입할 때 주로 발생할 수 있는 오류 문구
        //b = &a;
    
        int c[5] = { 1, 2, 3, 4, 5 };
        int *d = c; //포인터 변수에 배열은 대입 가능
    
        printf("%d\n", d[2]); //3
    
        system("pause");
        return 0;
    }​
  • 포인터는 연산이 가능하며, 연산을 통해 자료형의 크기만큼 이동한다
    예를 들어, 정수(int)형 포인터인 경우 4Bytes씩 이동한다
    #include<stdio.h>
    
    int main(void)
    {
        int a[5] = { 1, 2, 3, 4, 5 };
        int i;
        for (i = 0; i < 5; i++)
        {
            //주소값이 4Bytes씩 증가(배열 a의 마지막 원소의 주소값은 첫번째 원소의 주소값 + 16)
            //printf("%d ", (a + i));
            printf("주소값 : %d, 원소 값 : %d\n", (a + i), *(a + i));
            //printf("주소값 : %d, 원소 값 : %d\n", (a + i), a[i])와 동일
        }
        system("pause");
        return 0;
    }

2차원 배열과 포인터

  • 2차원 배열1차원 배열의 집합이다
    여기서 1차원 배열은 행이고, 그 수를 열이라 생각하면 이해하기 편하다
  • 2차원 배열은 메모리 상, '열'을 '행'번 나열한 형태로 할당된다
    ex) int[2][3] a의 경우: a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2]의 순서로 메모리가 할당된다
  • 2차원 배열에서는 첫번째 주소값해당 행을 대표하는 이름이다
    ex) int[2][3] a의 경우: a[0][0], a[1][0]의 주소가 이름이다
        즉, a[0]는 a[0][0]의 주소, a[1]은a[1][0]의 주소와 같고, a는 a[0]와 같다
  • 정리하면 2차원 배열에서 a = a[0] = &a[0][0]가 성립된다.
    단 의미하는 바는 다르기에 포인트 연산을 하면 차이가 발생한다
    • a + 1 = a[1] = &a[1][0]
      a는 2차원 배열의 대표이자 행들의 대표이기 때문에 a + 1은 다음행의 대표(주소값)을 나타낸다
    • a[0] + 1 = &a[0][1]
      a[0]은 첫번째 행의 주소를 나타내므로, a[0] + 1은 그 다음 원소의 주소값을 나타낸다
    • &a[0][0] + 1 = &a[0][1]
      &a[0][0]는 2차원 배열의 첫번째 원소의 주소값이므로 &a[0][0] + 1는 그 다음 원소의 주소값을 나타낸다
  • 또한 2차원 배열에서 *a = a[0] = &a[0][0]이며, **a = a[0][0]가 성립한다
    • *a ≠ &a[0][0]인 이유
      일반적으로 간접참조연산자(*)는 해당 포인터 변수의 주소를 참조하여 그 값에 접근 가능하다.
      하지만 a는 행들의 집합이며, *a로 해당 주소를 참조하는 것은 원소의 값이 아니라,
      행들의 집합의 대표, 즉 첫번째 행의 주소이자 이름(a[0] 혹은 &a[0][0])에 접근한다는 뜻이 된다.
    • **a = a[0][0]인 이유
      *a가 행들의 집합의 대표, 즉 첫번째 행의 주소이자 이름(a[0] 혹은 &a[0][0])에 접근한다는 뜻이므로
      **a는 첫번째 행의 주소가 가지는 값, 즉 a[0][0]을 뜻하게 된다
      ※주의할 것은 **a라 표기하였다고 해서 이것이 이중 포인트를 뜻하는 것이 아니다라는 점이다

#include<stdio.h>

int main(void)
{
    int a[2][5] = { { 1, 2, 3, 4, 5 },
                    { 6, 7, 8, 9, 10} };
   
    int(*p)[5] = a[1]; //특정한 행을 가리키는 포인터(이중 포인터)
    int i;
    for (i = 0; i < 5; i++)
    {
        printf("%d ", p[0][i]); //6 7 8 9 10
    }
    system("pause");
    return 0;
}

 

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

C 언어 - 15. 함수 포인터  (0) 2021.09.27
C 언어 - 14. 동적 메모리 할당  (0) 2021.09.09
C 언어 - 12. 컴퓨터가 변수를 처리하는 방법  (0) 2021.09.06
C 언어 - 11. 문자열  (0) 2021.09.05
C 언어 - 10. 문자  (0) 2021.08.05