8강 · 제6장 · 175~191쪽 · 약 75분

배열과 포인터(1)

1차원·다차원 배열, char형 배열과 문자열, 배열을 함수에 넘기는 방법을 교재 예제 6-1~6-8로 익힙니다. (교재 제6장 175~191쪽)

학습 목표

  • 같은 형의 자료를 배열로 모아 선언·초기화하고, 첨자는 0부터임을 설명한다
  • 1차원·2차원·3차원 배열의 형식과 행 우선 저장을 말한다
  • 문자열이 char 배열이며 끝에 \0이 필요함을 알고 크기를 잡는다
  • 배열을 함수에 넘기면 값이 아니라 위치가 전달되어 원본이 바뀔 수 있음을 확인한다
  • 교재 예제 6-1~6-8을 실행하고 초기값·첨자를 바꿔 결과를 예측한다

왜 이 강이 필요한가?

학생 100명의 점수를 변수 100개로 선언하면 이름도 반복도 버겁습니다. 같은 자료형을 한 이름 아래 모아 번호(첨자)로 다루는 것이 배열입니다.

이 강은 교재 제6장(배열과 포인터) 175~191쪽이며, LMS 강의내용 순서와 같습니다.

  1. 1차원 배열 — 선언, 연속 기억 공간, 초기화, 예제 6-1·6-2
  2. 다차원 배열 — 2차원·3차원, 예제 6-3·6-4
  3. char형 배열과 문자열 — \0, 예제 6-5·6-6
  4. 함수와 배열 — 배열명은 주소, 예제 6-7·6-8 (189~191쪽)

포인터의 선언·연산은 9강(6.2절)입니다. 이 강에서는 “배열명 = 시작 주소”, “함수에 넘기면 위치를 넘긴다” 정도만 잡습니다.

본문 C 예제는 실행 칸이 붙습니다. scanf 예제는 교재 입력값을 배열에 넣어 두었습니다. 표기는 int main(void)입니다.


1. 배열이란 / 1차원 배열

배열은 같은 자료형의 값들이 한 배열명 아래 순서대로 모인 것입니다. 각각의 칸을 원소(요소) 라 하고, 배열명 + 첨자 [] 로 구분합니다. 첨자 개수에 따라 1차원, 2차원, 3차원으로 부릅니다.

변수 100개 대신 score[100]처럼 쓰면, 반복문으로 합·평균을 구하기 쉽습니다.

1.1 선언

형식:  자료형  배열명[개수];
예:    int a[10];
  • 첨자가 하나이면 1차원입니다.
  • 개수는 요소의 개수이고, 정수 상수(또는 정수로 계산되는 상수 식)여야 합니다.
  • 첨자는 0부터입니다. int array[5]의 마지막은 array[4]입니다. array[5]는 범위를 벗어납니다.
  • 각 요소는 일반 변수처럼 자료형·기억 클래스를 갖습니다.
  • 선언하면 연속된 기억 공간이 잡힙니다. int array[5]는 int 5칸이 이어진 자리입니다.

배열명만 쓰면(첨자 없이) 그 영역의 시작 주소입니다. array의 값은 &array[0]과 같습니다. 자세한 포인터 관계는 9강입니다.

1.2 초기화

선언 후 칸마다 넣거나, 선언과 동시에 중괄호로 넣을 수 있습니다. 후자가 보통입니다.

int array[4];
array[0] = 10;
array[1] = 20;
array[2] = 30;
array[3] = 40;

선언과 동시에:

형태의미
int array[4] = {10, 20, 30, 40};네 칸에 그대로
int array[] = {10, 20, 30, 40};크기를 생략하면 값 개수(4)로 결정
int array[4] = {10, 20, 30};모자란 칸은 0
int array[4] = {0};전부 0
int array[4] = {10, 20, 30, 40, 50};값이 더 많으면 오류
int array[4] = {10, , 30, 40};빈 칸은 오류

입력으로 채우기:

int x[10], i;
for (i = 0; i < 10; i++)
    scanf("%d", &x[i]);

교재 6-1 — 네 가지 초기화:

이 예제 실행

실행 결과가 여기에 표시됩니다.

array3[2], array3[3]과 array4 전부는 0입니다.

1.3 배열을 함수에 넘기기 (예제 6-2)

배열 전체를 인자로 줄 때는 첨자 없이 배열명만 적습니다. 헤더의 int gr[]처럼 크기를 생략해도 됩니다. 크기를 적으면 그 크기로만 고정됩니다.

넘어가는 것은 값의 복사가 아니라 위치(주소) 입니다. 7강의 참조 전달과 같습니다. 그래서 함수 안에서 gr[0] = 0이면 호출한 쪽 score[0]도 0이 됩니다.

이 예제 실행

실행 결과가 여기에 표시됩니다.

실행: sum = 150, score[0] = 0.


2. 다차원 배열

2차원 이상은 다차원 배열입니다. 2차원은 “1차원 배열의 배열”, 3차원은 “2차원 배열의 배열”로 보면 됩니다. 대괄호가 늘면 차원도 늘습니다.

2.1 2차원 배열 (예제 6-3)

형식:  자료형  배열명[행][열];
예:    int a[3][4];    /* 3행 4열, 요소 12개 */

초기화는 한 줄로도, 행마다 중괄호로도 같습니다. 행을 묶으면 읽기 쉽습니다.

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

