본문 바로가기
Basic/C/C++

[C언어] 제 13 강 : 배열

by boxbop 2012. 1. 19.
반응형

 


 올해 구정은 빠르네요.... 보통 2월에 있지 않았나요~?
엊그제 계좌에 365일이 입금되었는대 벌써 18일을 써버렸습니다...ㅠㅠㅠ
잔액을 좀 더 알차게 사용해야겠습니다..

 오늘은 C언어 배열에 대하여 공부해보도록 하겠습니다. 우리가 변수를 지정하는 것 만큼이나 자주 사용하고 더 나아가 포인터의 개념도 맛볼 수 있기 때문에 중요합니다^^

 배열은 변수의 선언에 있어서 상당히 편리한 역할을 해줍니다. 예를들어 전교생의 성적을 저장해야되는 변수를 선언한다고 생각해봅시다. 천명이고 만명이고 학생 수 만큼의 변수가 필요하겠죠..? 그럼 그 많은 변수를 한땀한땀 선언해주어야 됩니다. 배열은 이러한 부분을 완벽하게 해결해 줍니다.

 int a = 1, b = 2, c = 3, d = 4; 이러한 변수의 선언은
 int array[4] = {1, 2, 3, 4}; 이렇게 배열로 나타낼 수 있습니다.

 즉, 배열로 선언된 변수들에는 동일한 코드 패턴을 적용할 수 있습니다. 배열의 선언에 있어서 필요한 것은 변수의 이름, 자료형, 개수 입니다.

 int array [4]; 이런식으로 배열을 선언해 줍니다. int 는 배열 요소의 자료형을, array는 배열의 이름을, 대괄호 내의 숫자는 배열의 길이를 지정합니다. int형 변수 4개가 선언이 됬습니다. 각각 array[0], array[1], array[2], array[3]으로 표시할 수 있습니다.

 여기서 중요한 부분은 길이를 4로 지정했다면 배열의 요소는 0부터 시작하여 배열의 길이에서 1을 뺀값 (배열의 길이 - 1)까지입니다.

 int array[3] = { 1, 2, 3 }; 이라고 배열을 선언하고 초기화를 했다면
array[0] 에는 1, array[1] 에는 2, array[2]에는 3이 저장됩니다.

 배열의 이름은 주소이다!
이 사실은 상당히 중요합니다. 배열을 좀 더 본질적으로 이해할 수 있기 때문이죠. 아까 우리는 int array[3] = { 1, 2, 3 }; 이라는 코드로 배열을 선언해 주었습니다. 여기서 array라는 배열 자체의 이름에는 할당된 배열의 시작 주소 정보가 담겨있습니다. 예를들어 array라는 이름에는 0x11이라는 주소가 담겨있죠.
int형은 몇 바이트라고 했죠? 4바이트 입니다. 배열의 길이는 3이죠? 그럼 array라는 배열은 총 4바이트 * 길이3 = 12바이트 입니다. 즉 4바이트씩 3개로 묶여있는 셈이죠.

 배열의 길이는 무조건 상수로만 입력해주어야 합니다. 물론 컴파일러마다 다르긴 하지만 상수로만 입력해야된다고 일단은 알아두도록 합시다^-^

 int size = 10;
 int array[size];

 이러한 코드는 잘못되었습니다. 배열의 길이 부분에 변수가 들어가 있기 때문이죠^-^ 생각보다 이 부분이 상당히 불편합니다. 일단은 배열의 길이를 지정하는 부분은 무조건 상수만 올 수 있다고 알아둡시다!

 또 하나 예시를 들어보겠습니다.

 int array1[3] = { 1, 2, 3 };
 int array2[3];

 array2 = array 1;

 이러한 코드는 우리가 의도한대로 작동을 할까요? 아닙니다.  array1을 똑같이
array2에 복사를 하고 싶은거죠? 절대 이러한 코드로는 복사가 되지 않습니다. 왜냐면 아까 말했듯이 배열의 이름은 해당 배열의 시작 주소를 나타낸다고 했습니다. 즉, 위와 같은 코드는 array1의 주소값을 array2에 복사하는 것 밖에 안됩니다. 좀 더 생각을 해봅시다. 그러나 중요한건 array2도 분명히 배열로써 선언을 했기때문에 array2도 array1과는 다른 주소값을 가지고 있을 것 입니다. 예를들어 array1의 주소값은 0x11이고 array2의 주소값은 0x22라고 한다면
0x22 = 0x11; 과 같은 문장이 되어버리기 때문에 컴파일 에러까지 발생을 시킵니다. 이해가 가셨나요~?

 배열의 문자를 저장해보자!
이번에는 배열에 문자열을 저장해보겠습니다.

char string[7]="boxbop";

'boxbop' 이라는 문자를 배열로 설정해주었습니다. 좀 더 풀어서 살펴보면
string[0] = 'b', string[1] = 'o', string[2] = 'x', string[3] = 'b', string[4] ='o',
string[5] = 'p', string[6] = '\0' 이렇게 풀어서 얘기할 수 있겠네요
어?! 근대 맨 마지막에 string[6] = '\0' 은 무엇일까요? Null이라는 문자입니다. 중요한 사실은 문자열을 저장할 때에는 무자열의 마지막에 널(Null) 문자를 저장해서 문자열의 끝을 표시합니다. 처음에 배열에 초기화 할 때는 널문자를 지정하지 않았는대 왜 생겼냐구요? 이는 문자열의 끝에 자동으로 삽입이 됩니다. 따라서 배열의 길이도 실제 문자의 길이보다 +1 해서 지정을 해줘야됩니다.
printf문으로 출력할때 널(Null)문자를 만나면 출력을 종료합니다.

 문자열을 입력받기 위한 scanf에서의 배열!

 char string[10];
 scanf("%s", string);

 문자열을 입력 받기위해서 배열의 이름을 사용했습니다. 그런대 왜 string앞에 '&'연산자가 안 붙어 있을까요? 정답은 string자체가 주소값이기 때문입니다. 이해가 잘안가신다면 scanf부분을 다시 읽어보시길 바랍니다~

 이번에는 다차원 배열이다!
