배열 인수 전달

Download Report

Transcript 배열 인수 전달

Part 09 배열
©우균, 창병모
1
이 장의 내용






배열이란
배열 선언과 초기화
배열 인수 전달
2차원 배열
재미있는 몇 가지 이야기
배열 활용 연습
2
9.1 배열이란
3
이상한 요구사항


5개의 정수를 받아서 역순으로 출력하는 프로그램을 작
성하라.
실행 예



입력: 19 10 8 29 36
출력: 36 29 8 10 19
점진적 세분화
1.
2.
5개의 정수를 읽어 x0, x1, x2, x3, x4에 저장한다.
(scanf를 이용하여 바로 구현 가능)
x4, x3, x2, x1, x0 순으로 출력한다.
(printf를 이용하여 바로 구현 가능)
4
revPrint.c



scanf 중복
마음에 듭니까?
scanf와 printf 패턴이 중복
되는 것이 마음에 불편하지요?
"배열"을 이용하면 이 중복을
제거할 수 있습니다.
printf 중복
실행결과:
다섯 개의 정수를 입력해 주세요.
19 10 8 29 36
입력된 정수를 역순으로 출력하면 다음과 같습니다.
36 29 8 10 19
5
배열 소개

배열이란?



배열 원소 참조



같은 자료형의 자료 여러 개를 하나로 묶은 것
또는 이런 자료를 나타내는 자료형
첨자 연산자(index operator) []를 이용하여 참조한다.
C 배열의 첨자는 항상 0부터 시작한다.
배열 예

다섯 개의 원소로 이루어진 배열 x
6
revPrint2.c
크기 5인 int 배열 x
첨자연산자 []가 주소연산자
&보다 높은 우선순위임. 따라
서 &(x[i])와 같은 뜻임
실행결과:
다섯 개의 정수를 입력해 주세요.
19 10 8 29 36
입력된 정수를 역순으로 출력하면 다음과 같습니다.
36 29 8 10 19
7
배열 원소 훑어보기

배열 원소를 차례로 훑어볼 경우에는 for 문이 제격이다.

크기 N인 배열 a의 원소를 차례로 훑어보는 관용어구(programming
idiom)
for (int i = 0; i < N; ++i) {
... a[i] ...
}

표준 C(C99)와 예전 C와의 차이점
표준 C에서는 for의 초기화 수식 부분에서 변수를 선언할 수 있음
 이렇게 선언된 변수의 유효범위는 for 문 내부로 한정됨
 표준 이전 C에서는 다음과 같이 별도의 블록으로 작성함

{
int i = 0;
for (i = 0; i < N; ++i) {
... a[i] ...
}
}
8
9.2 배열 선언과 초기화
9
배열 선언과 초기화

배열 선언



첨자연산자 내부에 크기를 명시하여 선언
int a[5];
// 크기 5인 int형 배열
일반 변수 선언과 함께 선언할 수 있음
int x, y, a[5];
배열 초기화



중괄호 {} 내부에 초기값을 나열
int a[5] = {1, 3, 5, 7, 9};
초기화 목록이 있을 경우 배열 크기 생략 가능
int x[] = {1, 3, 5, 7, 9};
초기값 개수와 배열 크기가 다르면…
int x[5] = {1, 3};
// 나머지는 0
int x[3] = {1, 3, 5, 7, 9};
// 오류!
10
arrName.c
배열이름의 비밀
배열 이름은 배열이 할당된 메
모리 공간의 시작주소(base
address)임
실행결과:
배열 이름 값
x =
배열 전체 크기
sizeof(x) =
배열 원소 크기 sizeof(x[0]) =
1245036
20
4
11
9.3 배열 인수 전달
12
배열 인수 전달


배열을 인수로 전달할 때에는
'배열 이름'만 전달함
매개변수는 일반 배열처럼 선
언하지만, 이 때 크기는 무시
됨
배열 이름만 전달
매개변수 선언 시 배열 크기는 무시되므로
int sum(int a[])
와 같은 뜻임
실행결과:
1 + 2 + ... + 10 = 55
13
배열 크기 전달

배열 매개변수 선언 시 크기
는 무시되므로, 배열 크기는
별도의 인수로 전달함
배열 크기 계산
배열 전체 크기(sizeof x)를
원소 크기(sizeof x[0])로
나눔
배열 크기 전달
실행결과:
1 + 2 + ... + 10 = 55
2 + 4 + ... + 10 = 30
14
배열매개변수를 통한 배열원소 변경

배열매개변수 값



배열매개변수에는 배열이름(배열 시작주소)가 전달되므로
배열매개변수를 통해 배열을 바꾸면 전달된 원본 배열이 변경됨
배열매개변수에 배열이름을 전달한 상황


