pc관련/C언어2019. 3. 20. 21:36

배열은 C 프로그램 내에서 가끔 사용되는 데이터 저장 영역의 하나이아. 오늘은 다음과 같은 내용을 다룰 것이다.


·배열은 무엇인가?

·일차원 배열과 다차원 배열의 정의

·배열의 선언과 초기화


1. 배열이란 무엇인가?

: 배열(array)은 동일한 데이터형과 동일한 이름을 가지는 집단적인 데이터 저장 영역을 말한다. 배열의 각 저장 영역을 배열 요소(array element)라고 한다. 프로그램에서는 왜 배열을 사용해야 하는 것일까? 이것은 예제를 통해서 설명하도록 하겠다. 만약 1998년에 월별로 접수된 영수증을 사용하여 재정 상태를 관리한다면, 12개 서류철로 나누어 관리할 수도 있겠지만 12개의 부분으로 나누어진 하나의 서류철에서 관리하는 것이 더 나을 것이다.


이 예제를 컴퓨터 프로그래밍에 적용해보자. 재정 관리를 위한 프로그램을 작성한다고 가정하자. 프로그램은 12개의 독립된 변수와 합계를 저장하는 변수를 선언하여 월별 지출액을 관리할 수 있을 것이다. 이것은 월별 영수증을 보관하기 위한 12개의 독립된 서류철을 사용하는 것과 유사하다. 그러나 효율적인 프로그램이라면 월별 지출액을 저장하는 12개의 요소와 합계를 저장하기 위한 하나의 요소를 가지는 배열을 사용할 것이다. 이것은 하나의 서류철에서 월별 영수증을 모두 관리하는 것과 유사하다.


1.1 일차원 배열

: 일차원 배열(single-dimensional array)은 하나의 첨자만을 사용하는 배열이다. 첨자(subscript)는 배열의 이름 위에 있는 대괄호에서 사용되는 숫자이다. 이것은 개벽적인 배열 요소의 번호를 나타낸다. 재정 관리 프로그램에서 사용하기 위한 float형의 배열을 선언하기 위해서는 다음과 같은 문장을 작성할 수 있을 것이다.


  float expenses[12];


배열은 expenses라는 이름을 사용하고, 12개의 요소를 가진다. 12개의 각 요소는 개별적인 부동 소수형 변수와 동일하다. 배열에는 C의 모든 데이터형을 사용할 수 있다. C의 배열 요소는 항상 0에서부터 시작하므로 12개의 요소는 0부터 11까지의 번호를 사용할 것이다. 1월의 지출액은 expenses[0]에 저장되고, 2월의 지출액은 expenses[1]에 저장된다.


배열을 선언할 때 컴파일러는 전체 배열을 저장하기에 충분한 메모리 영역을 보존한다. 소스코드에서 배열이 선언되는 위치는 중요하다. 다른 변수에서와 마찬가지로, 배열이 선언되는 위치는 프로그램에서 배열을 사용하는 방법에 영향을 준다. 변수나 배열이 선언되는 위치가 프로그램에 미치는 영향은 낭중에 상세히 설명하고, 일단 main() 함수가 시작되기 전에 다른 변수 선언문과 함께 배열 선언문을 위치시키도록 하자.  배열의 요소는 배열이 아닌 동일한 형태의 변수를 사용할 수 있는 곳이면 프로그램 내에서 어디든지 사용할 수 있다. 배열의 각 요소는 배열의 이름과 대괄호 내에 포함된 요소의 첨자에 의해서 사용된다. 예를 들어, 다음 문장은 두 번째  배열 요소에 89.95의 값을 저장한다. 배열의 처 번째 요소는 expenses[1]이 아니라 expenses[0]이라는 것을 기억하자.


  expenses[1] = 89.95;


비슷하게, 다음의 문장은


  expenses[10] = expenses[11];


