본문 바로가기
c언어

c언어 2차원 배열에 대하여 알아보기

by 개발자 L 2022. 12. 7.
반응형

c언어 2차원 배열에 대하여 알아보기

네 안녕하세요, 이번 포스팅에서는 2차원 배열에 대하여 알아보도록 하겠습니다.

차원 역시 프로그래밍에서 정말 많이 다룹니다.

보통 2차원과 3차원을 다루는데, 그중에서 3차원은 보통 3D 랜더링을 하는 디자인 관련 전공인 사람들이 일반적인 프로그래밍 언어들보다 훨씬 좋은 개발 툴, 이를테면 '3D 스튜디오', '오토 캐드' 등은 일반적인 디자인을 하는 분들이나 설계 관련 일을 하시는 분들이 많이 쓰시고,

'유니티', '언리얼 엔진' 등은 게임 개발을 하시는 분들이 많이 쓰십니다.

그러한 좋은 개발 도구들이 있어 그들을 이용하는 편이 훨씬 낫지만,

2차원 배열의 경우에는 프로그래밍 언어로 처리를 정말 많이 합니다.

'선형 대수학' 이라는 학문에서 배우는 '행렬'이 바로 여기에 속하기 때문입니다.

그리고 이 행렬 자체가 배열이 되는 경우가 있어서 더 그렇습니다.

그럼 지금부터 2차원 배열을 어떻게 다루는지 같이 보도록 하겠습니다.

 

1. 2차원 배열이란?

2차원 배열은 앞서 말씀드린 바와 같이 행과 열로 되어있습니다.

그래서 행렬이라 부르고요,

그 행과 열이 만나서 하나의 면을 이륩니다.

그래서 엑셀이라던지, 액세스나 sql 같은 곳에서 보는 테이블 행렬 역시 2차원 배열이고요,

우리가 보는 영상들, 정적 영상인 이미지, 그리고 동적 영상인 동영상들 역시 2차원 배열로 이루어져 있습니다.

실제로 영상의 경우는 BLOB(Binary Large Object)라고 하여 '이진 큰 객체'라고 부르는 자료형으로 데이터베이스를 저장합니다.

그리고 그걸 뜯어보면 0과 1로 이루어져 있는 이진 지도가 펼쳐져 있습니다.

c언어에서는 2차원 배열을 표현할 때 이렇게 표현을 합니다.

int A[3][5]; // 3 : 행의 개수, 5 : 열의 개수 - 3x5인 행렬

이렇게 쓰고요, 행 개수를 앞에 쓰고, 열 개수를 뒤에 씁니다.

그래서 위와 같이 쓰게 되면 3행 5열, 다시 말하면 3x5(3 by 5)인 행렬이 구성이 됩니다.

 

2. 2차원 배열에서의 요소 참조

일단 2차원 배열은 일반적인 배열처럼 1차원이 아니기 때문에 하나의 요소를 참조하기 위해서는 2개의 인덱스가 필요합니다.

다시 말하면 행에 해당하는 인덱스 하나, 열에 해당하는 인덱스 하나가 필요한 것이죠.

그래서 두 인덱스가 교차하는 지점이 바로 그 요소가 있는 위치가 됩니다.

예를 들어서 우리가 4행 5열로 구성이 된 행렬이 있다고 가정했을 때,

2번째 행의 3번째 열에 있는 수를 찾는다고 한다면 이렇게 찾을 수 있겠죠?

A[1][2];

여기서도 컴퓨터가 수를 세기 때문에 0부터 인덱스가 시작을 합니다.

그래서 이렇게 표기를 해야 원하는 위치에 있는 데이터에 접근이 가능합니다.

그러면 이들을 활용해서 행렬에 난수를 발생시키는 코드를 한 번 작성을 해보도록 하겠습니다.

#include <stdio.h>
#include <stdlib.h>

#define ROWS 3
#define COLS 5

int main()
{
    int i, j, A[ROWS][COLS];

    for (i = 0; i < ROWS; i++)
    {
        for(j = 0; j < COLS; j++)
        {
            A[i][j] = rand() % 100;
        }
    }

    for(i = 0; i < ROWS; i++)
    {
        for(j = 0; j < COLS; j++)
        {
            printf("%d", A[i][j]);
        }

        printf("\n");
    }

    return 0;

}

이렇게 작성을 해봤습니다.

배열에서 난수를 일으키는 것도 일반 자료형에서 난수를 발생시키는 것과 똑같습니다.

그럼 바로 결과를 보도록 하겠습니다.

41 67 34 0 69
24 78 58 62 64
54 58 1 27 61

이런 식으로 랜덤한 수가 나열이 됩니다.

반응형

 

3. 2차원 배열의 초기화

2차원 배열도 1차원 배열을 초기화하는 것과 마찬가지로 중괄호({})를 이용하여 초기화합니다.

다만, 행과 열이 존재하는 행렬이기 때문에 행과 열을 잘 맞춰서 작성해야 합니다.

이렇게 말이죠.

int A[3][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}
};

이게 정석적인 방법입니다.

그러면 이렇게 쓰면 어떻게 될까요?

int A[][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}
};

이렇게 행이 정해져 있지 않은데 초기값들이 다 주어져 있다면 컴파일러는 알아서 행의 크기를 조정합니다.

초기값이 주어진 행렬의 크기에 따라서 굳이 행렬의 크기를 설정을 하지 않았더라도 알아서 주어진다는 것입니다.

그리고 이런 경우도 있습니다.

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

이렇게 행렬의 크기보다 초기값이 더 적게 주어지는 경우도 있겠죠?
이럴 경우에는 행렬의 크기에 해당하는 나머지 요소들의 초기값은 모두 0으로 지정이 됩니다.

