본문 바로가기

셈틀/C/C++

비트연산을 이용한 한달 출석부 관리 프로그램

문제>
int의 경우 현재 컴퓨터에서 4바이트(1byte=8bit)의 크기를 가지고 있다. 즉 총 32비트를 이용할 수 있다. 이 32비를 0과 1로 설정해서 한 달의 출석과 결석의 상태를 조절하는 프로그램을 작성하시오.

0000 0000 0000 0000 0000 0000 0000 0000
[그림 1] int형 4바이트(Byte) 구성
[그림 1]의 4바이트에서 가장 오른쪽에 있는 비트(LSB)가 1일을 나타내며 가장 왼쪽에 있는 비트(MSB)의 경우 32일을 나타내게 되지만 32일은 없으므로 사용하지 않는다.
출석의 경우 해당 비트를 1로 설정하고 결석의 경우 0으로 설정한다.
예) 0000 0000 0000 0000 0000 0000 1101 1011

위의 예)에서는 1일, 2일, 4일, 5일, 7일, 8일에 출석을 한 것이고 나머지 날들은 결석이다. 총 출석일 수는 6일이 된다.
조건)
메뉴화면이 나오고 1~5까지의 번호를 입력하는 무한 반복 형태이다.
- [1]출결설정: 입력한날의 비트를 1(출석) 또는 0(결석)으로 바꾸는 메뉴
- [2]출결확인: 입력한날의 비트가 1(출석)인지 0(결석)인지를 알아내는 메뉴
- [3]모든비트출력: 32비트를 모두 출력하는 메뉴
- [4]총출석일수계산: 한 달중 출석한날이 몇일인지 알아내는 메뉴
- [5]종료: 프로그램 종료
함수를 이용하여 프로그램 하시오.
- 출석결석을 설정하는 함수
- 출결상황을 확인하는 함수
- 총 출석일 수를 계산하는 함수
- 메뉴를 출력하는 함수
- 이 외에 프로그래머가 필요하다고 생각하면 다른 함수 추가 가능

메뉴 출력 함수를 제외한, 모든 다른 함수 내에서는 printf문과 scanf문을 사용해서는 안됩니다.
출결상황을 저장하는 변수는 int 타입으로 1개만 정의해야 하며 반드시 main()함수 내부에 지역변수로 선언하여야 합니다.

소스>
#include <stdio.h>
#include <windows.h>

//루프를 빠져가나는 자물쇠를 위한 정의
#define OPEN 1
#define CLOSE 0

void prtMenu(int &book);//메뉴를 출력하는 함수
void setAtt(int IsAtt, int date, int &book);//출석결석을 설정하는 함수
int chkAtt(int date, int &book);//출결상황을 확인하는 함수
int calAtt(int &book); //총 출석일 수를 계산하는 함수

int outRan(int date);//1~31일 안에 들어가 있으면 0, 그렇지 않으면 1 리턴

int main()
{
	int book=0;//출석부 초기화
	prtMenu(book);//인자를 출석부로 하여 메뉴를 불러온다.
	return 0;
}

