C프로그래밍 8강 - 배열과 포인터(1)
동일한 자료형의 값을 연속된 메모리에 저장하는 배열의 구조를 이해하고, 1·2·3차원 배열의 선언과 초기화 방법을 익힌다. char형 배열로 문자열을 표현하는 원리와 함수를 호출할 때 배열의 규격을 전달하는 방법도 함께 정리한다.
1. 배열의 개념
배열(array)은 여러 개의 동일한 자료형 값을 연속적인 메모리 공간에 저장하고 하나의 이름으로 관리하는 변수이다. 많은 자료의 평균·최댓값을 구하거나 원하는 값을 찾고 정렬할 때, 자료마다 별도의 변수를 선언하는 것보다 반복문과 배열을 함께 사용하는 편이 효율적이다.
각 배열 요소에는 0부터 시작하는 번호가 차례로 붙는다. 이 번호를 첨자 또는 인덱스(index)라고 하며, 배열의 각 요소는 배열명[첨자] 형식으로 접근한다.
| 구분 | 구조 | 요소 접근 예 |
|---|---|---|
| 1차원 배열 | 값이 한 줄로 나열 | a[i] |
| 2차원 배열 | 행과 열로 나열 | a[i][j] |
| 3차원 배열 | 면·행·열로 나열 | a[i][j][k] |
배열의 모든 요소는 같은 자료형이며 메모리에 연속적으로 배치된다. 첨자의 시작값은 0이다.
2. 1차원 배열의 선언과 메모리 구조
1차원 배열은 다음 형식으로 선언한다.
자료형 배열명[개수];
int a[5];
int a[5];는 int형 값 5개를 저장하는 연속 공간을 만든다. 요소는 a[0]부터 a[4]까지이며 유효한 첨자의 범위는 항상 0부터 개수-1까지이다. 배열명 a만 사용하면 배열의 시작 위치를 나타낸다.
개수에는 0보다 큰 값을 갖는 정수형 상수식을 사용한다. 배열 요소의 자료형에는 기본 자료형뿐 아니라 열거형, 구조체형, 공용체형, 포인터형 등도 사용할 수 있다.
C는 배열 범위를 자동으로 검사하지 않는다. a[5]처럼 범위를 벗어난 요소에 접근하면 배열 앞뒤의 다른 자료를 침범할 수 있으므로 반복 조건을 정확히 작성해야 한다.
3. 1차원 배열의 초기화와 활용
초기화 규칙
배열 선언 뒤 각 요소에 값을 대입할 수도 있고, 선언과 동시에 중괄호 안에 초깃값을 나열할 수도 있다.
int a1[4] = {10, 20, 30, 40};
int a2[] = {10, 20, 30, 40};
int a3[4] = {10, 20};
int a4[4] = {0};
| 선언 | 배열 크기 | 저장되는 값 |
|---|---|---|
a1[4] | 4 | 10, 20, 30, 40 |
a2[] | 초깃값 수로 결정한 4 | 10, 20, 30, 40 |
a3[4] | 4 | 10, 20, 0, 0 |
a4[4] | 4 | 0, 0, 0, 0 |
초깃값 수는 배열 크기보다 많을 수 없다. 적으면 앞에서부터 채우고 나머지 요소를 0으로 초기화한다. 개수를 생략하면 나열한 초깃값의 수가 배열 크기가 된다. 전역 배열과 static 배열은 초깃값을 지정하지 않아도 모든 요소가 0이지만, 초기화하지 않은 지역 자동 배열에는 미지의 값이 들어 있다.
최댓값 구하기
int data[10] = {10, 23, 5, 9, 22, 48, 12, 10, 55, 31};
int max = data[0];
for (int i = 1; i < 10; i++) {
if (max < data[i])
max = data[i];
}
첫 요소를 최댓값으로 가정한 뒤 두 번째 요소부터 차례로 비교하면 결과는 55이다. 배열과 반복문을 결합하면 자료 개수가 늘어나도 같은 처리 구조를 유지할 수 있다.
4. 2차원 배열
2차원 배열은 행과 열의 구조를 갖는다. 선언 형식과 전체 요소 수는 다음과 같다.
자료형 배열명[행의 수][열의 수];
int a[2][3]; /* 2행 3열, 전체 6개 요소 */
a[2][3]은 3개 요소로 구성된 1차원 배열, 즉 행이 2개 있는 배열로 볼 수 있다. 논리적으로는 표처럼 보이지만 메모리에는 첫째 행의 모든 요소를 저장한 다음 둘째 행의 요소를 저장하는 행 우선(row-major) 순서로 연속 배치된다. a는 전체 배열의 시작 위치이고 a[0], a[1]은 각 행의 시작 위치를 나타낸다.
2차원 배열 초기화
int a[2][3] = {1, 2, 3, 4, 5, 6};
int b[2][3] = {{1, 2}, {4, 5, 6}};
int c[][3] = {{1, 2, 3}, {4, 5, 6}};
a는 첫째 행에 1, 2, 3, 둘째 행에 4, 5, 6이 저장된다. b의 b[0][2]는 부족한 초깃값 때문에 0이 된다. c처럼 행의 수를 생략하면 초깃값으로 행의 수를 정할 수 있지만, 한 행의 크기를 결정하는 열의 수는 지정해야 한다.
2차원 배열의 전체 요소 수는 행의 수×열의 수이고, 실제 메모리 배치 순서는 행 우선이다.
5. 2차원 배열의 활용과 3차원 배열
성적 합계 계산
학생 4명의 세 과목 점수를 score[4][3]에 저장하면 바깥 반복문은 학생을, 안쪽 반복문은 과목을 순회하도록 구성할 수 있다.
int score[4][3] = {
{90, 90, 90}, {80, 80, 80},
{70, 70, 70}, {60, 60, 60}
};
for (int i = 0; i < 4; i++) {
int sum = 0;
for (int j = 0; j < 3; j++)
sum += score[i][j];
printf("%d\n", sum);
}
각 행의 합계는 차례로 270, 240, 210, 180이다. 차원이 늘어나면 일반적으로 각 첨자를 순회하는 중첩 반복문이 필요하다.
3차원 배열
자료형 배열명[면의 수][행의 수][열의 수];
int a[2][3][4];
a[2][3][4]는 2면×3행×4열이므로 전체 24개 요소를 갖는다. 선언과 동시에 초기화할 때는 int a[][3][4] = {...};처럼 첫째 차원의 개수만 생략할 수 있다. a[2][][4]나 a[2][3][]처럼 뒤쪽 차원을 생략하면 요소 위치를 계산할 규격을 알 수 없어 오류가 된다.
6. char형 배열과 문자열
C의 문자열은 일련의 문자 뒤에 문자열의 끝을 알리는 널 문자 '\0'를 붙여 표현한다. 따라서 문자열은 char형 배열에 저장하며, 배열의 최소 크기는 문자열 길이+1이어야 한다.
char str[12]; /* 최대 11글자 문자열 */
char name[] = "HONG GIL DONG";
char addr[] = {'S', 'E', 'O', 'U', 'L', '\0'};
문자열 리터럴로 초기화하면 컴파일러가 마지막 널 문자까지 저장할 공간을 계산한다. 문자 단위로 초기화할 때는 마지막에 '\0'를 직접 넣어야 문자열 함수와 %s가 끝을 알 수 있다.
"HONG GIL DONG"은 문자 13개와 널 문자 1개가 필요하다. 그러므로 char name[10]은 부족하고, 강의 예처럼 char name[16]으로 충분한 여유를 두어 선언해야 한다.
scanf("%s", string)은 공백 전까지 입력한다. 강의의 핵심은 입력한 배열을 string[i] != '\0'인 동안 순회하면 문자 단위로 출력할 수 있다는 점이다.
7. 함수와 배열 인수 전달
배열을 함수의 인수로 전달할 때는 함수가 배열의 규격을 알 수 있도록 매개변수를 선언해야 한다. 첫째 차원의 개수는 지정하지 않아도 되지만 그 뒤 차원의 크기는 반드시 알려야 한다.
| 전달 배열 | 함수 헤더 예 | 별도 크기 정보 |
|---|---|---|
| 1차원 int 배열 | int f(int arr[], int n); | 요소 수 n |
| 열이 3개인 2차원 배열 | void g(int arr[][3], int n); | 행 수 n |
| 한 면이 3행 4열인 3차원 배열 | double h(double arr[][3][4], int n); | 면 수 n |
double average(int arr[], int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
sum += arr[i];
return sum / (double)n;
}
int score[4] = {90, 85, 100, 88};
printf("%.1f\n", average(score, 4)); /* 90.8 */
배열명 score를 전달하면 함수는 배열 요소에 접근할 수 있다. 배열 자체에는 요소 개수 정보가 포함되어 있지 않으므로 강의 예처럼 n을 함께 전달하여 반복 범위를 정한다.
2차원 배열 score[2][5]를 전달하는 매개변수는 int gr[][5]로 선언한다. 함수는 행 수와 열 수를 함께 받아 각 행의 합 150과 50을 계산할 수 있다.
핵심 개념 정리
- 배열은 같은 자료형의 여러 값을 연속된 메모리에 저장하고 하나의 이름으로 관리한다.
- 배열 첨자는 0에서 시작하며 크기가 n인 1차원 배열의 유효 범위는 0부터 n-1이다.
- 초깃값이 배열 크기보다 적으면 나머지는 0이 되고, 크기를 생략하면 초깃값 수로 결정된다.
- 2차원 배열은 행 우선 순서로 저장되며 전체 요소 수는 행의 수×열의 수이다.
- 다차원 배열에서 초기화로 생략할 수 있는 것은 첫째 차원의 개수뿐이다.
- C 문자열은 char형 배열에 저장하고 끝에 널 문자
'\0'를 둔다. - 문자열 배열은 실제 문자 수보다 최소 1칸 더 커야 한다.
- 배열을 함수에 전달할 때 첫째 차원을 제외한 나머지 차원의 크기를 매개변수에 표시한다.
최종 정리: 배열 문제는 ‘첨자가 0에서 시작한다’, ‘요소가 연속 배치된다’, ‘부족한 초깃값은 0으로 채운다’는 세 원칙으로 먼저 판단한다. 문자열에서는 널 문자 한 칸을 추가하고, 다차원 배열과 함수 매개변수에서는 첫째 차원만 생략할 수 있다는 규칙을 기억하자.
예상문제 20선
1. 배열(array)에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
배열은 동일한 자료형의 값을 연속 공간에 저장하며 하나의 배열명과 첨자로 관리한다.
2. int a[5];에서 사용할 수 있는 첨자의 범위는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
크기가 5인 배열의 첨자는 0부터 개수-1인 4까지이다.
3. 배열의 이름만 사용했을 때 나타내는 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
강의에서 배열명은 배열이 시작하는 메모리 위치를 나타낸다고 설명한다.
4. int a[4] = {10, 20};에서 a[3]의 값은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
초깃값이 부족하면 앞에서부터 채우고 나머지 요소는 0으로 초기화한다.
5. int a[] = {10, 20, 30};으로 선언한 배열의 크기는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
배열 크기를 생략하면 나열한 초깃값의 수가 배열 크기가 된다.
6. 초깃값을 지정하지 않은 지역 자동 배열의 요소 값은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
초기화하지 않은 지역 자동 배열에는 미지의 값이 들어 있다. 전역 또는 static 배열과 구분해야 한다.
7. 여러 값 중 최댓값을 구할 때 배열의 첫 요소를 max로 정했다면 비교를 시작할 적절한 첨자는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
0번 요소는 이미 max에 저장했으므로 나머지 자료인 1번 요소부터 비교한다.
8. int a[2][3];의 전체 요소 수는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
2행×3열이므로 전체 요소 수는 6이다.
9. C의 2차원 배열 요소가 메모리에 배치되는 기본 순서는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
첫째 행의 요소를 차례로 저장한 뒤 다음 행의 요소를 저장한다.
10. int b[2][3] = {{1, 2}, {4, 5, 6}};에서 b[0][2]는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
첫째 행에는 1과 2만 지정되어 남은 b[0][2]가 0으로 초기화된다.
11. int a[2][3][4];의 전체 요소 수는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
면의 수×행의 수×열의 수인 2×3×4=24이다.
12. 3차원 배열 선언과 초기화에서 생략할 수 있는 차원은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
초깃값으로 첫째 차원의 수는 정할 수 있지만 뒤 차원의 규격은 요소 위치 계산에 필요하다.
13. C 문자열의 끝을 나타내는 문자는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
C 문자열은 마지막의 널 문자로 문자열이 끝나는 위치를 표시한다.
14. 길이가 11인 문자열을 저장하기 위한 char 배열의 최소 크기는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
문자 11개와 끝을 표시할 널 문자 1개를 합쳐 최소 12칸이 필요하다.
15. char addr[] = {'S','E','O','U','L','\0'};의 배열 크기는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
문자 5개와 명시한 널 문자 1개가 초깃값이므로 배열 크기는 6이다.
16. char 배열의 문자열을 문자 단위로 순회할 때 종료 조건으로 적절한 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
널 문자를 만나면 문자열의 끝이므로 그 전까지 각 문자를 처리한다.
17. 1차원 int 배열을 함수에 전달하는 매개변수 선언으로 알맞은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
배열 매개변수와 반복 범위를 알리는 요소 수 n을 함께 선언할 수 있다.
18. 열이 3개인 2차원 int 배열을 받는 매개변수 선언은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
첫째 차원의 개수는 생략할 수 있지만 각 행의 크기인 열의 수 3은 지정해야 한다.
19. average(score, 4)에서 요소 수 4를 별도로 전달하는 주된 이유는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
배열 인수만으로는 함수가 요소 개수를 알 수 없으므로 크기 정보를 별도로 전달한다.
20. 배열 범위를 벗어난 접근에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
C는 일반적으로 배열 범위를 자동 검사하지 않으므로 잘못된 첨자는 다른 메모리 영역을 침범할 수 있다.
댓글
댓글 쓰기