Chapter08 프로그래밍 연습

milpy·2022년 5월 9일
0

C 기초 플러스 6판

목록 보기
12/18

다음의 몇몇 프로그램에서는 입력이 EOF로 끝나야 한다. 사용자의 운영체제가 리디렉션을 지원하지 않거나 사용이 불편하다면, 문자 &를 읽는 것과 같이, 입력을 종료할수 있는 다른 검사방법을 사용하라.
(필자는 리디렉션을 지원한다.)

01

파일의 끝까지 입력에 들어 있는 문자들의 수를 카운트하는 프로그램을 작성하라.

#include <stdio.h>

int main(void)
{
	int count = 0;
	int ch;

	while ((ch = getchar()) != EOF )
		count++;

	printf("문자들의 수는 : %d\n", count);

	return 0;
}

02


EOF를 만날 때까지 입력을 문자들의 스트림으로 읽는 프로그램을 작성하라. 프로그램은 각각의 입력 문자와 그것의 10진 ASCII 값을 출력해야 한다. ASCII 시퀸스에서 스페이스 문자보다 앞에 오는 문자들은 출력되지 않는 문자들이다. 그러므로 그들은 특별하게 처리해야 한다. 출력되지 않는 문자가 개행 또는 탭이면 \n 또는 \t로 출력하라. 그 밖에 경우에는 제어 문자 표기를 사용하라. 예를 들어 ASCII 1은 [Ctrl+A]인데, ^A로 출력할 수 있다. A의 ASCII 값은 [Ctrl+A]의 값에 64를 더한 값이다. 출력되지 않는 다른 문자들에도 같은 논리가 적용된다. 라인당 열 쌍을 출력하라. 다만 개행 문자를 만났을 때에는 새로운 라인을 시작하라. (주의: 운영체제는 일부 제어 문자들(control characters)에 대한 특별한 해석을 하여 프로그램에 도달하지 못하게 할 수도 있다.)

#include <stdio.h>
#include <ctype.h>

int main(void)
{
	int line_cnt = 0;
	int ch;

	while ((ch = getchar()) != EOF)
	{
		if(ch == '\n')
		{
			printf("\\n : %3d, \n", ch);
			line_cnt = 0;
			continue;
		}
		else if(ch == '\t')
		{
			printf("\t : %3d, ", ch);
		}
		else if(ch <= 26)
		{
			printf("^%c : %3d, ", (ch + 64), ch);
		}
		else
		{
			printf(" %c : %3d, ", ch, ch);
		}

		line_cnt++;
		if(line_cnt / 10)
			printf("\n");
		line_cnt %= 10;
	}

	return 0;
}

03

EOF를 만날 때 까지 입력을 문자들의 스트림으로 읽는 프로그램을 작성하라. 입력에 들어 있는 대문자의 수와 소문자의 수를 출력하라. 소문자와 대문자의 수치값들이 연속적이라고 가정한다. 또는, 좀더 이식성 있게 작성하기 위해, ctype.h 라이브러리에 있는 적절한 분류 함수를 사용할 수 있다.

#include <stdio.h>
#include <ctype.h>

int main(void)
{
	int ch;
	int lower_cnt = 0;
	int upper_cnt = 0;

	while ((ch = getchar()) != EOF)
	{
		if(islower(ch))
			lower_cnt++;

		else if(isupper(ch))
			upper_cnt++;
	}

	printf("\n소문자 수 : %d\n", lower_cnt);
	printf("대문자 수 : %d\n", upper_cnt);

	return 0;
}

04

EOF를 만날 깨까지 입력을 문자들의 스트림으로 읽는 프로그램을 작성하라. 단어당 사용된 평균 글자 수를 출력하라. 화이트 스페이스는 단어 안에 있는 글자로 카운트하지 마라. 실제로는 구두점도 카운트하면 안 된다. 그러나 여기서는 그 문제는 무시하라. 구두점 문제도 해결하고 싶다면, ctype.h 계열에 속한 ispunct() 함수를 사용할 수 있다.

#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>

int main(void)
{	
	int ch;
	int char_cnt = 0;
	int word_cnt = 0;
	bool first_char_flag = true;

	while ((ch = getchar()) != EOF)
	{
		if(!isspace(ch) && !ispunct(ch))
		{
			if(first_char_flag)
				word_cnt++;

			first_char_flag = false;

			char_cnt++;
		}
		else
			first_char_flag = true;
	}

	printf("총 문자 수 : %d\n", char_cnt);
	printf("총 단어 수 : %d\n", word_cnt);
	printf("평균 단어 수 : %.2f\n", ((double)char_cnt / word_cnt));

	return 0;
}

05

