C prime plus 第六版 課後程式設計練習 第8章

2020-08-10 00:36:35

C prime plus 第六版 課後程式設計練習 第8章


電子版C primer plus 第6版 中文文字版下載地址
https://blog.csdn.net/gouqi426/article/details/106412212

以下爲課後練習。
使用編譯器 vs 2013 。
如使用其他編譯器,可將scanf_s()修改爲scanf(),同時刪除sizeof()。具體原因請學習scanf_s()和scanf()的區別。

下面 下麪的一些程式要求輸入以EOF終止。如果你的操作系統很難或根本無法使用重定向,請使用一些其他的測試來終止輸入,如讀到&字元時停止。

8.11.1.設計一個程式,統計在讀到檔案結尾之前讀取的字元數。

EOF相關知識見課本8.3.2 第220頁。EOF定義在stdio.h中,返回值爲-1.
getchar()函數返回值通常介於0-127,擴充套件字元集爲0-255,無論哪種情況,-1都不對應任何字元,所以EOF可以用於標記檔案結尾。

// 8.11.1 統計字元數.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"

int _tmain()
{
	char ch;
	int i_count = 0;					//計數器
	printf("Please input some words.\n");

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

	printf("There are %d characters!\n", i_count);

	return 0;
}

在这里插入图片描述

8.11.2 編寫一個程式,在遇到 EOF 之前,把輸入作爲字元流讀取。程式要列印每個輸入的字元及其相應的ASCII十進制值。注意,在ASCII序列中,空格字元前面的字元都是非列印字元,要特殊處理這些字元。如果非列印字元是換行符或製表符,則分別列印\n或\t。否則,使用控制字元表示法。例如,ASCII的1是Ctrl+A,可顯示爲^A。注意,A的ASCII值是Ctrl+A的值加上64。其他非列印字元也有類似的關係。除每次遇到換行符列印新的一行之外,每行列印10對值。(注意:不同的操作系統其控制字元可能不同。)

ASCII碼錶 碼表可在本網站搜尋,此處不提供。

// 8.11.2 列印字元及ASCII碼.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"

int _tmain()
{
	
	char c_ch = 0;
	int i_char = 0;						//計數器,控制每行列印個數
	
	printf("Please enter some character:\n");

	while ((c_ch = getchar()) != EOF)	//輸入的不爲EOF,則進入回圈
	{
		i_char++;						//每讀取一個字元 計數器加1
		
		if (c_ch < ' ')					//在ASCII序列中,空格字元前面的字元都是非列印字元,此分支處置非列印字元
		{
			if (c_ch == '\t')			//
			{
				putchar('\\');
				putchar('t');
				printf(":%3d ", c_ch);	//列印ascii碼,%3d中的3用途是控制字長爲3位數,可以保證對齊,增加美觀。
			}
			else if (c_ch == '\n')
			{
				putchar('\\');
				putchar('n');
				printf(":%3d ", c_ch);
			}
			else
			{
				putchar('^');
				putchar(c_ch + 64);
				printf(":%3d ", c_ch);
			}
			
		}
		else
		{
			putchar(c_ch);
			printf(":%3d ", c_ch);
		}
		if (i_char % 10 == 0)				//每行列印10對,強制換行。
		{
			printf("\n");
		}

	}
		return 0;
}

在这里插入图片描述

8.11.3.編寫一個程式,在遇到 EOF 之前,把輸入作爲字元流讀取。該程式要報告輸入中的大寫字母和小寫字母的個數。假設大小寫字母數值是連續的。或者使用ctype.h庫中合適的分類函數更方便。

ctype.h相關內容見教材7.2.2

// 8.11.3 字母個數.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"
#include <ctype.h>

int _tmain()
{
	char c_ch;
	int i_low = 0;
	int i_cap = 0;

	printf("Please input some character:\n");

	while ((c_ch =getchar())!=EOF)
	{
		if (islower(c_ch))
			i_low++;

		else if (isupper(c_ch))
			i_cap++;
	}
	
	printf("There are %d uppercase letters and %d Lowercase letters.\n", i_cap, i_low);
	
	return 0;
}

在这里插入图片描述

4.編寫一個程式,在遇到EOF之前,把輸入作爲字元流讀取。該程式要報告平均每個單詞的字母數。不要把空白統計爲單詞的字母。實際上,標點符號也不應該統計,但是現在暫時不同考慮這麼多(如果你比較在意這點,考慮使用ctype.h系列中的ispunct()函數)。

