책정리/혼자 연구하는 C,C++ 1

9장 배열

GONII 2015. 2. 19. 17:02

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 배열의 특징

  1. 배열 요소의 번호인 첨자는 항상 0부터 시작

    n번 학생의 성적을 출력할 때 : printf("%d번 학생 성적은 %d",n, ar[n-1]);

    ar[n]을 출력할 때 : printf("%d 번 학생 성적은 %d", n+1, ar[n]);

  2. 배열이 차지하는 총 메모리양은 배열의 크기에 배열 요소의 크기를 곱해서 구할 수 있다.

    배열 크기 = sizeof(배열)/sizeof(배열[0]);

  3. 배열을 선언할 때 크기값은 반드시 상수로 주어야 한다.
  • 예제 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])));

}

  1. 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차 배열 초기화

  1. 초기값 개수가 꼭 맞는 경우

    나열하기만 하면 됨

  2. 초기값이 모자랄 때

    나머지 요소를 모두 0으로 초기화

  3. 초기값 개수가 남는 경우

    안됨, 에러

  4. 배열의 크기를 생략하는 방법

    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