피노리코 2015. 1. 16. 03:24

C언어 할때 배열은 했지만 중요하니까 한번더!

배열은 연속된 메모리 공간을 차지하는 같은 데이터형들의 집합

정적인 데이터이기때문에 컴파일러는 이 정해진 크기만큼 공간만을 확보한다

배열의 선언방법은

데이터형 배열명[배열의 크기];

예를들어보자

int array[10];

integer형으로 array라는 배열을 10의 크기로 정의 하였다

이것은 두가지 의미인데 첫번째는 array라는 배열명은 10개의 정수가 저장된 공간의 선두번지를

둘째로는 sizeof(array)와 같이 하면 배열의 크기 즉 int형이 몇개나 저장될 수 있는가에 10이라는 값을 나타낼 뿐이다.

그 이외의 배열에 대한 조작은 모두 포인터의 조작으로 대치된다.

중요한점은 배열의 제일 첫 요소는 array[1]이 아니라 array[0]이며 마지막 요소는 array[10]이 아니라 array[9]이다 위에서의 10은 정말로 배열의 크기일 뿐이다.

컴파일러는 위의 정의에 의해서 int형 데이터가 10개로 저장될 공간을 정적 데이터 영역에 확보해두고 실제로 확보되는 배열의 크기는 int형 크기에 2에 10을 곱한 값, 즉 20바이트가 된다.

중요한것은 배열은 포인터에 대한 처리로 대치되기 때문에 array는 배열에 확보된 메모리 공간의 선두번지를 의미한다 그래서 array[4]는 *(array+4)와 완전히 동일하다 배열의 이름 즉 메모리 공간의 선두번지는 포인터와 동일하게 취급해도 되지만 배열의 이름은 포인터가 아니라는 것이다.포인터는 주소를 가리키는 변수이고 배열이름은 그자체를 가리키는 상수이다. 그래서 배열의 이름에 따로 공간을 할당하지는 않는다. 그래서 array를 포인터로 취급해서 그 값을 변경하려 하면 에러가 발생한다.

1차원 배열(one dimensional array)

배열에서 차수는 배열 요소를 지정하는데 몇개의 첨자가 배열의 크기를 지정하는것이 있는가에 의해서 지정되는데 1차원배열은 하나만 있으면 된다.

배열은 실행 후에 그값을 결정할 수있지만 정의하면서 초기값을 부여할 수 있다.

예를들어

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

;을 빼먹지 말자

이와같은 배열은 다음과 같이 메모리에 배치된다.

               

                    array가 가르키는곳

?? 

?? 


1차원 배열은 위와 같아서 포인터의 연산이 제대로 먹히는 것이다.

다차원 배열(Multi dimensional array)

다차원 배열은 배열을 선언할때 원하는 차원만큼 첨자?를 지정하면 된다 보통 2차원을 많이 쓰고 3차원은 어쩌다가 가끔? 그이상은 잘 쓰지 않는다고 한다. 하지만 다차원 배열이라고 해도 그 근본은 2차원 배열과 같기 때문에 2차원 배열만 설명하겠다

2차원 배열 arra2를 선언하고 초기화를 해보자

int arra2[3][3] = 

{{1,2,3},

 {4,5,6},

 {7,8,9}};

2차원 배열의 초기화에는 여러가지 방법이 있지만 위의 방법이 가장 좋다.

배열요소를 지정할때 위의 수를 행렬이라고 생각하면 된다(고등학교때 수학을 열심히 해야하는 이유!)

         0열  1열  2열

0행     1,     2,    3  

1행     4,     5,    6 

2행     7,     8,    9  

그래서 int array2[2][1]은 2행의 1열이니 8이다

          int array2[0][1]은? 2다

array2는 2차원 배열이지만 메모리의 구조가 선형적 구조라서 메모리저장될때는 1차원 배열처럼 저장된다.

               array2가 가리키는곳(array2는 정수 3개의 배열을 가리키는 포인터라고 생각 하면 된다)

?? 

 1

 3

4 

7 

?? 

                                        array2+1                                      array2+2