void prtMenu(int &book){
	int mn; //메뉴 선택
	int date; //날짜 선택
	int lock=CLOSE; //루프를 빠져나가는 자물쇠 : 기본값 CLOSE(0)
	int flag=1; //비트를 비교하기 위한 flag
	int i;
	int IsAtt;//출결을 입력하기 위한 변수

	while(lock==CLOSE){//자물쇠가 CLOSE(0)인동안 반복
		system("cls");//화면을 지운다.

		//메뉴표시부분
		printf("[1] 출결 설정\n");
		printf("[2] 출결 확인\n");
		printf("[3] 출석부 출력\n");
		printf("[4] 출석일수 계산\n");
		printf("[5] 종료\n");
		printf("메뉴를 선택하세요. [   ]\b\b\b");
		scanf("%d", &mn);

		//각 메뉴에 대한 수행
		switch(mn){
			case 1://출결 설정
				while(1){//날짜를 범위에 맞게 입력 받음
					printf("출결설정 할 날짜 : ");
					scanf("%d", &date);
					if(outRan(date)){//날짜가 범위 밖이면
						printf("날짜를 잘 못 입력하셨습니다! (1~31)\n");
					}
					else
						break;
				}
				//해당 날짜의 현재 상태 표시
				printf("현재 상태: ");
				IsAtt=chkAtt(date, book);//현재의 출석상태를 IsAtt에 넣고
				if(IsAtt==1)//출석이면
					printf("출석\n");
				else//결석이면
					printf("결석\n");
				do{
					printf("출석으로 할 경우: 1\n결석으로 할 경우: 0\n어떻게 하시겠습니까? [   ]\b\b\b");
					scanf("%d", &IsAtt);//출결여부를 IsAtt에 입력
				}while(IsAtt!=0 && IsAtt!=1);//알맞은 메뉴를 선택했을 때 다음으로				
				setAtt(IsAtt, date, book);//출결을 출석부에 설정
				printf("설정되었습니다.\n");
				system("pause");//계속하기 위해 입력을 기다림
				break;

			case 2://출결 체크
				while(1){//날짜를 범위에 맞게 입력 받음
					printf("출결체크 할 날짜 : ");
					scanf("%d", &date);
					if(outRan(date)){//날짜가 범위 밖이면
						printf("날짜를 잘 못 입력하셨습니다! (1~31)\n");
					}
					else
						break;
				}
					if(chkAtt(date, book))//출석했으면 : chkAtt(date, book)==1
						printf("%d일 : 출석\n", date);
					else//결석했으면 : chkAtt(date, book)==0
						printf("%d일 : 결석\n", date);
				system("pause");//계속하기 위해 입력을 기다림
				break;

			case 3://출결 출력(bit 출력)
				i=sizeof(int)*8-1;//i 초기화
				for(i;i>=0;i--){
					if(book&(flag<<i))
						printf("1");
					else
						printf("0");
					if(i%5 == 0) //5(일)로 나누어 떨어지면
						printf(" ");//띄어쓰기 출력
				}
				printf("\n");
				system("pause");//계속하기 위해 입력을 기다림
				break;

			case 4://총 출석 출력
				printf("총 출석일수 : %d일\n", calAtt(book));
				system("pause");//계속하기 위해 입력을 기다림
				break;

			case 5://종료
				lock=OPEN;//자물쇠를 OPEN
				break;
		}
	}
}

//출결을 설정하는 함수
//IsAbs:출석설정=1/결설설정=0, date:해당날짜, book:출석부
void setAtt(int IsAtt,int date, int &book){
	int flag=1;
	flag=flag<<date-1;//flag를 해당 날짜의 비트로 이동
	if(IsAtt){//출석이면
	book=book|flag;//book의 해당 날짜에 1을 덮어씌운다.
	}
	else{//출석이면
		flag=~flag;//flag 반전 (나머진 1, 해당날짜 bit은 0이 된다.)
		book=book&flag;//book의 해당 날짜에 0을 덮어씌운다.
	}

}

//출결을 확인하는 함수
//date: 해당날짜, book: 출석부
int chkAtt(int date, int &book){
	int flag=1;//flag 선언 해당날짜의 bit와 비교하는데 쓰인다.
	//해당날짜로 이동한 flag와 book을 비교해서
	//해당날짜가 출석(1), 결석(0)이냐에 따라 그 값을 리턴
	return book&(flag<<date-1);
}

//출석부(book)를 인자로 하여 총 출석일수를 리턴
int calAtt(int &book){
	int i=sizeof(int)*8-1;
	int flag=1;
	int nbAtt=0;//출석일수 초기화
	for(i;i>=0;i--){
		if(book&(flag<<i))
			nbAtt++;
	}
	return nbAtt;
}

//날짜(date)가 범위(1~31)밖이면 1, 안이면 0을 리턴하는 함수
int outRan(int date){
	if(date>0 && date<32)
		return 0;
	else
		return 1;
}


결과>

사용자 삽입 이미지


사용자 삽입 이미지



결과2>

사용자 삽입 이미지

'셈틀 > C/C++' 카테고리의 다른 글

해결  (0) 2008.11.17
Cprogramming.com  (0) 2008.11.10
최대공약수(GCD)와 최소공배수(LCM) 구하기  (4) 2008.11.07
strstr함수 구현하기  (0) 2008.10.28
10진수를 BCD코드로 출력  (10) 2008.10.16