기억 공간에는 행 우선으로 1차원처럼 이어 붙습니다. a[0][0], a[0][1], … a[0][3], a[1][0], …
행만 쓰고 열을 빼면(a[1]) 그 행이 시작되는 주소입니다(포인터 역할, 9강).

이 예제 실행

실행 결과가 여기에 표시됩니다.

각 행 합계 270, 240, 210, 180. 교재는 static int로 두었습니다(7강 정적 저장). 지역 int로 초기화해도 이 예제는 같습니다.

2.2 3차원 배열 (예제 6-4)

형식:  자료형  배열명[면][행][열];
예:    int a[2][3][4];   /* 2면 3행 4열 = 24개 */

교재 6-4는 3반 × 3명 × 3과목입니다. 아래는 교재 실행 결과와 같은 점수를 넣어 두었습니다. (원래는 scanf로 9번 입력합니다.)

이 예제 실행

실행 결과가 여기에 표시됩니다.

국어 721(평균 80), 수학 758(84), 영어 769(85). 평균은 정수 나눗셈입니다.


3. char형 배열과 문자열

C에는 문자열 자료형이 없습니다. 문자열은 char 배열이거나 나중에 배울 포인터로 다룹니다.

"SEOUL KOREA"는 공백 포함 11글자 + 널 문자 \0 = 12칸입니다(2강). 컴파일러가 끝 \0을 넣습니다.

형식:  char 배열명[길이+1];
예:    char str[12];

초기화:

char name[] = "HONG GIL DONG";                 /* 문자열 단위, \0 자동 */
char address[] = {'S', 'E', 'O', 'U', 'L', '\0'};  /* 문자 단위, \0을 직접 */

문자 단위로 넣을 때는 \0를 빼먹으면 %s가 끝을 못 찾고 쓰레기 글자가 붙을 수 있습니다.

교재 6-5:

이 예제 실행

실행 결과가 여기에 표시됩니다.

교재는 adrs2 뒤에 쓰레기가 붙을 수 있다고 합니다. 선언과 동시에 일부만 초기화하면 나머지는 0이라, 이 코드에서는 adrs2[5]가 0이 되어 SEOUL만 나오는 경우가 많습니다. “끝이 \0이어야 %s가 멈춘다”는 점은 같습니다.

교재 6-6 — 입력 길이만큼 *로 복사:

이 예제 실행

실행 결과가 여기에 표시됩니다.

www.knou.ac.kr은 14글자라 별도 14개입니다. str_out 끝에도 \0를 넣어야 %s가 멈춥니다.

한글과 배열 크기. "Hello"는 5글자 + \0 → 최소 6. "안녕"은 글자 2개처럼 보여도, 이 사이트·맥의 소스는 보통 UTF-8이라 한글 1자가 3바이트인 경우가 많아 2×3 + 1 = 7칸이 안전합니다. 옛 완성형(EUC-KR 등)은 한글 1자가 2바이트라 2×2+1=5입니다. 글자 수가 아니라 바이트 수 + 1로 잡으세요.


4. 함수와 배열

배열을 매개변수로 쓸 때:

  • 호출은 배열명만 (첨자 없음). 배열명은 주소입니다.
  • 1차원 헤더는 크기를 생략해도 됩니다: int gr[]
  • 다차원은 가장 왼쪽(높은) 차원만 생략할 수 있습니다. 2차원은 int gr[][5], 3차원은 int gr[][2][3]처럼 오른쪽 크기는 필요합니다.
  • 크기를 적으면 그 크기의 배열만 받을 수 있습니다.
  • 전달은 위치(참조) 이지 값 복사가 아닙니다.

교재 6-7 — 2차원 배열을 함수에:

이 예제 실행

실행 결과가 여기에 표시됩니다.

sum[0] = 150, sum[1] = 50. 헤더의 [5]는 열 개수와 맞춥니다.

교재 6-8 — 3차원 배열과 정수 평균:

이 예제 실행

실행 결과가 여기에 표시됩니다.

반마다 학생 평균을 정수로 구한 뒤, 그 평균들의 평균이 반 평균입니다. 1반 15, 2반 20, 3반 40, 4반 10.


5. 지금 실습할 것

아래는 1차원 합·평균, 2차원 행 합, 문자열 \0를 한 파일에 모았습니다.

  1. scores 값을 바꾸고 합·평균이 따라가는지 확인
  2. 2차원 table의 한 칸을 바꿔 행 합이 바뀌는지 보기
  3. name 끝 \0를 주석으로 빼 보면 %s가 어떻게 되는지 관찰 (다시 넣기)
  4. (선택) 6-2처럼 함수에서 scores[0] = 0을 해 원본이 바뀌는지 확인

코드 실습 (C)

실행 결과가 여기에 표시됩니다.

확인 퀴즈

1. int a[5]; 에서 올바른 마지막 요소는?
2. int a[] = {10, 20, 30}; 에서 배열 크기는?
3. int a[4] = {10, 20}; 에서 a[2]의 값은?
4. 예제 6-2처럼 배열명만 함수에 넘기면?
5. int a[3][4]; 의 요소 개수는?
6. 2차원 배열을 함수 매개변수로 받을 때 옳은 형태는?
7. 문자열 "Hi"를 char 배열에 넣으면 칸 수는 최소?
8. char s[6]에 문자만 {'S','E','O','U','L'} 넣고 \0를 안 넣는 것이 위험한 이유는?
9. 첨자 없이 배열명 a 만 쓰면 무엇을 뜻하는가?
10. 예제 6-4에서 총점/9 평균이 정수인 이유는?

스스로 점검