배열은 포인터로 설명이 가능하지만 2차원 배열인 경우 약간 복잡하다. 1차원 배열에서는 배열명이 배열공간의 선두를 가리키는 주소라고 했다. 그래서 array는 int형을 가리키는 주소로 생각하면 되었다.

하지만 array2는 3개의 int형의 공간을 가리키는 조소이다 마찬가지로 array2+1은 array2다음의 3개의 int형의 공간을 가리킨다.

C의 문법은 재귀적이라는 것을 생각하면 2차원 배열이 이런 복잡한 구조를 갖는다는 것이 이해가 갈것이다

1차원 배열을 함수의 인자로 넘기는 방법

1차원 배열을 함수의 인자로 넘기는 방법은 간단하다. 포인터로 표현하는 방법과 배열로 표현하는 방법이 있지만 이 둘은 같다.

다음은 배열을 진자로 받아서 배열요소들의 평균을 구하는 프로그램이다.

int average(int a[],int n)

{

    int sum =0;

    int i;

    for (i=0;i<n;i++) {

        sum+=a[i];

    }

    return (sum/n);

}

C에서 배열의 크기는 메모리 공간을 할당할 때만 필요하지 실행시에는 배열의 크기에 대해서 컴파일러가 신경쓰지 않는다 그래서 함수가 배열을 인지로 받을 때 그 배열이 몇개의 요소를 가지는지는 전혀 알 방법이 없다. 이런이유로 average()함수는 n이라는 배열의 크기를 인자로 따로 받는다. 그리고 인자로 받는 배열a에도 []로 배열표시만 했지 크기를 명시하지 않았다(해도 컴파일러가 무시한다)

물론 배열자체에 끝을 나타냄이 있으면 배열의 크기를 넘길 필요가 없다. 가장 전형적인 예가 C에서 문자열을 다루는 방식이다. C에서 문자열은 char형의 배열로 구현하는데 특별히 문자열의 크기에 신경을 쓰지 않음을 알고 있을 것이다. 배열을 읽어가다가 0이 읽어지면 배열의 끝임을 알게 되는 것이다. 이렇게 배열의 한계는 두가지가 있지만 선택은 본인 몫이다.

배열은 포인터와 동일한 표현이라고 했으므로 위의 average함수도 포인터의 표현으로 나타낼수 있을 것이다. 다음과 같이 함수의 헤더를 바꾸어도 상관없다.

int average(int *a,int n)

다음 코드는 1차원 배열을 함수의 인자로 넘기는 방법을 보여준다.

#include <stdio.h>

#define MAX 10

int average(int a[],int n)

{

    int sum =0;

    int i;

    for (i=0;i<n;i++) {

        sum+=a[i];

    }

    return (sum/n);

}

int main(int argc, const char * argv[]) {

    int array[MAX];

    int i;

    printf("\nInput %d integer -> ",MAX);

    for (i=0; i<MAX; i++) {

        scanf("%d",array+i);

    }

    printf("\nAverage of %d integer is %d",MAX,average(array, MAX));

    return 0;

}

2차원 배열을 함수의 인자로 넘기는 방법

2차원 배열을 함수 인자로 넘기는것은 주의해야 한다. C는 프로그램이 실행한 뒤에는 배열의 크기를 모른다고 하였기 때문에 1차원 배열에서는 함수의 인자로 배열을 넘길때 배열의 크기를 명시하지 않고 따로 배열의 크기르 정수로 넘겨주었다.

하지만 2차원 배열은 뭔가 그 원칙에 어긋나는 것 같다

2차원 배열을 사용하는 가장 빈번한 예는 행렬(Matrix)이다. 다음 input_matrix() 함수는 2x2 행렬을 키보드로 입력받는 함수이다

void input_matrix(int m[][2],int n)

{

    int i,j;

    printf("\n input %d by %d Matrix in row order ->",n,n);

    for (i=0;i<n; i++) {

        for (j=0; j<n; j++) {

            scanf("%d",&m[i][j]);

        }

    }

}

배열의 크기를 모른다고 했는데 위의 input_matrix 함수는 인자에 int m[][2]라고 쓰여있어 2라는 크기가 들어갔음을 알수있다.