可以參考教材7.4 中的程式清單7.7
需要注意解決的幾個問題

  1. 輸入開頭爲非字母字元,如空格、標點符號,數位等
  2. 單詞中間存在連續空格或非字母字元
  3. 阿拉伯數位如何處理。
// 8.11.4 平均字母數.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"
#include <ctype.h>

int _tmain()
{
	char c_ch;								//讀入的字元
	char c_prev=' ';						//讀入的前一個字元
	int i_word = 0;							//單詞數
	int i_alph = 0;						   //總字母數
	
	double d_avrg = 0.0;					//平均數
	
	printf("Please input text to be analyzed:\n");

	while (c_ch = getchar())				//清理輸入開頭處的非字母字元,如空格、標點等
	{
		if (isalpha(c_ch))					//如果字元爲字母則跳出回圈,到下一步,不是則繼續回圈至爲字母
			break;
	}

	while (c_ch != EOF)
	{
		if (isalpha(c_ch))				//本字元爲字母,字母數加1
		{
			i_alph++;
		}
		else if (isspace(c_ch))					 // 本字元是空格
		{
			;
		}
		c_prev = c_ch;					//將本字元賦值給前字元後繼續處理字元流 
		c_ch = getchar();
		
		if (!isalpha(c_ch) && isalpha(c_prev))  //本字元不是字母,前字元是字母
		{
			i_word++;							//單詞數加1
		}
	}
		
	d_avrg = (double)i_alph / i_word;

	printf("Total words:\t\t%d,\nTotal characters:\t%d,\nCharacters per word:\t%.2lf\n", i_word, i_alph, d_avrg);
}

在这里插入图片描述

8.11.5.修改程式清單8.4的猜數位程式,使用更智慧的猜測策略。例如,程式最初猜50,詢問使用者是猜大了、猜小了還是猜對了。如果猜小了,那麼下一次猜測的值應是50和100中值,也就是75。如果這次猜大了,那麼下一次猜測的值應是50和75的中值,等等。使用二分查詢(binary search)策略,如果使用者沒有欺騙程式,那麼程式很快就會猜到正確的答案。

// 8.11.5 猜數位.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"
#include <ctype.h>

int _tmain()
{
	char c_chyn;				//讀取Y/N輸入
	char c_chbs;			//讀取B/S輸入
	int i_upper = 100;			//上限
	int i_lower = 0;			//下限

	int i_guess = 50;				//初值

	printf("Pick an integer from 1 to 100. I will try to guess ");
	printf("it.\nRespond with a y or Y if my guess is right and with");
	printf("\nan n or N if it is wrong.\n");
	printf("Uh...is your number %d (Y/N)?\n", i_guess);

	scanf_s("%c", &c_chyn,1);
	c_chyn = toupper(c_chyn);
	getchar();
	//printf("%c\n",c_chyn);		//覈對輸入數據

	while (c_chyn != 'Y')	 // 獲取響應,與 Y 做對比 
	{
		printf("Well,the number you chosen is bigger or smaller than I guess?(B/S)\n");

		scanf_s("%c", &c_chbs,1);
		c_chbs = toupper(c_chbs);
		getchar();
		
		if (c_chbs == 'B')
		{
			i_lower = i_guess;
			i_guess = (i_lower + i_upper) / 2;
		}
		else
		{
			i_upper = i_guess;
			i_guess = (i_lower + i_upper) / 2;
		}
		printf("Uh...is your number %d, (Y/N)?\n", i_guess);

		scanf_s("%c", &c_chyn,1);
		c_chyn = toupper(c_chyn);
		getchar(); 
	}
	
	printf("I knew I could do it!\n");
	return 0;
}

在这里插入图片描述在这里插入图片描述

8.11.6 修改程式清單8.8中的get_first()函數,讓該函數返回讀取的第1個非空白字元,並在一個簡單的程式中測試。

// 8.11.6 返回非空白字元.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"
#include <ctype.h>

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

