9.1 배열
9.1.1 배열의 정의
동일한 타입을 가지는 변수들의 유한 집합
-
기본 형식
일반 변수 선언문과 동일하되 변수명 뒤에 [ ] 괄호(bracket)와 배열 크기 지정문이 온다
type 배열명[크기][크기]...;
int ar[5]; // 크기가 5인 정수형 배열 ar
ar[0] |
ar[1] |
ar[2] |
ar[3] |
ar[4] |
9.1.2 배열의 특징
-
배열 요소의 번호인 첨자는 항상 0부터 시작
n번 학생의 성적을 출력할 때 : printf("%d번 학생 성적은 %d",n, ar[n-1]);
ar[n]을 출력할 때 : printf("%d 번 학생 성적은 %d", n+1, ar[n]);
-
배열이 차지하는 총 메모리양은 배열의 크기에 배열 요소의 크기를 곱해서 구할 수 있다.
배열 크기 = sizeof(배열)/sizeof(배열[0]);
- 배열을 선언할 때 크기값은 반드시 상수로 주어야 한다.
- 예제 Array
#include <stdio.h>
void main(void) { int arScore[5]; int i; int sum;
for (i=0; i<sizeof(arScore)/sizeof(arScore[0]); i++) { printf("%d번 학생의 성적은 입력하세요 : ",i+1); scanf("%d", &arScore[i]); }
sum=0; for(i=0; i<sizeof(arScore)/sizeof(arScore[0]); i++) { sum+=arScore[i]; }
printf("\n총점은 %d점이고 평균은 %d점입니다.\n",sum, sum/(sizeof(arScore)/sizeof(arScore[0]))); } |
- C언어는 배열의 범위를 전혀 점검하지 않는다.
- 예제 AraayBound
#include <stdio.h>
void main(void) { char name[10];
printf("이름이 뭐에요?\n"); gets(name); printf("니가 %s구나\n",name);
} |
// 이름이 길면 name[10]에 저장하지 못하고 에러남
- 예제 ArrayBound2
#include <stdio.h>
void main(void) { int i; int ar[5];
i=1234; ar[5]=5678;
printf("i= %d",i); } |
ar[5] 선언시 ar[0,1,2,3,4]까지 만들어지기 때문에 ar[5]는 없는 공간이다.
9.1.3 다차원 배열
2차원 배열은 첨자 두 개를 사용하는 배열
int ar[2][3];
ar[0][0] |
ar[0][1] |
ar[0]2] |
ar[1][0] |
ar[1][1] |
ar[1][2] |
- 예제 ArraySung
#include <stdio.h>
void main() { int arScore[2][2]; int cla,stu; int sum[2]; int maxScore=0; int maxc, maxs;
arScore[0][0]=92; arScore[0][1]=84; arScore[1][0]=40; arScore[1][1]=100;
for(cla=0; cla<2; cla++) { sum[cla]=0; for(stu=0; stu<2; stu++) { sum[cla]+=arScore[cla][stu]; if(maxScore<arScore[cla][stu]) { maxScore=arScore[cla][stu]; maxc=cla; maxs=stu; } } printf("%d 반 : 총점=%d점, %d점\n",cla+1,sum[cla],sum[cla]/3); } printf("최고득점은 %d반 %d번 학생의 %d점입니다.\n",maxc+1,maxs+1,maxScore); } |
9.1.4 배열명
배열명이 단독으로 사용되면 배열의 시작 번지값을 가지는 포인터 상수이다.
배열도 변수이므로 어딘가에 메모리를 차지하며 모든 배열 요소들이 연속적으로 배치되어 있다.
배열명은 이 메모리의 시작 번지를 가리키는 포인터가 된다.
9.2 배열 초기화
9.2.1 쓰레기값
지역 배열은 초기화되지 않는다.
- 예제 Garbage
#include <stdio.h>
void main() { int ar[5]; int i;
for(i=0; i<5; i++) { printf("ar[%d]=%d\n",i,ar[i]); } } |
9.2.2 1차원 배열 초기화
type 배열명[크기]={초기화 값들};
9.2.3 초기식
int arBig[1000]={1,2,3,}; // ar[0,1,2]는 1,2,3초기화, 나머지는 0으로 초기화
int ar[]={1,2,3,4,5} // 초기값으로 들어온 만큼 크기 선언
배열의 크기와 초기값이 |
결과 |
꼭 맞으면 |
만사 형통 |
초기값이 모자라면 |
나머지는 모두 0 |
초기값이 남으면 |
에러로 처리됨 |
배열 크기를 생략하면 |
개수만큼 자동으로 크기 설정 |
9.2.4 2차 배열 초기화
-
초기값 개수가 꼭 맞는 경우
나열하기만 하면 됨
-
초기값이 모자랄 때
나머지 요소를 모두 0으로 초기화
-
초기값 개수가 남는 경우
안됨, 에러
-
배열의 크기를 생략하는 방법
int ar[][3]={{1,2,3},{4,5,6}} // 2차원 배열의 1차 첨자의 크기생략
9.3 배열의 활용
9.3.1 불규칙한 정보
체력과 시간만 있다면 해도됨
9.3.2 재사용할 정보
- 예제 RandArray
#include <stdio.h> #include <stdlib.h> #include <windows.h>
// 지정한 위치로 커서 이동하는 함수 선언 void setPosition(int x, int y) { COORD pos= {x,y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); }
void main() { short arPt[100][2]; int i;
//별 찍기 for문 for(i=0;i <100; i++) { arPt[i][0]=rand()%80; // 0~79 사이의 난수를 arPt[i][0]에 대입 arPt[i][1]=rand()%25; // 0~24 사이의 난수를 arPt[i][0]에 대입 setPosition(arPt[i][0],arPt[i][1]); // x=arPt[i][0], y=arPt[i][1]로 커서 이동 putch('*'); Sleep(20); // 지정된 시간만큼 정지 후 실행 }
Sleep(2000); //별 지우기 for 문 for(i=0; i<100; i++) { setPosition(arPt[i][0],arPt[i][1]); putch(' '); Sleep(20); } } |
난수로 임의 위치에 * 100개 출력, 지우기
9.3.3 작업 결과 저장
- 예제 Eratosthenes
#include <stdio.h> #define RANGE 100 #define TURE 1 #define FALSE 0
typedef enum{false, true} BOOL;
void main() { BOOL Prime[RANGE+1]; int i,j;
// 일단 전부 소수로 가정 for (i=0; i<=RANGE; i++) { Prime[i]=TURE; }
// 2부터 배수를 찾아 지움. for (i=2; i<=RANGE; i++) { if (Prime[i]) { for(j=i*2; j<=RANGE; j+=i) { Prime[j]=FALSE; } } }
puts("1~100까지의 소수 목록"); for (i=2; i<=RANGE; i++) { if (Prime[i]) { printf("%d ", i); } } } |
- 과제 AlphaNum
/* 목적 : 입력받은 글자의 개수를 출력 */ #include <stdio.h>
void main() { // 변수 선언 char alphaNum[100]={0}; int i; int Number=0;
// 글자 입력 받는다. printf("알파벳을 입력하세요.(100자 이하) : "); scanf("%s", alphaNum);
// 입력받은 글자의 배열에 NULL값이 있는 곳까지 for문 반복 for(i=0; alphaNum[i]!='\0'; i++) { // 입력받은 글자수++ Number+=1; }
//입력받은 문장의 개수 출력 printf("입력받은 글자 개수=%d\n",Number); } |
9.3.4 룩업 테이블
값의 참조를 위해 사용하는 배열을 룩업 테이블(Lookup Table)이라 한다.
읽기 전용인 경우가 많으므로 static으로 선언하는 것이 좋다.
- 예제 PrintTomorrow
/* 목적 : 내일 날짜를 출력 */ #include <stdio.h>
void PrintTomorrow(int m, int d); void main() { int month, day;
printf("오늘 날짜(월 일)을 공백으로 구분하여 입력해 주세요 : "); scanf("%d%d",&month,&day);
PrintTomorrow(month, day); }
void PrintTomorrow(int m, int d) { // 0 ~ 12월 마지막 날 배열 입력 static int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
// 일이 달의 마지막날보다 크거나 || 달이 1월보다 작거나 || 달이 12월보다 크면 잘못 입력 if (d>days[m] || m<1 || m>12) { printf("잘못된 날짜 입력\n"); } else { d++; // 일++하여 해당 달의 마지막 날을 넘는지 체크 if(d>days[m]) { d=1; // 달의 마지막 날을 넘으면 다음 달 1일로 출력 m++; // 12월이 지나면 1월 1일로 출력 if(m==13) { m=1; } } printf("내일은 %d월 %d일입니다.\n",m,d); } } |
- 예제 RandTable
#include <stdio.h> #include <stdlib.h> #include <time.h>
void main(void) { int arRand[]={2,9,14,19,27}; int Num;
srand((unsigned)time(NULL)); Num=arRand[rand()%(sizeof(arRand)/sizeof(arRand[0]))]; printf("생성한 난수 = %d\n",Num); } |
원하는 난수를 포괄하여 범위에서 수를 하나 생성하는 조건문으로 사용
- 예제 GameMessage1
// switch case문이 길어 비효율적으로 보임 #include <stdio.h>
void Congratulation(int count);
void main() { Congratulation(3); }
void Congratulation(int count) { switch(count) { case 1: puts("축하합니다. 최고 성적입니다."); break; case 2: puts("대단한 성적입니다."); break; case 3: puts("참 잘 하셨습니다."); break; case 4: puts("보통이 아니군요."); break; case 5: puts("보통입니다."); break; case 6: puts("조금 더 노력하셔야겠습니다."); break; case 7: puts("정말 못하시는군요."); break; case 8: puts("수준 이하입니다."); break; } } |
- 예제 GameMessage2
//위 예제 보다 훨씬 보기 좋다. #include <stdio.h>
void Congratulation(int count);
void main() { Congratulation(3); }
void Congratulation(int count) { static char *Message[]={"", "축하합니다. 최고 성적입니다.", "대단한 성적입니다.", "참 잘 하셨습니다.", "보통이 아니군요.", "보통입니다.", "조금 더 노력하셔야겠습니다.", "정말 못하시는군요.", "수준 이하입니다." };
if(count>=9) count=9; puts(Message[count]); } |
- 예제 GameMessage3
#include <stdio.h>
void Congratulation(int count);
void main() { Congratulation(8); }
void Congratulation(int count) { static char *Message[]={ "잘 하셨습니다.", "보통입니다.", "못하는 군요", }; static int arMes[]={0,0,0,0,1,1,1,1,1,2,2,2,2};
if(count>=12) count=12; puts(Message[arMes[count]]); } |
- 예제 PrintTomorrow2
/* 목적 PrintTomorrow예제는 녀도에 대한 고려는 하지 않는데 년도까지 계산에 포함하면 윤년을 고려해야 한다. 윤년 = 4로 나누어 떨어지되 100으로는 나누어 떨어지지 않는 년도인데 1904년=윤년, 1990년=윤년아님 또한 100으로 나누어 떨어지는 년이라도 400으로 나누어 떨어지면 윤년임 2000년은 윤년 윤년에는 2월이 29일임 년, 월, 일 정보를 입력받아 윤년까지 고려해 내일 날짜를 출력 */ #include <stdio.h>
void PrintTomorrow(int year, int month, int day);
void main() { int year, month, day; printf("년, 월, 일 입력 : "); scanf("%d%d%d",&year, &month, &day);
PrintTomorrow(year, month, day); }
void PrintTomorrow(int year, int month, int day) { // 윤년 = year%4==0 && year%400==0 || year!=100 && month==2 // 2월 29일까지 static int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
if(year%4==0 && year%400==0 || year%100!=0 && month==2 && day==28) { day++; printf("내일은 %d년 %d월 %d일\n", year, month, day); }
// 윤년이 아니고 else if(day>days[month] || 1>month || 12<month) { printf("잘못 입력\n"); } else { day++; if(day>days[month]) { day=1; month++; if(month>13) { year++; month=1; } } printf("내일은 %d년 %d월 %d일\n", year, month, day); } } |
9.3.5 미리 계산된 값
- 예제 Revolution1
// 연산이 많아 좌표계산하는데 시간이 오래 걸린다 #include <stdio.h> #include <conio.h> #include <math.h>
void setPosition(int x, int y);
void main() { double angle; int x=-1, y=-1;
setPosition(40,12); putch('S'); for(angle=0;;angle+=10) { if(angle==360) { angle=10; } if(kbhit()) { break; } setPosition(40+x,12+y); putch(' '); x=(int)(cos(angle*3.1416/180)*20); y=(int)(sin(angle*3.1416/180)*10); setPosition(40+x, 12+y); putch('E'); Sleep(100); } }
void setPosition(int x, int y) { COORD pos= {x,y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } |
- 예제 Revolution2
// 필요한 모든 값을 미리 구해 배열에 넣어두고 참조하면 상대적으로 빠르다. #include <stdio.h> #include <math.h> #include <windows.h>
void setPosition(int x, int y);
void main() { double angle; int x=-1, y=-1; static int arx[]={20,19,18,17,15,12,9,6,3,0,-3,-6,-10,-12,-15,-17,-18,-19,-19,-19,-18,-17,-15,-12,-9,-6,-3,0,3,6,10,12,15,17,18,19}; static int ary[]={0,1,3,5,6,7,8,9,9,9,9,9,8,7,6,4,3,1,0,-1,-3,-5,-6,-7,-8,-9,-9,-9,-9,-9,-8,-7,-6,-4,-3,-1};
setPosition(40,12); putch('s');
for(angle=0;;angle+=10) { if (angle==360) {angle=10;} if (kbhit()) {break;} setPosition(40+x,12+y); putch(' '); x=arx[(int)angle/10]; y=ary[(int)angle/10]; setPosition(40+x, 12+y); putch('e'); Sleep(100); } }
void setPosition(int x, int y) { COORD pos= {x,y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } |
9.4 소코반
9.4.1 게임 소개
전형적인 퍼즐 게임으로서 규칙이 간단해서 누구나 쉽게 즐길 수 있다.
1980년대 초반에 일본에서 처음 개발됨
최근 핸드폰 게임 '푸시푸시'라는 이름으로 이식되었음
9.4.2 분석
'책정리 > 혼자 연구하는 C,C++ 1' 카테고리의 다른 글
11장 배열과 포인터 (0) | 2015.02.19 |
---|---|
10장 포인터 (0) | 2015.02.19 |
8장 표준 함수 (0) | 2015.02.19 |
7장 기억 부류 (0) | 2015.02.19 |
6장 함수 (0) | 2015.02.19 |