우리가 특정 자료형의 변수를 선언하면 이는 메모리상 어딘가에 특정 크기만큼의 자리를 차지하게 됩니다. 만약 비슷한 종류의 값을 모아서 저장하고 싶다면 어떻게 해야 할까요? 메모리상에서 여러 값을 연이어서 저장하고 사용하는 방법과 그 이점을 알아보겠습니다.
C에는 아래와 같은 여러 자료형이 있고, 각각의 자료형은 서로 다른 크기의 메모리를 차지합니다.
bool: 불리언, 1바이트
char: 문자, 1바이트
int: 정수, 4바이트
float: 실수, 4바이트
long: (더 큰) 정수, 8바이트
double: (더 큰) 실수, 8바이트
string: 문자열, ?바이트
컴퓨터 안에는 아래 사진과 같은 RAM 이라고 하는 물리적 칩이 메모리 역할을 합니다.
쉽게 생각하면 아래 사진에서 여러 개의 노란색 사각형이 메모리를 의미하고, 작은 사각형 하나가 1바이트를 의미한다고 볼 수 있습니다.
예를 들어 char 타입의 변수를 하나 생성하고, 그 값을 입력한다고 하면 위 사진에서 한 사각형 안에 그 변수의 값이 저장되는 것이죠.
아래와 같이 세 개의 점수를 저장하고 그 평균을 출력하는 프로그램이 있습니다.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Scores
int score1 = 72;
int score2 = 73;
int score3 = 33;
// Print average
printf("Average: %i\n", (score1 + score2 + score3) / 3);
}
만약 점수의 개수가 더 많아진다면 이 프로그램은 많은 부분을 수정해줘야 합니다.
이 때 활용할 수 있는 것이 배열의 개념입니다.
배열
: 같은 자료형의 데이터를 메모리상에 연이어서 저장하고 이를 하나의 변수로 관리하기 위해 사용됩니다.
위 코드는 배열을 이용하면 아래와 같이 바꿀 수 있습니다.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Scores
int scores[3]; //배열 요소의 개수를 정해준다
scores[0] = 72;
scores[1] = 73;
scores[2] = 33;
// Print average
printf("Average: %i\n", (scores[0] + scores[1] + scores[2]) / 3);
}
int scores[3]; 이라는 코드는 int 자료형을 가지는 크기 3의 배열을 scores 라는 이름으로 생성하겠다는 의미입니다.
-> 배열은 개수와 타입을 구한다
배열의 인덱스는 0부터 시작하기 때문에, scores의 인덱스는 0, 1, 2 세 개가 있습니다.
-> 0부터 시작
이 인덱스를 변수명 뒤 대괄호 [ ] 사이에 입력하여 배열의 원하는 위치에 원하는 값을 저장하고 불러올 수 있습니다.
-> 배열[위치] = 값
하지만 위와 같은 코드는 여전히 점수의 개수가 바뀌는 상황에서 제약이 많습니다.
다음 강의에서는 배열을 보다 동적으로 선언하고 저장하는 방법을 알아보겠습니다.
타입 변수명[개수] : 변수에 정해진 타입과 개수만큼 요소를 가진 배열을 넣는다
변수명[index] = 값 : 해당 자리에 값을 넣는다
#include <cs50.h>
#include <stdio.h>
const int N = 3;
int main(void)
{
// 점수 배열 선언 및 값 저장
int scores[N];
scores[0] = 72;
scores[1] = 73;
scores[2] = 33;
// 평균 점수 출력
printf("Average: %i\n", (scores[0] + scores[1] + scores[2]) / N);
}
scores의 크기로 전역 변수를 선언하였기 때문에 점수 개수가 바뀌었을때 수정해야 하는 코드가 조금 줄었습니다.
하지만 여전히 일일이 배열의 인덱스마다 점수를 지정해줘야 하는 불편함이 있습니다.
아래 코드에서와 같이 루프와 함수를 선언하여 좀 더 동적인 프로그램을 작성할 수 있습니다.
#include <cs50.h>
#include <stdio.h>
float average(int length, int array[]);
int main(void)
{
// 사용자로부터 점수의 갯수 입력
int n = get_int("Scores: ");
// 점수 배열 선언 및 사용자로부터 값 입력
int scores[n];
for (int i = 0; i < n; i++)
{
scores[i] = get_int("Score %i: ", i + 1);
}
// 평균 출력
printf("Average: %.1f\n", average(n, scores));
}
//평균을 계산하는 함수
float average(int length, int array[])
{
int sum = 0;
for (int i = 0; i < length; i++)
{
sum += array[i];
}
return (float) sum / (float) length;
}
여기서는
1) 배열의 크기를 사용자에게 직접 입력 받고,
2) 배열의 크기만큼 루프를 돌면서 각 인덱스에 해당하는 값을 역시 사용자에게 동적으로 입력 받아 저장합니다.
3) 그리고 average 라는 함수를 따로 선언하여 평균을 구합니다.
: average 함수는 length 와 array[],
-> 즉 배열의 길이와 배열을 입력으로 받습니다.
함수 안에서는 배열의 길이만큼 루프를 돌면서 값의 합을 구하고 최종적으로 평균값을 반환합니다.
이와 같은 방법을 통해서 임의의 점수 개수와 점수 배열에 대해서 동적으로 평균값을 구하는 프로그램을 작성할 수 있습니다.
#include <cs50.h> //전처리기에서 읽어서 컴파일 전 include
#include <stdio.h>
//컴파일에서 소스코드를 어셈블어로
//어셈블에서 어셈블어를 오브젝트 코드(기계)어로
//링크에서 위의 파일들과 모두 하나로
float average(int length, int array[]);
//main이 밀리지 않기 위해 맨 위에서 선언부터
//소수 타입을 반환하고 int 타입의 매개변수 두개를 받는다
int main(void) //시작하는 함수, 입력 출력이 없다 : void
{
// 사용자로부터 점수의 갯수 입력(동적으로
int n = get_int("Scores: ");
// 점수 배열 선언 및 사용자로부터 값 입력
int scores[n];
for (int i = 0; i < n; i++)
{
scores[i] = get_int("Score %i: ", i + 1);
}
// 평균 출력
printf("Average: %.1f\n", average(n, scores));
}
//평균을 계산하는 함수
float average(int length, int array[])
{
int sum = 0;
for (int i = 0; i < length; i++)
{
sum += array[i];
}
return (float) sum / (float) length;
}
앞에 반환 타입, 괄호 안에 매개변수 타입