배열의 선언과 사용
목차
- 배열의 선언
- 배열의 사용
- 배열의 초기화
- 배열과 반복문
- 배열 요소의 개수 구하기
1. 배열의 선언
배열을 사용하는 이유
그동안 메모리에 저장 공간을 확보할 때 변수를 선언했습니다.
int a, b, d, d, result, sum.. 처럼 말이죠.
하지만 우리는 조금 더 편하게 데이터를 저장하고자 합니다.
이를테면 한 학생의 과목 성적 같은거 말이죠, 혹은 학기별 성적이라던가요.
동일한 자료형 여러 개를 한 번에 묶어서 처리할 수 있는 방법은 없을까요?
그럴 때 사용하는 것이 바로 배열(array)입니다.
배열의 선언
선언 방법은 간단해요, 변수처럼 선언해둔 다음, 끝에 [ ] 만 추가하면 된답니다.
int a[5]; 처럼 선언하면 된답니다.
이때, a는 배열의 이름을 의미하고 [5]는 배열의 요소 개수를 의미한답니다.
배열을 사용하는 것은 처리속도에도 도움이 된답니다. 예를 들어...
a1, a2, a3, a4, a5를 변수로 선언하면 각각 다른 자리에 저장되어서 찾는 데 시간이 걸리지만
배열 a[5]를 사용하면
a[0] | a[1] | a[2] | a[3] | a[4] |
처럼 저장되기 때문에 바로바로 긁어올 수 있어요.
이는 나중에 배울 포인터와도 관련이 있는데.. 그건 나중에 설명하죠.
그런데, 배열은 a[5]인데 정작 저장은 a[0], a[1], a[2]..처럼 되네요? 이유가 뭘까요?
2. 배열의 사용
배열을 선언할 때와 배열을 사용할 때의 대괄호는 의미가 서로 달라요.
배열을 선언할 때 사용되는 [ ]는 그 배열 요소의 개수를 의미하고,
배열을 사용할 때 사용되는 [ ]는 그 배열 요소의 위치를 의미해요.
이때 배열 위치는 0부터 불러온답니다. 이걸 인덱스(index)라고도 부르는데, 한번 실습해볼까요..
#include <stdio.h>
int main(void)
{
int stats[5];
stats[0] = 10;
stats[1] = 20;
stats[2] = 30;
printf("%d\n", stats[0]);
printf("%d\n", stats[1]);
printf("%d\n", stats[2]);
printf("%d\n", stats[3]);
printf("%d\n", stats[4]);
return 0;
}
으음.. 좋아요.
일단 결과를 먼저 보자면 다음과 같은데
10
20
30
-858993460
-858993460
음, 왜 이럴까요?
한줄씩 뜯어보자면, 일단 5번째 줄에서 배열 int stats[5]를 만들어요.
이때 stats[5]는 다음과 같아요.
? | ? | ? | ? | ? |
왜 ? 가 들어가 있냐면, 배열을 선언만 해 둔 상태고 초기화를 한 상태가 아니기 때문이에요.
일반적인 변수들처럼 쓰래기 값이 들어가 있죠.
이때 7~9줄까지를 통해 stats에 값을 집어넣어요. index값은 0부터 시작한다고 했죠?
그렇게 되면 stats[5]는 다음과 같아져요.
10 | 20 | 30 | ? | ? |
이제 이 값을 printf를 통해 출력하면 다음과 같은 값이 나오는 거랍니다.
3. 배열의 초기화
물론 방금처럼 초기화할 수 있겠지만, 저러면 그냥 변수랑 다를 바가 뭔가요
배열을 한번에 초기화 해 봅시다.
일반적인 변수는 int a = 0; 으로 초기화하지만, 배열은 여러개의 변수가 들어 있어요.
이럴 때는 중괄호 { } 를 사용해서 변수를 초기화한답니다.
다음과 같이 말이죠.
int stats[5] = { 1,2,3,4,5 };
이러면 배열은 다음과 같은 방식으로 초기화된답니다.
1 | 2 | 3 | 4 | 5 |
하지만 배열 요소의 개수가 100개, 200개 등을 넘어가면 어떨까요?
이럴 때 사용하는 자동 초기화 기능이 있어요.
int stats[5] = { 0 };
혹은 int stats[5] = { };도 가능하긴 합니다만, 이건 C랑 C++의 컴파일러에 따라 다르게 나오는 경우가 있어서 추천하지 않아요.
이러면 배열은 다음과 같은 방식으로 초기화된답니다.
0 | 0 | 0 | 0 | 0 |
물론 요소가 늘어나도 계속 0으로 초기화된답니다.
아쉽게도 0 말고 다른 걸 넣을 수는 없어요.
4같은걸로 초기화하려고
int stats[5] = { 4 };
를 넣으면 초기화는 다음과 같아집니다.
4 | 0 | 0 | 0 | 0 |
배열 요소의 크기보다 초기화한 변수의 개수가 적을 때는 어떻게 될까요?
사실 바로 위랑 똑같기는 한데...
이렇게 말이에요.
int stats[5] = { 1,2,3 };
이러면 배열은 이렇게 초기화된답니다.
1 | 2 | 3 | 0 | 0 |
흠, 배열의 길이를 안 정해주면 어떨까요?
int stats[] = { 1,2,3,4,5 }; 처럼 말이죠.
이 배열의 크기가 생략되었지만, 컴파일러는 자동으로 이 배열의 요소 개수를 계산해서 배열의 크기를 설정합니다.
본질적으로
int stats[ ] = { 1,2,3,4,5 };
int stats[5] = { 1,2,3,4,5 };
는 동일하다는 거죠.
1 | 2 | 3 | 4 | 5 |
재미있게도, 오직 하나의 형만이 조금 다릅니다. char 배열이죠.
이전의 "변수" 회차의 3. 문자열의 저장 편을 보시면 말이죠..
C의 문자열은 문자의 배열과 동등하다고 말했어요.
그때 구조는 char 배열명 [공백 혹은 문자열길이+1 이상] = 문자열; 이었죠.
한번 다시 가져와봅시다.
흐음, 뭔가 위에서 본 거랑 비슷하죠?
문자열 배열의 크기를 비워두면, 자동으로 널 문자 \0을 삽입시켜서 컴파일러가 계산해준답니다.
char 배열의 자세한 내용은 나중에 배우도록 해요!
다시 본론으로 돌아와서, 배열 전체를 초기화하는데 성공했습니다.
하지만 한번 더 이 배열을 초기화하고 싶어요. 어떻게 해야 할까요?
stats[5] = { 1,2,3,4,5 }; 하면 될까요?
아쉽게도 이건 불가능해요. C언어의 문법적 이유 때문이죠.
문법적 이유에 대해 깊이 탐구하기는 어려우니, 다른 방법을 이용하도록 합시다.
방법은 두 가지가 있어요. 반복문(for, while)을 통해 배열을 하나하나 수정하거나,
혹은 <string.h>라이브러리를 이용해서 strcpy로 수정하는 거에요.
후자는 배열에 대해 추가적으로 배울 때 알아볼 테니, 일단 첫번째 방법으로 초기화해봅시다.
int new_values[5] = {5, 4, 3, 2, 1};
for (int i = 0; i < 5; i++) {
stats[i] = new_values[i];
}
첫번째 방법은 이러한 방법으로 초기화됩니다.
이 경우에는 배열을 하나 더 만들어서 초기화했지만, 원한다면 for문을 수정해서 scanf값을 받아서 초기화하거나 for문의 count값으로 수정하는 것도 가능해요.
4. 배열과 반복문
마지막으로 배열을 반복문에 사용하는 방법을 알아봅시다.
위에 제가 올렸던 코드를 보면, 뭔가 반복되는 부분이 있어요.
흠, printf 부분이 배열의 index값만 다르지 나머지는 다 똑같은걸 알 수 있나요?
저기에 for문이나 while문의 count를 집어넣으면 어떨까요?
당연하게도 가능합니다. 한번 해보도록 하죠.
배열을 사용하여 성적의 합, 평균을 구하는 코드를 짜 봅시다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int stats[5] = { 0 }; //값을 입력할 배열 선언
int sum = 0; //총점을 누적할 변수
for (int i = 0; i < 5; i++) //i가 0부터 4까지 5번 반복
{
printf("성적을 입력하세요: ");
scanf("%d", &stats[i]); //각 배열 요소에 성적 입력
sum += stats[i]; //값을 누적하여 총점 계산
}
printf("총합 : %d\n", sum); //총점 출력
printf("평균 : %.2f\n", sum/5.0); //평균 출력
return 0;
}
결과는 다음과 같아요.
성적을 입력하세요: 86
성적을 입력하세요: 91
성적을 입력하세요: 88
성적을 입력하세요: 83
성적을 입력하세요: 89
총합 : 437
평균 : 87.40
언뜻 보면 그냥 노가다한것보다 까다로워 보이지만, 변수가 100개, 1000개, 10000개를 넘어가면 이 반복문과 배열의 진가가 드러난답니다.
아무리 많은 데이터라도 배열과 반복문을 잘 활용하면 손쉽게 관리할 수 있어요.
5. 배열 요소의 개수 구하기
하지만 한 가지 문제가 있죠. 바로 배열 요소의 개수를 상수로 집어넣어야 한다는 말이에요.
그렇다면 조금 멀리서 접근해 봅시다. 배열 요소의 개수를 어떻게 구할까요?
배열은 동일한 자료형의 변수의 모음이니, 배열의 크기를 변수의 크기로 나누면 개수가 나오지 않을까요?
그러기 위해서 사용하는 것이 이전에도 나왔던 sizeof 연산자입니다.
한번 계산해보죠.
일반적으로 배열 요소의 개수는 다음과 같이 구합니다.
배열 요소의 개수 = 배열의 전체 크기 / 배열 요소 하나의 크기
배열 요소의 개수 = sizeof(배열) / sizeof(배열 요소 하나)
이렇게 위쪽 코드를 수정하면..
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
int stats[5] = { 0 }; //값을 입력할 배열 선언
int sum = 0; //총점을 누적할 변수
int count;
count = sizeof(stats) / sizeof(stats[0]);
for (int i = 0; i < count; i++) //i가 0부터 count까지 5번 반복
{
printf("성적을 입력하세요: ");
scanf("%d", &stats[i]); //각 배열 요소에 성적 입력
sum += stats[i]; //값을 누적하여 총점 계산
}
printf("총합 : %d\n", sum); //총점 출력
printf("평균 : %.2f\n", sum/(float)count); //평균 출력
return 0;
}
짜잔.
이제 배열의 크기만 수정하면 모든 배열 포함 구문들이 고쳐집니다. 편하네요!