m을 포인터라고 보았을때 int m[][2]의 표현은 m이 두개의 int형의 공간을 가리키는 포인터이다. 즉 int m[][2]의 표현은 배열의 크기를 나타낸것이 아니라 m이 어떤 형의 데이터르 가리키는 포인터 인지 나타내는 것이다. 즉 m이 두개의 int혀이 공간을 가리킨다는 것은 알려졌지만 두개의 int형의 공간이 몇개나 있는지는 모른다. 결국 배열의 크기는 모른다는 것이다.

input_matrix 함수는 포인터 표현으로 나타낼수 있다 아래처럼 바꾸어도 지장이 없다

void input_matrix(int *(m[2]),int n) 

포인터로 표현하니 의미가 더 명확하게 보인다. 2개의 int형 공간을 가리키는 포인터 m의 정체가 이제 확연하게 드러난다.

2차원 배열을 1차원 배열인것 처럼 사용할수도 있지만 그럴 필요까진 없을것 같다 굳이 하자면 할수 있지만...굳이 써보자면

void input_matrix(int *m,int n)

{

    int i,j;

    printf("\n input %d by %d Matrix in row order ->",n,n);

    for (i=0;i<n; i++) {

        for (j=0; j<n; j++) {

            scanf("%d",m+i*n*j);

        }

    }

}

함수 호출은 다음과 같다.

void main()

{

int mat[2][2];

input_matrix(&mat[0][0],2);

...

}

조금은 기형적입니다. 왠만하면 보이는 대로 2차원 배열을 다룹시다!

연습으로 2x2의 정방행렬을 두개 입력받아서 곱을 출력하는 프로그램을 작성해 보자.

두행렬 A,B의 곱 C에 대입하는 알고리즘을 풀어 써보자

1.for(i는 0부터 N-1까지 1씩 증가) --> i는 C의 행

2.for(j는 0부터 N-1까지 1씩 증가) --> j는 C의 열

3.C[i][j]를 0으로 초기화 -->누적을 위해서 초기화

4.for(k는 0부터 N-1까지 1씩 증가)

5.C[i][j]에 A[i][k]*B[k][j]를 더함

이 알고리즘을 코드로 구현해 보면

#include <stdio.h>

#define MAX 2

void input_matrix(int m[][MAX],int n) //배열을 키보드로 입력받음

{

    int i,j;

    

    printf("\n input %d by %d Matrix in row order ->",n,n);

    for (i=0;i<n; i++) {

        for (j=0; j<n; j++) {

            scanf("%d",&m[i][j]);

        }

    }

}

void print_matrix(int m[][MAX],int n)

{

    int i,j;

    

    printf("\n");

    for (i=0; i<n; i++) {

        for (j=0; j<n; j++) {

            printf("%-6d",m[i][j]);

        }

        printf("\n");

    }

}

void multiply_matrix(int m1[][MAX],int m2[][MAX],int m3[][MAX],int n)

{

    int i,j,k;

    

    for (i=0; i<n; i++) {

        for (j=0; j<n; j++) {

            m3[i][j] = 0;

            for (k=0; k<n; k++) {

                m3[i][j] += m1[i][j] * m2[k][j];

            }

        }

    }

}

int main(void)

{

    int mat1[MAX][MAX];

    int mat2[MAX][MAX];

    int mat3[MAX][MAX];

    

    input_matrix(mat1, MAX);

    input_matrix(mat2, MAX);

    

    multiply_matrix(mat1, mat2, mat3, MAX);

    

    printf("\n Answer : ");

    print_matrix(mat3, MAX);

    

}

이렇게 나타낼수 있다.

다차원 배열을 함수의 인자로 넘기는 방법

이 방법은 2차원 배열을 함수의 인자로 넘기는 방법의 연장선상에 있다. 즉 다차원 배열을 함수의 인자로 넘길 떄에는 2차원 배열과 마찬가지로 가장 큰 블록을 가리키는 최자측 첨자를 비워두고 나머지 첨자는 그 크기를 명시하는 것이다

예를들어 3*4*2 크기를 가지는 int형의 tri 배열을 예로 들어 보겠다.

int tri[3][4][2];

int func(int t[][4][2])

{    ...    

}

위와 같다.

그 이상도 마찬가지다