Part 09 배열 1
이장의내용 배열이란 배열선언과초기화 배열인수전달 2차원배열 재미있는몇가지이야기 배열활용연습 2
9.1 배열이란 3
이상한요구사항 5 개의정수를받아서역순으로출력하는프로그램을작성하라. 실행예 입력 : 19 10 8 29 36 출력 : 36 29 8 10 19 점진적세분화 1. 5 개의정수를읽어 x0, x1, x2, x3, x4 에저장한다. (scanf 를이용하여바로구현가능 ) 2. x4, x3, x2, x1, x0 순으로출력한다. (printf 를이용하여바로구현가능 ) 4
revprint.c 마음에듭니까? scanf 와 printf 패턴이중복되는것이마음에불편하지요? scanf 중복 " 배열 " 을이용하면이중복을제거할수있습니다. 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 = 1245036 배열전체크기 sizeof(x) = 20 배열원소크기 sizeof(x[0]) = 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. 샘플들의평균분포 b 도확률분포로변경 (to_pdf 이용 ) 4. 배열값을 scale 만큼확대하여히스토그램을그림 void histogram(double a[], int NUM, int scale); 5. 모집단 a 의확률분포와샘플평균분포 b 의확률분포를히스토그램으로출력함 (b 의히스토그램은정규분포와유사해야함 ) 39
프로그래밍실습 1 ( 출력예 ) 샘플평균의분포 b 의확률분포를출력하면다음과같이정규분포와유사하게출력되어야한다 x = 0 [ 0.04]:*** x = 1 [ 0.09]:******** x = 2 [ 0.11]:*********** x = 3 [ 0.14]:************** x = 4 [ 0.19]:****************** x = 5 [ 0.16]:**************** x = 6 [ 0.11]:*********** x = 7 [ 0.09]:******** x = 8 [ 0.06]:***** x = 9 [ 0.01]:* 40
프로그래밍실습 2 틱택토 (Tick-Tac-Toe) 프로그램 1. 말판의좌표는그림과같이정한다. 2. 각위치의말판을입력하면빈자리인가확인하고말판을놓은후, 변화된말판을출력한다. 각선수는 O, X 로출력한다. 선수 O 가 b3 에두었다면그림과같이출력되어야한다. 3. 매번돌을놓을때마다승패를판단하고, 특정선수가이겼을경우축하메시지를출력한다. 1 2 3 +---+---+---+ A +---+---+---+ B O +---+---+---+ C +---+---+---+ 41