배열 오소 expenses[11]에 저장된 값을 배열 요소 expenses[10]에 할당한다. 배열의 요소를 지정할 때 배열의 첨자는 이런 예제에서 사용되었듯이 실제 상수{literal constant)이다. 그러나 프로그램에서는 C의 정수형 변수나 수식, 심지어 다른 배열 요소를 첨자로 사용할 수도 있다. 다음은 몇 가지 예이다.


  float expenses[100];

  int a[10];


  /* 그 밖의 프로그램 문장 */


  expenses[i] = 100;    /* i는 정수형 변수이다. */

  expenses[2 = 3] = 100;   /* expenses[5]와 동일하다. */

  expenses[a[2]] = 100;   / * a[]는 정수형 배열이다. */


마지막 줄에 대해서는 약간의 보충 설명이 필요하다. 예를 들어, a[]라는 이름의 정수형 배열이 있고 a[2]에는 8의 값이 저장되어 있다고 하자. 다음 문장은


  expenses[a[2]]


다음과 같은 내용이 될 것이다.


  expenses[8];


배열을 사용할 때에는 배열 요소의 개수를 기억하도록 하자. n개의 요소를 가지는 배열에서 사용할 수 있는 첨자는 0부터 n-1까지이다. 만약 첨자로 n을 사용하면 프로그램에서는 문제가 발생한다. C 컴파일러는 프로그램에서 범위를 벗어난 배열의 첨자가 사용되는지 확인하지 않는다. 프로그램은 정상적으로 컴파일되고 링크되지만, 범위를 벗어난 첨자의 사용은 잘못된 결과를 가져올 것이다. 가끔 프로그램에서는 배열이 1부터 n까지의 요소를 가지는 것처럼 다루기 원할 것이다. 예를 들어, 앞에서 설명한 예제의 경우에는 1월의 지출액을 expenses[1]에, 2월의 지출액을 expenses[2]에 저장하는 것이 더욱 자연스러울 것이다. 이렇게 하는 가장 간단한 방법은 필요한 것보다 하나 더 많은 요소를 가지는 배열을 선언하고, 첫 번째 요소인 0을 무시하는 것이다. 이때 다음과 같이 배열을 선언할 수 있다. 또한 관련 데이터, 예를 들어 연간 지출 합계를 요소 0에 저장할 수 있을 것이다.


  float expenses[13];


<리스트 8.1>에 있는 프로그램 EXPENSES.C는 배열의 사용 예를 보여준다. 이것은 실제로 사용되지 않는 간단한 프로그램이지만 배열의 사용 예를 보여주기에는 저당...


<리스트 8.1> EXPENSES.C는 배열의 사용 예를 보여준다.

 

1.2 다차원 배열
: 다차원 배열은 하나 이상의 첨자를 가진다. 이차원 배열(two-dimensional array)은 두 개의 첨자를 가지고 삼차원 배열(three-dimensional array)은 세 개의 첨자를 가진다. C에서 배열의 차원에는 아무런 제한이 없다. 그러나 이 장의 후반부에서 설명하겠지만 전체적인 배열의 크기에는 제한이 있다. 예를 들어, 보드 게임을 수행하는 프로그램을 작성한다고 가정하자. 보드는 8행 8열의 64개 요소를 가지고 격자 형태로 구성된다. 프로그램은 다음과 같이 이차원 배열의 형태로 보드를 정의할 수 있을 것이다.

  int checker[8][8];

결과적으로, 배열은 64개의 요소를 가지게 된다. 각각의 요소는 checker[0][0], checker[0][1] …, checker[7][7]이 된다. 다음은 이 차원 배열의 구조를 나타낸다

 

비슷하게, 3차원 배열은 입체로 생각할 수 있다. 4차원 이상의 배열은 아마도 상상하기 힘들 것이다. 배열은 몇 차원으로 정의하든지 관계없이 메모리에 순서대로 저장된다. 배열이 메모리에 저장되는 방법에 대한 상세한 내용은 낭중에 다루겠다.

 