리스트 8.4의 수 맞추기 프로그램을 좀더 지능적인 추측 전략을 사용하도록 수정하라. 예를 들어, 처음에 50으로 추측하고, 생각한 수보다 그 추측이 높은지 낮은지 아니면 정확한지 사용자에게 묻는다. 가령, 그 추측이 생각한 수보다 낮다면, 다음 번에는 50과 100 사이의 절반, 즉 75로 추측한다.
다시 그 추측이 높다면, 그 다음번에는 75와 50 사이의 절반으로 추측한다.
이와 같은 2진 검색(binary search) 전략을 사용하면, 사용자가 속이지 않는 한 수를 빨리 맞출 수 있다.

#include <stdio.h>

int main(void)
{
	int guess = 0;
	int max_guess = 100;
	int min_guess = 1;
	char response = 'y';

	guess = (max_guess + min_guess) / 2;

	printf("%d에서 %d까지 범위에 있는 한 정수를 생각하시오.\n", min_guess, max_guess);

	while (response != 'o')
	{
		printf("당신이 생각한 수가 %d보다 큽니까?\n", guess);
		printf("당신이 생각한 수보다 높으면 y로 응답하고,\n");
		printf("낮으면 n으로 응답하시오.\n");
		printf("만약 당신이 생각한 수가 맞으면 o를 입력하시오.\n");

		response = getchar();

		switch(response)
		{
			case 'y':
				min_guess = guess;
				guess = (max_guess + min_guess) / 2;
				break;
			case 'n':
				max_guess = guess;
				guess = (max_guess + min_guess) / 2;
				break;
			case 'o':
				break;
			default:
				printf("미안하지만, (y, n, o)으로만 입력해주시오.\n");
		}
		while (getchar() != '\n')
			continue;
	}

	printf("그것 봐요, 내가 맞출 수 있다고 했잖아요!\n");

	return 0;
}

06

리스트 8.8의 get_first() 함수를, 처음으로 만나는 화이트 스페이스가 아닌 문자를 리턴하도록 수정하라. 간단한 프로그램으로 그것을 테스트 하라.

#include <stdio.h>
#include <ctype.h>

char get_choice(void);
char get_first(void);
int get_int(void);
void count(void);

int main(void)
{
	int choice;

	void count(void);

	while ((choice = get_choice()) != 'q')
	{
		switch (choice)
		{
		case 'a':
			printf("쌀 때 사서 비쌀 때 파시오.\n");
			break;
		case 'b':
			putchar('\a');
			break;
		case 'c':
			count();
			break;
		default:
			printf("프로그램 에러!\n");
			break;
		}
	}
	printf("안녕!\n");

	return 0;
}

void count(void)
{
	int n, i;

	printf("몇까지 카운트 할까요? 정수 하나를 입력하시오:\n");
	n = get_int();
	for(i = 1; i <= n; i++)
		printf("%d\n", i);
	while(getchar()!='\n')
		continue;
}

char get_choice(void)
{
	int ch;

	printf("a,b,c,q 중에서 하나를 선택하시오:\n");
	printf("a. 조언		b. 경고\n");
	printf("c. 카운트	q. 종료\n");

	ch = get_first();

	while ((ch < 'a' || ch > 'c') && ch != 'q')
	{
		printf("a,b,c,q 중에서 하나를 선택해야 합니다.\n");
		ch = get_first();
	}

	return ch;
}

char get_first(void)
{
	int ch;

	while( (ch = getchar()) != '\n' && isspace(ch))
		continue;

	return ch;
}

int get_int(void)
{
	int input;
	char ch;

	while (scanf("%d", &input) != 1)
	{
		while ((ch = getchar()) != '\n')
			putchar(ch);
		printf(": 정수가 아닙니다.\n25, -178, 3과 같은 ");
		printf("정수값을 입력하십시오: ");
	}

	return input;
}

07

7장의 프로그래밍 연습문제(08)을, 메뉴 선택에서 수 대신 문자 레이블을 사용할 수 있도록 수정하라. 입력을 종료하는 신호로 5대신 q를 사용하라.

#include <stdio.h>

#define OVERTIMEPAY 1.5

#define INCOME1 300
#define TAXES1 0.15

#define INCOME2 150
#define TAXES2 0.20

#define TAXES3 0.25

int main(void)
{
	float hourlyWage;
	int playTime;
	float grossPay = 0, taxes = 0, netPay = 0;

	while(1)
	{
		printf("************************************************************\n");
		printf("자신의 기본급에 해당하는 번호를 선택하시오(끝내려면 5번을 선택하시오):\n");
		printf("a) 시간당 $8.75				b) 시간당 $9.33\n");
		printf("c) 시간당 $10.00			d) 시간당 $11.20\n");
		printf("q) 종료\n");
		printf("************************************************************\n");

		char n;
		scanf("%c", &n);
		switch(n)
		{
			case 'a':
				hourlyWage = 8.75;
				break;
			case 'b':
				hourlyWage = 9.33;
				break;
			case 'c':
				hourlyWage = 10.00;
				break;
			case 'd':
				hourlyWage = 11.20;
			case 'q': break;
			default:
				printf("잘못 입력했습니다.\n");
				continue;
		}

		if(n == 'q') break;

		printf("일주일 동안 노동한 시간을 입력해주세요 : \n");
		scanf("%d", &playTime);
	
		grossPay = (playTime > 40 ? 
				(playTime - 40) * OVERTIMEPAY
				: playTime) * hourlyWage;
		
		if(grossPay > INCOME1)
			taxes += INCOME1 * TAXES1;
		else
			taxes += grossPay * TAXES1;
	
		if(grossPay > INCOME1 + INCOME2)
			taxes += (INCOME1 + INCOME2) * TAXES2;
		else
			taxes += (grossPay - INCOME1) * TAXES2;
		
		if(grossPay > INCOME1 + INCOME2)
			taxes += (grossPay - INCOME1 - INCOME2) * TAXES3;
	
		netPay = grossPay - taxes;
	
		printf("총소득 : $%.2f\n", grossPay);
		printf("세금 : $%.2f\n", taxes);
		printf("순이익 : $%.2f\n", netPay);	
	}
	printf("종료!\n");

	return 0;
}