함수 f에서 함수 g를 호출할 때, 배열 a를 매개변수 x[]에 전달
했다면 x는 a의 시작주소(그림의 xxx)이므로
피호출자 g에서 x[1]의 값을 변경하면 a[1] 값이 변경된다.
15
sum2.c (1/2)
sum
main
x
read
main의 배열 x의 원소
값을 read가 채워주고
sum이 x의 원소 합을
구함
16
sum2.c (2/2)
함수 sum은
매개변수 a로 전달된
배열의 원소 합을 구하여
돌려준다.
프로시저 read는
매개변수 a로 전달된
배열의 각 원소 값을
표준 입력에서 읽는다.
실행결과:
5 개의 정수를 입력하세요: 1 3 5 7 9
입력한 숫자의 합은 25 입니다.
17
9.4 2차원 배열
18
다차원 배열

다차원 배열이란?



여러 개의 첨자를 갖춘 배열
선, 면, 입체, …  1차원, 2차원, 3차원, …
2차원 배열 선언 및 초기화
int x[2][3];
int y[2][3] = {{1,3,5}, {2,4,6}};

2차원 배열을 초기화할 때에는 초기화 목록 내에 초기화 목록을
명시한다.
19
2차원 배열 활용 예

N×N 정방행렬을 입력받은 후, 각 행과 열의 합을 구하
는 프로그램을 작성하라.



N×N 행렬 x의 원소를 읽는다.
각 행과 각 열의 합을 구하여 rSum, cSum에 저장한다.
행렬 x와 rSum, cSum을 출력한다.
20
rcSum.c (1/3)
각 배열 원소를 0으
로 초기화
정방행렬 x를 읽고
각 행과 열의 합의 구하고
x와 계산 결과를 출력함
21
rcSum.c (2/3)
정방행렬 a의
각 원소를 읽음
정방행렬 a의
각 행의 합 rSum과
각 열의 합 cSum을
구함
22
rcSum.c (3/3)
각 원소의 출력폭은 lseg의
길이보다 하나 작게 정함
각 원소 출력폭을 별도의 인수
로 받음
실행결과:
3 x 3 정수 행렬을 입력하세요:
1 2 3
4 5 6
7 8 9
1
2
3 |
6
4
5
6 |
15
7
8
9 |
24
---------------------+
12
15
18
23
9.5
재미있는 몇 가지 이야기
24
실행 중 printf의 출력 폭 지정



printf의 출력 폭을 별도의 인수로 받을 수 있음
출력 폭을 *로 지정하고 인수로 출력 폭을 넘김
활용 예


width가 6이라면 다음 문장은
printf("%*d", width, a[i][j]);
다음 문장처럼 해석된다.
printf("%6d", a[i][j]);
25
C에 2차원 배열은 없다?!

사실 2차원 배열은…



1차원 배열의 1차원 배열
배열 원소가 1차원 배열인 배열
2차원 배열도 1차원 배열로 취급할 수 있음
int y[2][3] = {{1,3,5}, {2,4,6}};
y[0]는 {1,3,5}, y[1]은 {2,4,6}
따라서
int y[2][3] = {1,3,5,2,4,6};
처럼 초기화할 수 있다.
26
9.6 배열 활용 연습
27
배열 활용 연습: 난수 발생

난수 발생 함수
int x = rand();

// 0~RAND_MAX 사이의 난수 발생
난수 발생 범위 변경

0이상 n이하 난수를 발생시키려면(범위 내 정수는 n+1개)
rand() % (n+1)

x이상 y이하의 난수를 발생시키려면(범위 내 정수는 y – x + 1개)
rand() % (y – x + 1) + x

초기 발생 난수 변경

time이 반환한 calendar time을 srand의 인수로 전달
srand((unsigned int)time(NULL));
28
histogram.c (1/3)
발생시킬 난수 개수
난수 발생 범위(LB: 하한, UB: 상한)
n개의 별표 *를 출력함
각 배열원소에 대해
첨자 값과 원소 값을 출력하고
원소 개수만큼 별표를 출력함
29
histogram.c (2/3)
초기 발생 난수 변경
lower 이상, upper 이하 범위의
난수를 발생시켜 되돌려 줌
LB이상 UB이하의
n개 난수를 발생시켜
배열 a의 각 원소에 저장
30
histogram.c (3/3)
초기 발생 난수를 변경하고
NUM개의 난수를 발생시켜 a에 저장한 후
a에 대한 히스토그램을 출력함
실행결과:
0 [ 19]:*******************
1 [ 8]:********
2 [ 20]:********************
3 [ 3]:***
4 [ 5]:*****
5 [ 12]:************
6 [ 9]:*********
7 [ 12]:************
8 [ 16]:****************
9 [ 15]:***************
31
Key Point
32
Key Point 1






배열이란 같은 자료형의 변수 여러 개를 묶은 자료, 또는 이러한 자
료형을 뜻한다.
배열 첨자 연산자는 대괄호 []를 이용하여 나타낸다. C 언어에서 배
열 첨자는 항상 0부터 시작한다. 따라서 n번째 원소를 참조하려면 첨
자 n-1을 사용해야 한다.
배열을 선언할 때는 배열 원소 자료형으로 선언하되 배열 이름 다음
에 배열 크기를 첨자 연산자([])로 묶어서 선언한다.
배열 이름은 배열이 할당된 메모리 공간의 시작주소다.
배열을 함수의 인수로 전달할 때는 배열 이름을 전달한다. 일차원 배
열 인수를 받는 형식 매개변수는 배열 크기가 생략된 형태로 선언한
다.
배열을 인수로 전달할 때, 배열의 크기는 별도의 인수로 전달해야 한
다.
33
Key Point 2


