Taking baby-developer steps

13. 다차원 배열과 포인터 배열 - 2차원 배열(필요성, 초기화,모든 원소 출력하기) / 다차원 배열 /배열과 포인터의 구조 분석 본문

CS 지식/C언어_basic

13. 다차원 배열과 포인터 배열 - 2차원 배열(필요성, 초기화,모든 원소 출력하기) / 다차원 배열 /배열과 포인터의 구조 분석

Surin Lee 2021. 3. 26. 21:27

다차원 배열과 포인터 배열

다양한 차원의 배열을 표현하는 방법을 이해한다. 포인터를 이용해 2차원 배열을 다루는 방법을 학습한다.

 

2차원 배열

필요성

2차원 배열은 굉장히 많은 목적으로 사용된다. 행렬 데이터를 표현 할 때, 그래프 알고리즘을 처리할 때, 다수의 실생활 데이터를 처리 할 때 등인데, 흔히 우리가 보는 표 구조가 2차원 배열과 흡사하다.

 즉, 각각의 사용자에 대한 이름 정보가 있고, 어떠한 수치 데이터가 2차원 형태로 존재할 때, 2차원 배열로 모델링 하기 수월하다.

 

초기화

2차원 배열은 1차원 배열이 중첩되었다는 의매로, [](대괄호)를 두번 연속하여 쓴다.

자료형 배열이름[행][열] = {{값, 값, 값, ...}, {값, 값, 값, ...}, ...}

예를 들어, 10X10 의 행렬 같은 경우 다음과 같이 선언 할 수 있다.

int a[10][10];

2차원 배열 또한 기본 적으로 0 인덱스부터 시작한다.

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

2차원 배열은 주로 2중 For문과 함께 사용한다.

 ex) 2차원 배열의 모든 원소 출력하기

#include <stdio.h>

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

int main(void) {
    int i, j ;
    for (int i=0; i < 3; i++){
        for(int j = 0; j < 3; j++){
            printf("%d", a[i][j]);
        }    
        printf("\n");
    }
    system("pause");
    return 0;
}

->123

   456

   789

기본적으로, C언어 에서의 배열은 '행'우선으로 처리 되기 때문에, 위의 예제에서 i는 각각의 '행'에 접근하는 변수, 'j'는 각각의 '열'에 접근하는 변수로서 사용 되었다.

 

다차원 배열

2차원 이상의 다차원 배열 또한 사용할 수 있다. 다만 컴퓨터는 기본적으로 화면에 2차원 형태만 출력할 수 있으므로, 2차원 배열 형태로 출력 하되, 내부적으론 다차원 구조로서 동작한다.

ex) 3차원 배열의 모든 원소 출력하기 - 3중 For문으로 각각의 데이터에 접근할 수 있다.

#include <stdio.h>

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 (int i=0; i < 2; i++){
        for(int j = 0; j < 3; j++){
            for(int k= 0; k < 3; k++){
            printf("%d", a[i][j][k]);
            }
            printf("\n");
        }    
        printf("\n");
    }
    system("pause");
    return 0;
}

-결과 값(아래)-

123                                                                                                                                                 
456                                                                                                                                                 
789                                                                                                                                                 
                                                                                                                                                    
123                                                                                                                                                 
456                                                                                                                                                 
789  

 

포인터 배열의 구조 분석

 배열은 포인터와 동일한 방식으로 동작한다. 배열의 이름은 배열의 원소의 첫번째 주소가 된다. 유일한 차이점은, 포인터는 변수이며, 배열의 이름은 상수(배열의 이름은 바뀔 수 없음)이다.

 

다음의 소스 코드를 통해, 배열의 이름이 변수가 아닌 상수임을 확인할 수 있다.

#include <stdio.h>

int main(void) {
    int a = 10;
    int b[10];
    b = &a; // 오류 메세지 발생 : error: assignment to expression with array type
    system("pause");
    return 0;
}

'b'라는 배열의 이름은 수정 할 수 없는 '상수'이므로, 다른 주소 값을 넣을 수 없다. (+ 배열은 포인터로 사용할 수 없다.)

 

그러나 포인터를 배열로 사용하는 것은 가능하다.

#include <stdio.h>

int main(void) {
    int a[5] = {1,2,3,4,5};
    int *b = a;
    printf("%d",b[2]);
    system("pause");
    return 0;
}

-> 3

이게 가능한 이유는, 배열의 이름배열의 첫번째 원소의 주소이기 때문이다. (a == &a[0] ) 즉 위의 예제는 다음과 같다.

#include <stdio.h>

int main(void) {
    int a[5] = {1,2,3,4,5};
    int *b = &a[0];
    printf("%d",a[2]);
    system("pause");
    return 0;
}

 

포인터는 연산이 가능하며,  연산을 통해 자료형의 크기만큼 이동한다. 따라서, 정수(int)형 포인터는 4바이트씩 이동한다. 이는 배열의 Index에 접근하는 방식과 굉장히 유사하다.

#include <stdio.h>

int main(void) {
    int a[5] = {1,2,3,4,5};
    int i;
    for (i=0; i < 5; i++){
        printf("%d\n", a + i);
    }
    system("pause");
    return 0;
}

위의 소스코드의 결과 값으로, 각 원소가 저장된 메모리 주소를 출력 받을 수 있는데, 각 주소가 각 원소(int형)가 차지하는 메모리공간(4B) 만큼 차이 나는 것을 볼 수 있다.

617739840
617739844
617739848
617739852
617739856

위의 예제 코드에서 각 원소의 주소가 가리키는 "값"으로 출력 받으려면, printf()구문을 다음과 같이 변경하면 된다.

printf("%d\n", *(a + i));

혹은 배열의 index를 통해 접근하는 것도 위(*(a+i))와 완전히 동일하다.

printf("%d\n", a[i]);

 

+2차원 배열 또한 포인터로 처리할 수 있다. 이 경우 2중 포인터로 처리한다,

#include <stdio.h>

int main(void) {
    int a[2][4] = {{1,2,3,4}, {5,6,7,8}};
    int (*p)[4] = a[1];
    int i;
    for (i=0; i <4; i++){
        printf("%d",p[0][i]);
    }
    system("pause");
    return 0;
}
5678

위의 예제에서, 포인터 *p를 "4개의 열을 가지는 하나의 행"을 의미하는 포인터로서 선언하고, 2번째 행을 가리키도록 초기화했다. 따라서 for문을 통해 2번째 행의 모든 열을 출력했다.

 

요약

  1. 컴퓨터에서 2차원 및 그 이상의 배열을 표현할 수 있다.
  2. C언어의 배열은 내부적으로 포인터와 동일하므로 포인터 연산으로 배열을 대체할 수 있다.(배열의 index를 통한 접근과 같은 맥락으로 사용할 수 있다. 그러나, 배열은 포인터로서 사용할 수 없다.(배열의 이름은 상수이기 때문) ) 
Comments