08

덧셈, 뺄셈, 곱셈, 나눗셈을 메뉴에서 선택할 수 있는 프로그램을 작성하라. 사용자가 하나의 연산을 선택하면, 프로그램은 두 수를 입력할 것을 요청하고, 요청받은 연산을 수행해야 한다. 프로그램은 메뉴에서 제시한 선택만을 받아들여야 한다. 또한 수들은 float형을 사용해야 한다.수를 입력하지 않을 때에는 사용자가 다시 입력할 수 있는 기회를 제공해야 한다. 나눗셈의 경우에, 입력된 두 번째 수가 0이면 새로운 수를 다시 입력하라고 사용자를 안내해야 한다. 프로그램의 실행 예는 다음과 같아야 한다.

원하는 연산에 해당하는 문자를 선택하시오(끝내려면 q):
a. add(덧셈)			s.subtract(뺄셈)
m. multiply(곱셈)		d. divide(나눗셈)
q. quit(종료)
a
첫 번째 수를 입력하시오: 22.4
두 번째 수를 입력하시오: one
one: 수가 아닙니다.
2.5, -1.78E8, 3과 같은 수를 입력하시오: 1
22.4 + 1.0 = 23.4
원하는 연산에 해당하는 문자를 선택하시오(끝내려면 q):
a. add(덧셈)			s.subtract(뺄셈)
m. multiply(곱셈)		d. divide(나눗셈)
q. quit(종료)
d
첫 번째 수를 입력하시오: 18.4
두 번째 수를 입력하시오: 0
0이 아닌 다른 수를 입력하시오: 0.2
18.4 / 0.2 = 92.0
원하는 연산에 해당하는 문자를 선택하시오(끝내려면 q):
a. add(덧셈)			s.subtract(뺄셈)
m. multiply(곱셈)		d. divide(나눗셈)
q. quit(종료)
q
종료!

코드

#include <stdio.h>
#include <ctype.h>

float get_number(int );
void print_chart(void);


int main(void)
{
	char ch;
	float left_num = 0.0f;
	float right_num = 0.0f;
	float result = 0.0f;

	for(print_chart(); (ch = getchar()) != 'q'; print_chart())
	{

		left_num = get_number(1);
		right_num = get_number(2);
		
		switch(ch)
		{
		case 'a':
			result = left_num + right_num;
			printf("%.1f + %.1f = %.1f\n", left_num, right_num ,result);
			break;
		case 's':
			result = left_num - right_num;
			printf("%.1f - %.1f = %.1f\n", left_num, right_num ,result);
			break;
		case 'm':
			result = left_num * right_num;
			printf("%.1f * %.1f = %.1f\n", left_num, right_num ,result);
			break;
		case 'd':
			while(right_num == 0)
			{
				printf("0이 아닌 다른 수를 입력하시오.\n");
				right_num = get_number(2);
			}
			result = left_num / right_num;
			printf("%.1f / %.1f = %.1f\n", left_num, right_num ,result);
			break;
		}
	}
	printf("종료!\n");

	return 0;
}

float get_number(int mode)
{
	float num = 0;
	int check = 0;

	while(check != 1)
	{
		switch(mode)
		{
		case 1:
			printf("첫 번째 ");
			break;
		case 2:
			printf("두 번째 ");
			break;
		}
	
		printf("수를 입력하세요 : ");
	
		check = scanf("%f", &num);

		if(check == 0)
		{
			printf("다시 입력해 주세요.\n");
			printf("2.5, -1.78E8, 3과 같은 수를 입력해주세요.\n");
			while(getchar() != EOF)
				continue;
		}
	}
	while(getchar() != '\n')
		continue;

	return num;
}

void print_chart(void)
{
	printf("원하는 연산에 해당하는 문자를 선택하시오(끝내려면 q):\n");
	printf("a. add(덧셈)			s.subtract(뺄셈)\n");
	printf("m. multiply(곱셈)		d. divide(나눗셈)\n");
	printf("q. quit(종료)\n");
	printf("입력 : ");
}

0개의 댓글