하지만 초기값이 전혀 지정이 되어있지 않다면 일반 배열과 마찬가지로 쓰레기 값이 들어가서 코드에 하자가 생길 수 있으니, 되도록이면 초기값을 설정을 해주는 것이 좋습니다.

이어서 이를 활용한 예제를 풀어볼 건데요.

가장 대표적인 예제가 바로 학생들의 성적을 출력하는 프로그램입니다.

그럼 바로 코드를 작성해보도록 하겠습니다.

#include <stdio.h>

#define ROWS 3
#define COLS 5

int main()
{
    int A[ROWS][COLS] ={
        {87, 95, 67, 99, 4},
        {49, 78, 32, 90, 2},
        {67, 98, 13, 65, 0}
    };

    for(int i = 0; i < ROWS; i++)
    {
        double final_scores = A[i][0] * 0.3 + A[i][1] * 0.4 + A[i][2] * 0.2 + A[i][3] * 0.1 - A[i][4];
        printf("학생 #%i의 최종 성적은 %0.2f 입니다.\n", i + 1, final_scores);
    }

    return 0;
}

이렇게 작성을 했습니다.

그리고 학생들의 성적은 이 표를 따랐습니다.

학번 중간고사(30%) 기말고사(30%) 과제(20%) 수시평가(10%) 결석횟수(감점)
1 87 95 67 99 4
2 49 78 32 90 2
3 67 98 13 65 0

그래서 제일 마지막 숫자들은 빼줘야 합니다.

그러면 결과를 바로 보도록 하겠습니다.

학생 #1의 최종 성적은 83.40 입니다.
학생 #2의 최종 성적은 59.30 입니다.
학생 #3의 최종 성적은 68.40 입니다.

결과도 문제없이 잘 나온 것을 볼 수가 있습니다.

그리고 이와 관련된 예제 중 행렬의 합을 구하는 방법에 대한 예제도 있습니다.

행렬은 자연과학에서 정말 많이 쓰이고, 개발자라면 선형 대수학에 대하여 어느 정도의 지식을 가지고 있어야 하는데,

그 이유는 배열이 바로 선형 대수학의 일부이기 때문이고,

배열을 다룬다는 것은 차원을 다루는 것과 같기 때문에 더 그렇습니다.

그러면 바로 코드를 작성을 해보도록 하겠습니다.

#include <stdio.h>

#define ROWS 3
#define COLS 3

int main()
{
    int A[ROWS][COLS] = 
    {
        {2, 3, 0},
        {8, 9 , 1},
        {7, 0 , 5}
    };

    int B[ROWS][COLS] = 
    {
        {1, 0, 0},
        {1, 0 ,0},
        {1, 0 ,0}
    };

    int C[ROWS][COLS];
    int r, c;

    for(r = 0; r < ROWS; r++)
    {
        for(c = 0; c < COLS; c++)
        {
            C[r][c] = A[r][c] + B[r][c];
        }
    }

    for(r = 0; r < ROWS; r++)
    {
        for(c = 0; c < COLS; c++)
        {
            printf("%d", C[r][c]);
        }

        printf("\n");
    }

    return 0;
}

이렇게 행렬의 합을 구해서 출력을 하는 코드를 작성했습니다.

코드가 길기는 하지만, 그렇게 어려운 코드는 아닙니다.

그럼 결과를 한 번 보도록 하겠습니다.

3 3 0
9 9 1
8 0 5

결과가 잘 나온 것을 확인을 할 수 있습니다.

 

4. 2차원 배열을 함수로 전달하기

2차원 배열 역시 함수로 전달을 할 수 있습니다.

우리가 사용자 지정 함수를 선언하여 인수들을 전달했었죠?

그것과 똑같이 사용자 지정 함수를 만들어서 쓸 수가 있습니다.

그럼 바로 코드를 작성해보도록 하겠습니다.

#include <stdio.h>

#define YEARS 3
#define PRODUCTS 5

int sum(int scores[YEARS][PRODUCTS]);

int main()
{
    int sales[YEARS][PRODUCTS] = 
    {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    int total_sale;

    total_sale = sum(sales);

    printf("총 매출은 %d 입니다.\n", total_sale);

    return 0;
}

int sum(int scores[YEARS][PRODUCTS])
{
    int y, p;
    int total = 0;

    for(y = 0; y < YEARS; y++)
    {
        for(p = 0; p < PRODUCTS; p++)
        {
            total += scores[y][p];
        }
    }

    return total;
}

이렇게 작성을 했습니다.

매출의 합을 구하는 것이기 때문에 sum()이라는 함수를 하나 만들어서 for문을 이용하여 매출액을 누적을 시켜줬습니다.

그럼 결과를 보도록 하겠습니다.

총 매출은 45 입니다.

결과도 잘 나온 것을 볼 수가 있습니다.

 

4 - 1. 함수로 2차원 배열을 받을 때 주의사항

함수로 2차원 배열을 받을 때 주의사항이 있습니다.

2차원 배열을 받는 것 역시 일반 배열을 함수의 인자로 받는 것과 동일한 구조를 가지고 있지만,

형렬의 크기를 잘 맞춰야 합니다.

행의 경우는 앞에서 보았듯이 굳이 정하지 않았더라도 알아서 컴파일러가 정해주기 때문에 상관이 없지만,

열의 경우는 조금이라도 설정한 범위보다 많아지면 쓰레기 값이 들어오면서 값을 파괴해버리기 때문에 주의를 해야 합니다.

 

여기까지 2차원 배열에 대하여 알아보았는데요,

다음 포스팅에서는 지금까지 배운 것들을 이용하여 여러 가지 문제들을 풀어보는 시간을 가져보도록 하겠습니다.

긴 글 읽어주신 독자분들께 진심으로 감사드립니다 ~

반응형

댓글