2. 배열의 이름을 지정하고 선언하는 방법

: 배열의 이름을 지정할 때에는 앞서 공부한 "데이터 저장하기 : 변수와 상수"에서 설명했던 변수 이름에 대한 것과 같은 규칙이 적용된다. 배열의 이름은 독특해야 한다. 즉, 다른 배열이나 어떤 변수, 상수 등에서 사용된 이름을 배열에서 다시 사용할 수 없다. 짐작할 수 있듯이, 배열의 선언은 배열의 이름 다음에 요소의 수를 지정해주는 것을 제외하고는 일반적인 변수를 선언하는 것과 동일한 형식을 따른다. 배열은 선언할 때에는 앞의 예제에서 사용했듯이 실제 상수를 사용하거나 또는 #define 지시어로 생성된 기호 상수를 사용하여 요소의 수를 지정할 수 있다.


  #define MONTHS 12

  int array[MONTHS];


앞의 문장은 다음과 같은 뜻을 가진다.


  int array[12];


그러나 대부분의 컴파일러에서는 const키워드를 통해서 생성된 기호 상수를 사용하여 배열을 선언할 수 없다.


  const int MONTHS = 12;

  int array[MONTHS];  /* 사용할 수 없다 */


<리스트 8.2>의 GRADES.C는 1차원 배열의 사용 예를 보여주는 다른 하나의 프로그램이다. GRADES.C에서는 10개의 점수를 저장하는 배열이 사용된다.

 

2.1 배열의 초기화
: 배열을 처음 선언할 때에는 전체나 일부분을 초기화할 수 있다. 배열의 선언에서 등호와 함께 중괄호 내에 포함되며 쉼표로 구분되는 초기화 값의 목록을 입력하면 된다. 입력되는 값은 첫 번째 요소(0)부터 시작하여 배열의 각 요소에 할당한다. 예를 들어, 다음 문장은 array[0]에 100, array[1]에 200, array[2]에 300, array[3]에 400의 값을 저장한다.

  int array[4] = {100, 200, 300, 400};

배열의 크기를 지정하지 않으면 컴파일러는 단지 초기화 값을 저장하기에 충분히 큰 배열을 생성한다. 그래서 다음 문장은 이전의 배열 선언문과 동일한 결과를 나타낼 것이다.

  int array[] = {100, 200, 300, 400};

그러나 배열을 선언할 때에는 다음 문장에서처럼 필요한 초기값만을 입력할 수도 있다.

  int array[10] = {1, 2, 3}

배열의 요소를 분명하게 초기화하지 않는다면 프로그램이 실행될 때 배열에 어떤 값이 저장되어 있는지 알 수 없을 것이다. 또한, 배열의 요소의 수보다 많은 초기값을 입력하면 컴파일러는 에러를 발생할 것이다.

2.2 다차원 배열의 초기화
: 다차원 배열도 초기화할 수 있다. 주어진 초기값은 뒷 부분의 첨자가 먼저 증가하는 순서로 배열의 요소에 할당된다. 예를 들어, 다음 문장은

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

다음과 같은 뜻을 가진다.

  array[0][0] = 1
  array[0][1] = 2
   …
  array[3][1] = 11
  array[3][2] = 12

다차원 배열을 초기화할 때에는 초기값을 구분하기 위해서 추가적인 중괄호를 사용하고 여러 줄에 걸쳐서 표현하여 소스 코드를 더욱 이해하기 쉽게 만들 수 있다. 다음의 초기화 문장은 앞에서 사용한 것과 동일하다.

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

초기값이 쉼표에 의해 구분되어야 한다는 것을 기억하자. 초기값 사이에 중괄호가 있을 때에도 쉼표로 구분해야 하는 것은 당연하다. 또한, 모든 중괄호는 쌍으로 사용해야 하고, 그렇지 않은 경우에는 컴파일러가 에러 메시지를 출력한다.