배열 인수를 전달받은 함수에서 배열 원소에 값을 저장하면 원본 배
열의 원소 값이 바뀐다.
2차원 배열이란 배열의 첨자가 두 개인 배열이다. 2차원 배열을 초기
화할 때에는 초기화 목록 내에 다시 초기화 목록을 기입한 형태를 사
용한다.
34
Key Point(고급 주제)





printf의 포맷 스트링에서 너비 지정 상수를 별도의 인수로 받도록
할 수 있는데 이 때 "%*d"와 같이 포맷 스트링의 너비를 *로 지정한
다.
C에는 2차원 배열이 없다. C에서 2차원 배열은 1차원 배열의 1차원
배열로 구현된다.
C의 다차원 배열도 1차원 배열의 초기화 목록을 이용하여 초기화할
수 있다.
C에서 난수를 이용해야 할 경우에는 난수 발생 함수 rand()를 이용
할 수 있다.
rand()가 생성하는 초기 난수를 변경하려면
srand((unsigned)time(NULL));와 같이 time()과 함께
srand()를 호출한 후에 rand()를 호출하면 된다.
35
요약(1/2)

배열



배열 선언 및 초기화



배열을 선언할 때에는 배열 크기를 첨자연산자 내에 명시함
배열을 초기화하기 위해서는 초기값 목록을 {, }로 묶어 명시함
배열 인수 전달



같은 자료형의 자료를 일렬로 묶은 자료 혹은 그러한 자료형
배열 원소는 첨자연산자 []를 통해 참조함
배열을 인수로 전달할 때에는 배열 이름만 전달함
배열 크기는 필요에 따라서 별도의 인수로 전달함
배열 매개변수를 이용한 배열 변경


배열 이름은 배열이 할당된 공간의 시작주소이므로
배열 매개변수를 통해 배열 원소를 변경하면 원본 배열도 변경됨
36
요약(2/2)

다차원 배열




다차원 배열은 첨자를 덧붙임으로써 선언할 수 있음
다차원 배열은 배열의 배열로 간주함
2차원 배열은 1차원 배열을 배열 원소로 하는 1차원 배열임
난수 발생 함수



난수가 필요한 경우에는 rand()를 이용할 수 있음
난수 발생범위는 나머지 연산자 %를 이용하여 변경 가능
초기 발생 난수를 임의로 변경하려면 srand() 이용
srand((unsigned int)time(NULL));
37
프로그래밍 실습
38
▶ 프로그래밍 실습 1

중심극한 정리를 확인하는 프로그램 작성
1.
크기 N인 모집단 a를 생성한 후, 이를 확률분포로 변경
double sum(double a[], int NUM);
void to_pdf(double a[], int NUM, double sum);
2.
모집단 a에서 크기 2인 샘플을 모두 구한 후 샘플 평균들을 배열
b에 기록함
void normalize(double a[], double b[], int NUM);
3.
4.
샘플들의 평균 분포 b도 확률분포로 변경(to_pdf 이용)
배열 값을 scale 만큼 확대하여 히스토그램을 그림
void histogram(double a[], int NUM, int scale);
5.
모집단 a의 확률분포와 샘플 평균 분포 b의 확률분포를 히스토
그램으로 출력함(b의 히스토그램은 정규분포와 유사해야 함)
39
▶ 프로그래밍 실습 1 (출력 예)

샘플 평균의 분포 b의 확률분포를 출력하면 다음과 같이
정규분포와 유사하게 출력되어야 한다
x
x
x
x
x
x
x
x
x
x
=
=
=
=
=
=
=
=
=
=
0
1
2
3
4
5
6
7
8
9
[
[
[
[
[
[
[
[
[
[
0.04]:***
0.09]:********
0.11]:***********
0.14]:**************
0.19]:******************
0.16]:****************
0.11]:***********
0.09]:********
0.06]:*****
0.01]:*
40
▶ 프로그래밍 실습 2

틱택토(Tick-Tac-Toe) 프로그램
1.
2.
3.
말판의 좌표는 그림과 같이 정한다.
각 위치의 말판을 입력하면 빈 자리인가 확인하고 말판을 놓은
후, 변화된 말판을 출력한다. 각 선수는 O, X로 출력한다. 선수 O
가 b3에 두었다면 그림과 같이 출력되어야 한다.
매번 돌을 놓을 때마다 승패를 판단하고, 특정 선수가 이겼을 경
우 축하 메시지를 출력한다.
1
2
3
+---+---+---+
A |
|
|
|
+---+---+---+
B |
|
| O |
+---+---+---+
C |
|
|
|
+---+---+---+
41