사실 다차원 배열이라는 건 단순히 눈속임 입니다. 사실상 배열은 모두 평행적으로 구성이되죠. 다만 인식하기에 직선, 평면, 입체로 구성되어 있는 것 처럼 보이기 때문에 다차원 배열이라고 얘기를 하는데요 별거 없습니다~ 메모리 구조에서는 모두가 1차원 구조이긴 합니다.

 int string[2][3]; 이라고 배열을 선언했습니다. 물론 유효한 문장입니다. 배열의 요소는 2 * 3 = 6개가 되겠습니다.

 string[0][0]     string[0][1]     string[0][2]
 string[1][0]     string[1][1]     string[1][2]
 

 수학시간에 '행렬' 기억 나시나요? 그것과 똑같다고 보시면 됩니다. 다만 보기 좋게~~ 묶여있을 뿐이죠^-^ 배열의 순서는 [0][0], [0][1], [0][2], [1][0] ,[1][1]..... 이런식이니까 초기화도 마찬가지로 해주면 됩니다.

 다만 1차원 배열과의 차이점은 1차원 배열에서는 배열의 이름이 주소값이라고 했죠? 2차원 배열에서도 동일합니다. 그러나 주소값을 포함하는 배열명이 몇 개 더 있습니다.

 string이라는 주소값과 stirng[0]의 주소값은 동일합니다.(2차원 배열에서) 그리고 string[1]과 string[2]도 주소값을 가지고 있습니다. 이는 2차원 배열이 1차원 배열을 3개 가지고 있다고 생각하면 편합니다. 즉, string 배열의 1행 string[0], 2행 string[1], 3행 string[2]은 각각 행을 대표하는 시작 주소를 나타냅니다. 그렇게 중요한 부분은 아니니까 가볍게 넘어가도록 하겠습니다~

 마지막으로 배열을 함수의 인자로 전달하는 방법을 살펴보고 이번 장을 마치도록 하겠습니다.

int main(void)
{
     int array[3] = { 1, 2, 3 };
     arrayPrint(array);
     return 0;
}

void arrayPrint(int arr[])
{
    for( int i = 0 ; i <3 ; i++)
         printf("%d", arr[i]);
}

 위의 소스코드를 예로들어 설명하겠습니다. arrayPrint(array)에서 보시면 배열의 이름을 전달하고 있습니다. 배열의 이름은 주소값이라고 했죠? 즉, 주소 값을 전달해주는 과정입니다. 그럼 이 함수의 구현 부분을 보겠습니다. 함수호출에 의해 전달되는 배열의 주소 값은 매개변수에 저장되는데, 여기서는 arr라는 매개변수가 선언되었습니다. 이러한 매개변수를 함수내에서는 사용하고 있습니다. array라는 배열처럼요. 매개변수를 선언할때 규칙은 배열의 길이를 나타내는 숫자만 생략하면 됩니다.

 가끔 코딩을 하다보면 배열의 길이가 가변적일 때가 있습니다. 이럴때 배열의 길이를 계산하는 방법을 간단하게 설명하겠습니다. 일단은 위 소스에서 arrayPrint() 함수 내에서 배열의 길이는 계산할 수 없습니다.

void arrayPrint(int arr[])
{
    int len = sizeof(arg)/sizeof(int);   
}

 sizeof연산자에 대하여 공부했었죠? 단순히 배열의 이름은 sizeof연산자에 넣으면 전체 배열의 크기가 나오겠죠? int형 배열이니까 4로 나눠주면 배열의 길이나 나오겠죠~? 그래서 위와 같이 함수를 구현했습니다. 그러나 이는 올바른 문장이 아닙니다. 왜냐하면 매개변수는 단지 int형, 4바이트 크기의 변수일 뿐 입니다. 임시로 값을 저장하는 변수일 뿐이죠... 실제 배열이 아닙니다~ 그저 매개변수는 배열의 주소값을 저장하는 것! 그게 다~~~~입니다.
결론은 함수 내에서 인자로 전달된 배열의 주소 값만 가지고 배열의 길이를 계산할 수 없습니다. 따라서 함수의 주소 값을 인자로 전달할 때에는 배열의 길이도 미리 계산해서 전달해주어야 합니다..ㅠㅠㅠ번거롭죠ㅠ arrayPrintf(array, sizeof(array)/sizeof(int)); 이런식으로 값을 계산해서 전달해주어야 합니다~ 이해가 가셨죠?

 다음 장부터는 포인터에 대해서 공부해볼 겁니다~ 사실 글로 표현하기에는 너무 힘들기때문에 포토샵을 사용할까 했지만 그러면 시간이 너무 오래 걸릴 것 같아서 포인터는 쉽게쉽게 넘어가려고 합니다.... 어차피 C언어 포스팅의 목적은 개인적인 복습이기 때문에... 혹시라도 단 한명이라도 이 포스팅을 꾸준이 열람하시는 분이 계실찌느은~? 모르겠지만 있으시다면 죄송합니다~굽신굽신ㅋㅋㅋㅋ... 벌써 시간이 이렇게 됬군요 ㅠㅠㅠㅠ 영화 보면서 쉬엄쉬엄 포스팅한다는게 이미 영화는 끝나버렸내요..;;;ㅋㅋㅋ 열공합시다~~~

반응형