이제 배열의 장점을 보여주는 예제를 살펴보도록 하자. <리스트 8.3>에 있는 프로그램 RANDOM.C는 1,000개의 요소를 가지는 3차원 배열을 생성하고 무작위로 값을 저장한다. 그리고 나서 프로그램은 하면 상에 배열의 요소를 출력한다. 배열이 아닌 일반적인 변수를 사용할 경우에는 이런 작업을 수행하기 위해서 얼마나 많은 변수가 필요할지 상상해보기 바란다. 이 프로그램에서는 새로운 라이브러리 함수 getch()가 사용된다. getch() 함수는 키보드에서 하나의 문자를 읽어들인다. <리스트 8.3>에서 getch()는 하나의 키가 눌러질 때까지 프로그램의 실행을 정지시킨다. getch()는 낭중에 더욱 상세히 설명하겠음....

<리스트 8.3> RANCOM.C는 다차원 배열을 생성한다..

 

2.3 배열의 최대 크기
: 바이트 단위로 표현되는 배열의 크기는 각 요소의 크기뿐 아니라 배열 요소의 개수에 의해서 결정된다. 각 요소의 크기는 배열의 데이터형과 컴퓨터의 환경에 따라 결정된다. <표 8.1>에는 <표 3.2>에서 설명했던 각 숫자 데이터형의 크기가 편의를 돕기 위해서 다시 나타나 있다. 대부분의 PC에서 사용되는 데이터형의 크기이다.

<표 8.1> 대부분의 PC에서 사용되는 숫자 데이터형의 저장 공간 요구량.

 

배열에서 필요한 저장 영역을 계산하기 위해서는 요소의 크기에 배열 내의 요소의 개수를 곱하면 된다. 예를 들어, 500개의 요소를 가지는 float형 배열은 500 * 4를 계산하여 2,000바이트의 저장 영역을 요구한다는 사실을 알 수 있다.


C의 sizeof() 연산자를 사용하면 프로그램 내에서 저장 영역의 크기를 계산할 수 있다. sizeof()는 함수가 아니라 단항 연산자인데, 변수의 이름이나 데이터형을 인수로 받아들이고 인수로 사용된 변수나 데이터형의 크기를 바이트단위로 계산하여 돌려준다. sizeof()의 사용 예는 <리스트 8.4>에 나타나 있다.


<리스트 8.4> 배열에서 필요로 하는 저장 영역의 양을 계산하기 위해 sizeof() 연산자를 사용하는 프로그램.

 

 /* sizeof() 연산자의 사용 예 */

 

 #include <stdio.h>

 

/* 100개의 요소를 가지는 여러 개의 배열 선언 */

 

 int intarray[100];

 float floatarray[100];

 double doublearray[100];

 

 main{}

 {

    /* 숫자 데이터형의 크기 출력 */

 

    printf("\n\nSize of int = %d bytes", sizeof(int));

    printf("\nSize of short = %d bytes", sizeof(short));

    printf("\nSize of long = %d bytes", sizeof(long));

    printf("\nSize of float = %d bytes", sizeof(float));

    printf("\nSize of double = %d bytes", sizeof(double));

 

    /* 세 배열의 크기 출력 */

 

    printf("\nSize of intarray = %d bytes", sizeof(intarray));

    printf("\nSize of floatarray = %d bytes", sizeof(floatarray));

    printf("\nSize of doublearray = %d bytes", sizeof(doublearray));

 

    return 0;

 }

'pc관련 > C언어' 카테고리의 다른 글

C언어_숫자배열사용  (0) 2019.03.24
입출력의 기초  (0) 2019.03.20
C언어-프로그램제어문  (0) 2019.03.17
함수의 기본  (0) 2019.03.16
데이터 저장하기 : 변수와 상수  (0) 2019.03.11
Posted by 둥이파파^^