int _tmain()
{
	int choice;
	void count(void);
	while ((choice = get_choice()) != 'q')
	{
		switch (choice)
		{
		case 'a': printf("Buy low, sell high.\n");
			break;
		case 'b': putchar('\a');  /* ANSI */
			break;
		case 'c':  count();
			break;
		default:  printf("Program error!\n");
			break;
		}
	}
	printf("Bye.\n");
	return 0;
}
void count(void)
{
	int n, i;
	printf("Count how far? Enter an integer:\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("Enter the letter of your choice:\n");
	printf("a. advice       b. bell\n");
	printf("c. count        q. quit\n");
	ch = get_first();
	while ((ch < 'a' || ch > 'c') && ch != 'q')
	{
		printf("Please respond with a, b, c, or q.\n");
		ch = get_first();
	}
	return ch;
}
char get_first(void)
{
	int ch;
	while (!isalpha(ch = getchar()))
	{
		continue;
	}
		
	return ch;
}
int get_int(void)
{
	int input;
	char ch;
	while (scanf_s("%d", &input,sizeof(input)) != 1)
	{
		while ((ch = getchar()) != '\n')
			putchar(ch); // 處理錯誤輸出
		printf(" is not an integer.\nPlease enter an ");
		printf("integer value, such as 25, -178, or 3: ");
	}
	return input;
}

8.11.7修改第7章的程式設計練習8,用字元代替數位標記選單的選項。用q代替5作爲結束輸入的標記。

// 8.11.7 字元代替數位標記選單選項.cpp : 定義控制檯應用程式的入口點。

/*
7.12.8.修改練習7的假設a,讓程式可以給出一個供選擇的工資等級選單。使用switch完成工資等級選擇。執行程式後,顯示的選單應該類似這樣:**************************************************************
Enter the number corresponding to the desired pay rate or action:
1) $8.75/hr              2) $9.33/hr
3) $10.00/hr             4) $11.20/hr
5) quit
**************************************************************
如果選擇 1~4 其中的一個數字,程式應該詢問使用者工作的小時數。程式要通過回圈執行,除非使用者輸入 5。如果輸入 1~5 以外的數位,程式應提醒使用者輸入正確的選項,然後再重複顯示選單提示使用者輸入。使用#define建立符號常數表示各工資等級和稅率。

*/

#include "stdafx.h"
#include <ctype.h>

#define BSTIME 40
#define MTP 1.5

#define RATE1 0.15
#define RATE2 0.20
#define RATE3 0.25

#define LINE1 300
#define LINE2 150

#define INCOME_PER_HR1 8.75
#define INCOME_PER_HR2 9.33
#define INCOME_PER_HR3 10.00
#define INCOME_PER_HR4 11.20

int _tmain()
{
	double d_wktime = 0;
	double d_money_t = 0;
	double d_money_l = 0;
	double d_tax = 0;
	double INCOME_PER_HR = 0;
	int i_chs = 0;
	int i_count;

	for (i_count = 0; i_count <= 65; i_count++)
	{
		putchar('*');
	}
	printf("\nEnter the letter corresponding to the desired pay rate or action:\n");
	printf("a) $8.75/hr\tb) $9.33/hr\n");
	printf("c) $10.00/hr\td) $11.20/hr\n");
	printf("q) quit\n");
	for (i_count = 0; i_count <= 65; i_count++)
	{
		putchar('*');
	}
	printf("\n");
	
	i_chs=getchar();

	while (isalpha(i_chs))
	{
		switch (i_chs)
		{
		case 'a':
			INCOME_PER_HR = INCOME_PER_HR1;
			break;
		case 'b':
			INCOME_PER_HR = INCOME_PER_HR2;
			break;
		case 'c':
			INCOME_PER_HR = INCOME_PER_HR3;
			break;
		case 'd':
			INCOME_PER_HR = INCOME_PER_HR4;
			break;
		}

		if (i_chs == 'a' || i_chs == 'b' || i_chs == 'c' || i_chs == 'd')
		{
			printf("Your desired pay rate is $ %.2f/hr.\n", INCOME_PER_HR);
			printf("Please enter how long you work perweek:\n");
			
			scanf_s("%lf", &d_wktime, 3);
			getchar();

			if (d_wktime <= BSTIME)
				d_money_t = d_wktime*INCOME_PER_HR;
			else
				d_money_t = BSTIME*INCOME_PER_HR + (d_wktime - BSTIME)*MTP*INCOME_PER_HR;
			if (d_money_l <= LINE1)
				d_tax = d_money_t*RATE1;
			else if (d_money_t <= (LINE2 + LINE1))
				d_tax = LINE1*RATE1 + (d_money_t - LINE1)*RATE2;
			else
				d_tax = LINE1*RATE1 + LINE2*RATE2 + (d_money_t - LINE1 - LINE2)*RATE3;

			d_money_l = d_money_t - d_tax;
			printf("Total income \t%.2f $ \nTax \t\t%.2f $ \nNet income \t%.2f $.\n", d_money_t, d_tax, d_money_l);
			
			i_chs = getchar();
		}
		else if (i_chs == 'q')	//輸入5跳出回圈 
			break;
		else
			printf("Incorrect input,please choose an option above!\n");
		continue;
	}
	printf("BYE.\n");
	return 0;
}

8.11.88.編寫一個程式,顯示一個提供加法、減法、乘法、除法的選單。獲得使用者選擇的選項後,程式提示使用者輸入兩個數位,然後執行使用者剛纔選擇的操作。該程式只接受選單提供的選項。程式使用float型別的變數儲存使用者輸入的數位,如果使用者輸入失敗,則允許再次輸入。進行除法運算時,如果使用者輸入0作爲第2個數(除數),程式應提示使用者重新輸入一個新值。該程式的一個執行範例如下:

Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
a
Enter first number: 22.4
Enter second number: one
one is not an number.
Please enter a number, such as 2.5, -1.78E8, or 3: 1
22.4 + 1 = 23.4
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
d
Enter first number: 18.4
Enter second number: 0
Enter a number other than 0: 0.2
18.4 / 0.2 = 92
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quit
q
Bye.

// 8.11.8 加減乘除.cpp : 定義控制檯應用程式的入口點。

#include "stdafx.h"
//#include <ctype.h>

char choose(void);
float number(void);
float add(float a, float b);
float multip(float a, float b);
float subtr(float a, float b);
float divide(float a, float b);

int _tmain(void)
{
	float f_num1 = 0;			//輸入的第一個數位
	float f_num2 = 0;			//輸入的第2個數字
	float f_result = 0;			//計算結果
	char c_chos = 0;
	char c_calc = 0;			//運算子

	while ((c_chos = choose()) != 'q')
	{
		printf("Enter first number:");
		f_num1 = number();

		printf("Enter second number:");
		f_num2 = number();

		switch (c_chos)
		{
		case 'a':
			f_result = add(f_num1, f_num2);
			c_calc = '+';
			break;
		case 'm':
			f_result = multip(f_num1, f_num2);
			c_calc = '*';
			break;
		case 's':
			f_result = subtr(f_num1, f_num2);
			c_calc = '-';
			break;
		case 'd':
			if (f_num2 == 0)									//處理除數爲0的情況,數學規則,除數不能爲0
			{
				printf("Enter a number other than 0:");
				scanf_s("%f", &f_num2, sizeof(f_num2));
			}
			f_result = divide(f_num1, f_num2);
			c_calc = '/';
			break;
		}
		
		printf("%.1f %c %.1f = %.1f.\n\n", f_num1, c_calc,f_num2, f_result);		//爲了輸出結果更直觀,有區分,此處使用2個換行符,增加一行空行

		while (getchar() != '\n');					
	}
	printf("Bye!\n");

	return 0;

}

char choose(void)									//選擇函數,從5個選項中進行選擇,5個以外的其他選項進行提示重選
{
	char chos;

	printf("Enter the operation of your choose:\n");
	printf("a.add \t\t s.subtract\n");				//使用製表符對齊
	printf("m.multiply \t d.divide\n");
	printf("q.quit\n");

	while ((chos = getchar()) && chos != 'a' && chos != 'm' && chos != 's' && chos != 'd' && chos != 'q')
	{
		printf("Please enter again, enter a, m, s, d or q:");
		while (getchar() != '\n');
	}

	return chos;
}


float number(void)
{
	float f_num;
	char num;
		
	while (scanf_s("%f", &f_num, sizeof(f_num)) != 1)  //當輸入非數位時,scanf_s()不會讀取,會放在輸入快取等待讀取,就可以用下面 下麪的getchar來讀取這個字元 
	{
		while ((num = getchar()) != '\n')
			putchar(num);
		printf(" is not an number.\n");
		printf("Please enter a number, such as 2.5, -1.78E8, or 3:");
	}

	return f_num;
}


float add(float a, float b)
{
	float sum;

	sum = a + b;

	return sum;
}

float multip(float a, float b)
{
	float multi;

	multi = a * b;

	return multi;
}

float subtr(float a, float b)
{
	float sub;

	sub = a - b;

	return sub;
}

float divide(float a, float b)
{
	float div;

	div = a / b;

	return div;
}

程式碼執行結果與範例基本一致,存在的問題是,因要求輸入數位爲float,故在列印時,即便輸入爲整數,列印也帶小數,無法做到與範例完全一致。