C Primer Plus 第六版 编程练习题及详细答案

本文包含书中所有章节末尾的编程练习题及答案代码

注:两份答案,第一份为官方标准答案(部分题目官方并未提供答案),第二份为我个人学习编写,如有错漏欢迎指正。

第一章

1.1

你刚被MacroMuscle有限公司聘用。该公司准备进入欧洲市场,需要一个把英寸单位转换为厘米单位(1 英寸=2.54 厘米)的程序。该程序要提示用户输入英寸值。你的任务是定义程序目标和设计程序(编程过程的第1步和第2步)。

#include <stdio.h>//个人
int main(void)
{
	float inch;
	printf("英寸单位转厘米单位\n");
	printf("请输入英寸值:");
	scanf_s("%f",&inch);
	printf("%f英寸等于%f厘米\n",inch,inch*2.54);
	return 0;
}

第二章

2.1

编写一个程序,调用一次 printf函数,把你的姓名打印在一行。再调用一次 printf函数,把你的姓名分别打印在两行。然后,再调用两次printf函数,把你的姓名打印在一行。输出应如下所示(当然要把示例的内容换成你的姓名):

/* Programming Exercise 2-1  */ 
#include <stdio.h> 
int main(void) 
{ 
    printf("Gustav Mahler\n"); 
    printf("Gustav\nMahler\n"); 
    printf("Gustav "); 
    printf("Mahler\n"); 
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	printf("姓	名\n");
	printf("姓\n名\n");
	printf("姓	");
	printf("名\n");
	return 0;
}

2.2

编写一个程序,打印你的姓名和地址。

#include <stdio.h>//个人
int main(void)
{
	printf("姓	名:×××\n");
	printf("地	址:×××××××××\n");
	return 0;
}

2.3

编写一个程序把你的年龄转换成天数,并显示这两个值。这里不用考虑闰年的问题。

不考虑具体月份及闰年版

/* Programming Exercise 2-3  */ 
#include <stdio.h> 
int main(void) 
{ 
    int ageyears;    /* age in years */ 
    int agedays;    /* age in days  */ 
                    /* large ages may require the long type */ 
    ageyears = 101; 
    agedays = 365 * ageyears; 
    printf("An age of %d years is %d days.\n", ageyears, agedays); 
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	int age;
	printf("请输入你的年龄:");
	scanf_s("%d",&age);
	printf("你已存活%d天\n",age*365);
	return 0;
}

2.4

编写一个程序,生成以下输出:

For he's a jolly good fellow!

For he's a jolly good fellow!

For he's a jolly good fellow!

Which nobody can deny!

除了 main函数以外,该程序还要调用两个自定义函数:一个名为 jolly,用于打印前 3 条消息,调用一次打印一条;另一个函数名为deny,打印最后一条消息。

/* Programming Exercise 2-4  */ 
#include <stdio.h> 
void jolly(void); 
void deny(void); 
int main(void) 
{ 
    jolly(); 
    jolly(); 
    jolly(); 
    deny(); 
    return 0; 
} 
void jolly(void) 
{ 
    printf("For he's a jolly good fellow!\n"); 
} 
void deny(void) 
{ 
    printf("Which nobody can deny!\n"); 
}
#include <stdio.h>//个人
void jolly(void);
void deny(void);
int main(void)
{
	jolly();
	jolly();
	jolly();
	deny();
	return 0;
}
void jolly(void)
{
	printf("For he's a jolly good fellow!\n");
	//因为他是一个快乐的家伙!
}
void deny(void)
{
	printf("Which nobody can deny!\n");
	//没有人可以否认!
}

2.5

编写一个程序,生成以下输出:

Brazil, Russia, India, China

India, China,

Brazil, Russia

除了main以外,该程序还要调用两个自定义函数:一个名为br,调用一次打印一次“Brazil, Russia”;另一个名为ic,调用一次打印一次“India, China”。其他内容在main函数中完成。

#include <stdio.h>//个人
void br(void);
void ic(void);
int main(void)
{
	br();
	printf(",");
	ic();
	printf("\n");
	ic();
	printf(",\n");
	br();
	return 0;
}
void br(void)
{
	printf("Brazil, Russia");
}
	//巴西,俄罗斯
void ic(void)
{
	printf("India, China");
	//印度,中国
}

2.6

编写一个程序,创建一个整型变量toes,并将toes设置为10。程序中还要计算toes的两倍和toes的平方。该程序应打印3个值,并分别描述以示区分。

/* Programming Exercise 2-6  */ 
#include <stdio.h> 
int main(void) 
{ 
    int toes; 
     
    toes = 10; 
     
    printf("toes = %d\n", toes); 
    printf("Twice toes = %d\n", 2 * toes); 
    printf("toes squared = %d\n", toes * toes); 
    return 0; 
} 
/* or create two more variables, set them to 2 * toes and toes * toes */
#include <stdio.h>//个人
int main(void)
{
	int toes = 10;
	printf("toes为%d,其两倍为%d,其平方为%d\n",toes,toes*2,toes*toes);
	return 0;
}

2.7

许多研究表明,微笑益处多多。编写一个程序,生成以下格式的输出:

Smile!Smile!Smile!

Smile!Smile!

Smile!

该程序要定义一个函数,该函数被调用一次打印一次“Smile!”,根据程序的需要使用该函数。

#include <stdio.h>//个人
void smile(void);
int main(void)
{
	for (int i = 3; i >= 1; i--)
	{
		for (int j=1;j<=i;j++)
			smile();
		printf("\n");
	}
	return 0;
}
void smile(void)
{
	printf("Smile!");//微笑
}

2.8

在C语言中,函数可以调用另一个函数。编写一个程序,调用一个名为one_three的函数。该函数在一行打印单词“one”,再调用第2个函数two,然后在另一行打印单词“three”。two函数在一行显示单词“two”。main函数在调用 one_three函数前要打印短语“starting now:”,并在调用完毕后显示短语“done!”。因此,该程序的输出应如下所示:

starting now:

one

two

three

done!

/* Programming Exercise 2-8  */ 
#include <stdio.h> 
void one_three(void); 
void two(void); 
int main(void) 
{ 
printf("starting now:\n"); 
one_three(); 
printf("done!\n"); 
return 0; 
} 
void one_three(void) 
{ 
printf("one\n"); 
two(); 
printf("three\n"); 
} 
void two(void) 
{ 
printf("two\n"); 
}
#include <stdio.h>//个人
void one_three(void);
void tow(void);
int main(void)
{
	printf("starting now:\n");//从现在开始:
	one_three();
	printf("done!\n");//完毕!
	return 0;
}
void one_three(void)
{
	printf("one\n");
	tow();
	printf("three\n");
}
void tow(void)
{
	printf("two\n");
}

第三章

3.1

通过试验(即编写带有此类问题的程序)观察系统如何处理整数上溢、浮点数上溢和浮点数下溢的情况。

#include <stdio.h>//个人
int main(void)
{
	int big = 2147483648;
	printf("%d	整数上溢\n",big);//整数上溢(从最小值开始循环)
	float tooBig = 3.4E38 * 100.0f,tooSmall=0.1234E-10;
	printf("%e		浮点数上溢\n", tooBig);//浮点数上溢(无穷)
	printf("%e	浮点数下溢?\n",tooSmall/10);//浮点数下溢?
	return 0;
}

3.2

编写一个程序,要求提示输入一个ASCII码值(如,66),然后打印输入的字符。

/* Programming Exercise 3-2  */ 
#include <stdio.h> 
int main(void) 
{ 
int ascii; 
printf("Enter an ASCII code: "); 
scanf("%d", &ascii); 
printf("%d is the ASCII code for %c.\n", ascii, ascii); 
return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	while (1)
	{
		char a;
		printf("请输入一个ASCII码值(0-127):");
		scanf_s("%d", &a);
		printf("%d对应的字符为%c\n\n", a, a);
	}
	return 0;
}

3.3

编写一个程序,发出一声警报,然后打印下面的文本:

Startled by the sudden sound, Sally shouted,

"By the Great Pumpkin, what was that!"

#include <stdio.h>//个人
int main(void)
{
	printf("\aStartled by the sudden sound, Sally shouted,\n\"By the Great Pumpkin, what was that!\"");
	//printf双引号内不能打回车
	return 0;
}

3.4

编写一个程序,读取一个浮点数,先打印成小数点形式,再打印成指数形式。然后,如果系统支持,再打印成p记数法(即十六进制记数法)。按以下格式输出(实际显示的指数位数因系统而异):

Enter a floating-point value: 64.25

fixed-point notation: 64.250000

exponential notation: 6.425000e+01

p notation:0x1.01p+6

/* Programming Exercise 3-4  */ 
#include <stdio.h> 
int main(void) 
{ 
float num; 
printf("Enter a floating-point value: "); 
scanf("%f", &num); 
printf("fixed-point notation: %f\n", num); 
printf("exponential notation: %e\n", num); 
printf("p notation: %a\n", num); 
return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	float a;
	printf("Enter a floating-point value:");//输入浮点值:
	scanf_s("%f",&a);
	printf("fixed-point notation: %f\n",a);//小数点表示法
	printf("exponential notation: %e\n", a);//指数表示法
	printf("p notation:%a\n", a);//p 表示法
	return 0;
}

3.5

一年大约有 3.156×10^7秒。编写一个程序,提示用户输入年龄,然后显示该年龄对应的秒数。

#include <stdio.h>//个人
int main(void)
{
	float second=3.156e7;
	int a;
	printf("请输入你的年龄:");
	scanf_s("%d",&a);
	printf("你已存活%e秒\n",second*a);
	return 0;
}

3.6

1个水分子的质量约为3.0×10^-23克。1夸脱水大约是950克。编写一个程序,提示用户输入水的夸
脱数,并显示水分子的数量。

/* Programming Exercise 3-6  */ 
#include <stdio.h> 
int main(void) 
{ 
    float mass_mol = 3.0e-23;    /* mass of water molecule in grams */ //水分子质量(克)
    float mass_qt = 950;        /* mass of quart of water in grams */ //夸脱水的质量(克)
    float quarts; 
    float molecules; 
     
    printf("Enter the number of quarts of water: "); 
    //输入水的夸脱数
    scanf("%f", &quarts); 
    molecules = quarts * mass_qt / mass_mol; 
    printf("%f quarts of water contain %e molecules.\n", quarts, molecules); 
    //%f 夸脱水含有 %e 分子。
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	long double water = 3.0e-23;
	float quart;
	printf("请输入夸脱数:");
	scanf_s("%f", &quart);
	printf("%f夸脱水中有%e个水分子\n", quart, quart * 950 / water);
	return 0;
}

3.7

1 英寸相当于2.54厘米。编写一个程序,提示用户输入身高 (/英寸),然后以厘米为单位显示身高。

#include <stdio.h>//个人
int main(void)
{
	float height;
	printf("请输入你的身高(英寸):");
	scanf_s("%f",&height);
	printf("你的身高为%.2f厘米\n",height*2.54);
	return 0;
}

3.8

在美国的体积测量系统中,1品脱等于2杯,1杯等于8盎司,1盎司等于2大汤勺,1大汤勺等于
3 茶勺。编写一个程序,提示用户输入杯数,并以品脱、盎司、汤勺、茶勺为单位显示等价容量。
思考对于该程序,为何使用浮点类型比整数类型更合适?

#include <stdio.h>//个人
int main(void)
{
	float cup;
	printf("请输入你杯数:");
	scanf_s("%f",&cup);
	printf("%.2f杯等同于%.2f品脱\n",cup,cup/2);
	printf("%.2f杯等同于%.2f盎司\n", cup, cup * 8);
	printf("%.2f杯等同于%.2f大汤勺\n", cup, cup * 16);
	printf("%.2f杯等同于%.2f茶勺\n", cup, cup * 48);
	return 0;
}

第四章

4.1

编写一个程序,提示用户输入名和姓,然后以“名,姓”的格式打印出来。

/* Programming Exercise 4-1  */ 
#include <stdio.h> 
int main(void) 
{ 
    char fname[40]; 
    char lname[40]; 
     
    printf("Enter your first name: "); 
    scanf("%s", fname); 
    printf("Enter your last name: "); 
    scanf("%s", lname); 
    printf("%s, %s\n", lname, fname); 
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	char surname[10], name[10];
	scanf_s("%s",surname,10);
	scanf_s("%s", name,10);
	printf("%s,%s\n",surname,name);
	return 0;
}

4.2

编写一个程序,提示用户输入名和姓,并执行以下操作:

a.打印名和姓,包括双引号;

b.在宽度为20的字段右端打印名和姓,包括双引号;

c.在宽度为20的字段左端打印名和姓,包括双引号;

d.在比姓名宽度宽3的字段中打印名和姓。

#include <stdio.h>//个人
#include <string.h>
int main(void)
{
	char surname[10] = { 0 }, name[10] = { 0 };
	printf("请输入你的姓氏:");
	scanf_s("%s",surname,10);
	printf("请输入你的名字:");
	scanf_s("%s", name,10);
	int a=strlen(surname), b=strlen(name);
	printf("\"%s,%s\"\n",surname,name);
	printf("\"%20s,%20s\"\n", surname, name);
	printf("\"%-20s,%-20s\"\n", surname, name);
	printf("%*s,%*s\n", a+3,surname, b+3,name);
	printf("%zd	%zd", strlen(surname),strlen(name));
	return 0;
}

4.3

编写一个程序,读取一个浮点数(21.29),首先以小数点记数法打印,然后以指数记数法打印。用下面的格式进行输出(系统不同,指数记数法显示的位数可能不同):

a.The input is 21.3 or 2.1e+001.

b.The input is +21.290 or 2.129E+001.

#include <stdio.h>//个人
int main(void)
{
	float a;
	printf("请输入浮点数:");//21.29
	scanf_s("%f",&a);
	printf("The input is %.1f or %1.1e.\n",a,a);
	printf("The input is %+2.3f or %1.3E.\n",a,a);
	return 0;
}

4.4

编写一个程序,提示用户输入身高(单位:英寸)和姓名,然后以下面的格式显示用户刚输入的信息:

Dabney, you are 6.208 feet tall

使用float类型,并用/作为除号。如果你愿意,可以要求用户以厘米为单位输入身高,并以米为单位显示出来。

/* Programming Exercise 4-4 */ 
#include <stdio.h> 
int main(void) 
{ 
    float height; 
    char name[40]; 
     
    printf("Enter your height in inches: "); 
    scanf("%f", &height); 
    printf("Enter your name: "); 
    scanf("%s", name); 
    printf("%s, you are %.3f feet tall\n", name, height / 12.0); 
     
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	char name[20];
	float tall;
	printf("请输入你的姓名:");
	scanf_s("%s",name,20);
	printf("请输入你的身高(厘米):");
	scanf_s("%f",&tall);
	printf("%s,你的身高是%.3f米\n",name,tall/100);
	return 0;
}

4.5

编写一个程序,提示用户输入以兆位每秒(Mb/s)为单位的下载速度和以兆字节(MB)为单位的文件大小。程序中应计算文件的下载时间。注意,这里1字节等于8位。使用float类型,并用/作为除号。该程序要以下面的格式打印 3 个变量的值(下载速度、文件大小和下载时间),显示小数点后面两位数字:

At 18.12 megabits per second, a file of 2.20 megabytes

downloads in 0.97 seconds.

#include <stdio.h>//个人
int main(void)
{
	float speed, size;
	printf("请输入下载速度(Mb/s):");
	scanf_s("%f",&speed);
	printf("请输入文件大小(Mb):");
	scanf_s("%f",&size);
	printf("%.2fMb的文件以%.2fMb/s的速度下载需要%.2f秒。\n",size,speed,size/speed);
	return 0;
}

4.6

编写一个程序,先提示用户输入名,然后提示用户输入姓。在一行打印用户输入的名和姓,下一行分别打印名和姓的字母数。字母数要与相应名和姓的结尾对齐,如下所示:

Melissa Honeybee

          7                8

接下来,再打印相同的信息,但是字母个数与相应名和姓的开头对齐,如下所示:

Melissa Honeybee

7         8

#include <stdio.h>//个人
#include <string.h>
int main(void)
{
	char surname[20] = { 0 }, name[20] = {0};
	int length1, length2;
	printf("请输入姓:");
	scanf_s("%s",surname,20);
	printf("请输入名:");
	scanf_s("%s",name,20);
	length1 = strlen(surname);
	length2 = strlen(name);
	printf("%s %s\n%*d %*d\n",surname,name,length1,length1,length2,length2);
	printf("%s %s\n%-*d %-*d\n", surname, name, length1, length1, length2, length2);
	return 0;
}

4.7

编写一个程序,将一个double类型的变量设置为1.0/3.0,一个float类型的变量设置为1.0/3.0。分别显示两次计算的结果各3次:一次显示小数点后面6位数字;一次显示小数点后面12位数字;一次显示小数点后面16位数字。程序中要包含float.h头文件,并显示FLT_DIG和DBL_DIG的值。1.0/3.0的值与这些值一致吗?

/* Programming Exercise 4-7 */ 
#include <stdio.h> 
#include <float.h> 
int main(void) 
{ 
    float ot_f = 1.0 / 3.0; 
    double ot_d = 1.0 / 3.0; 
    printf(" float values: "); 
    printf("%.4f %.12f %.16f\n", ot_f, ot_f, ot_f); 
    printf("double values: "); 
    printf("%.4f %.12f %.16f\n", ot_d, ot_d, ot_d); 
    printf("FLT_DIG: %d\n", FLT_DIG); 
    printf("DBL_DIG: %d\n", DBL_DIG); 
    return 0; 
} 
#include <stdio.h>//个人
#include <float.h>
int main(void)
{
	float a = 1.0 / 3.0;
	double b = 1.0 / 3.0;
	printf("float:%.6f %.12f %.16f\n",a,a,a);
	printf("double:%.6f %.12f %.16f\n",b,b,b);
	printf("float精确度:%d\n",FLT_DIG);
	printf("double精确度:%d\n", DBL_DIG);
	return 0;
}

4.8

编写一个程序,提示用户输入旅行的里程和消耗的汽油量。然后计算并显示消耗每加仑汽油行驶的英里数,显示小数点后面一位数字。接下来,使用1加仑大约3.785升,1英里大约为1.609千米,把单位是英里/加仑的值转换为升/100公里(欧洲通用的燃料消耗表示法),并显示结果,显示小数点后面 1 位数字。注意,美国采用的方案测量消耗单位燃料的行程(值越大越好),而欧洲则采用单位距离消耗的燃料测量方案(值越低越好)。使用#define 创建符号常量或使用 const 限定符创建变量来表示两个转换系数。

转换系数:将一种单位的测量值转换为另一种单位测量值的数值,用于表达同一个物理量两种不同单位之间的数学关系

#include <stdio.h>//个人
#define GALLON 3.785
#define MILE 1.609
int main(void)
{
	float mileage, gasoline;
	printf("请输入里程数:");
	scanf_s("%f",&mileage);
	printf("请输入所耗汽油量:");
	scanf_s("%f",&gasoline);
	float rate = mileage / gasoline;
	printf("每加仑汽油可供行驶%.1f英里\n",rate);
	printf("每升汽油可供行驶%.1f百公里\n", rate / GALLON * MILE / 100);
	//每加仑行驶英里数 / 加仑到升的转换系数 = 每升行驶英里数
	//每升行驶英里数 / 英里到千米(公里)的转换系数 = 每升行驶千米(公里)数
	return 0;
}

第五章

5.1

编写一个程序,把用分钟表示的时间转换成用小时和分钟表示的时间。使用#define或const创建一个表示60的符号常量或const变量。通过while循环让用户重复输入值,直到用户输入小于或等于0的值才停止循环。

/* Programming Exercise 5-1 */ 
#include <stdio.h> 
int main(void) 
{ 
    const int minperhour = 60; 
    int minutes, hours, mins; 
     
    printf("Enter the number of minutes to convert: "); 
    scanf("%d", &minutes); 
    while (minutes > 0 ) 
    { 
        hours = minutes / minperhour; 
        mins = minutes % minperhour; 
        printf("%d minutes = %d hours, %d minutes\n", minutes, hours, mins); 
        printf("Enter next minutes value (0 to quit): "); 
        scanf("%d", &minutes); 
    } 
    printf("Bye\n"); 
     
    return 0; 
}
#include <stdio.h>//个人
#define HOUR 60
int main(void)
{
	int min;
	printf("请输入分钟数(输入非正数结束):");
	scanf_s("%d", &min);
	while (min>0)
	{
		printf("这是%d:%d\n",min/HOUR,min%HOUR);
		printf("请输入分钟数(输入非正数结束):");
		scanf_s("%d", &min);
	}
	return 0;
}

5.2

编写一个程序,提示用户输入一个整数,然后打印从该数到比该数大10的所有整数(例如,用户输入5,则打印5~15的所有整数,包括5和15)。要求打印的各值之间用一个空格、制表符或换行符分开。

#include <stdio.h>//个人
int main(void)
{
	int number,end;
	printf("请输入一个整数:");
	scanf_s("%d",&number);
	end = number + 10;
	while (number <= end)
	{
		printf("%d\t",number);
		number++;
	}
	return 0;
}

5.3

编写一个程序,提示用户输入天数,然后将其转换成周数和天数。例如,用户输入18,则转换成2周4天。以下面的格式显示结果:

18 days are 2 weeks, 4 days.

通过while循环让用户重复输入天数,当用户输入一个非正值时(如0或-20),循环结束。

/* Programming Exercise 5-3 */ 
#include <stdio.h> 
int main(void) 
{ 
    const int daysperweek = 7; 
    int days, weeks, day_rem; 
     
    printf("Enter the number of days: "); 
    scanf("%d", &days); 
    while (days > 0) 
    { 
        weeks = days / daysperweek; 
        day_rem = days % daysperweek; 
        printf("%d days are %d weeks and %d days.\n", 
               days, weeks, day_rem); 
     
        printf("Enter the number of days (0 or less to end): "); 
        scanf("%d", &days); 
    } 
    printf("Done!\n"); 
    return 0; 
} 
#include <stdio.h>//个人
#define WEEK 7
int main(void)
{
	int day;
	printf("请输入天数(输入非正数结束):");
	scanf_s("%d",&day);
	while (day>0)
	{
		printf("这是%d周零%d天\n",day/WEEK,day%WEEK);
		printf("请输入天数(输入非正数结束):");
		scanf_s("%d", &day);
	}
	return 0;
}

5.4

编写一个程序,提示用户输入一个身高(单位:厘米),并分别以厘米和英寸为单位显示该值,允许有小数部分。程序应该能让用户重复输入身高,直到用户输入一个非正值。其输出示例如下:

Enter a height in centimeters: 182

182.0 cm = 5 feet, 11.7 inches

Enter a height in centimeters (<=0 to quit): 168.7

168.0 cm = 5 feet, 6.4 inches

Enter a height in centimeters (<=0 to quit): 0

bye

#include <stdio.h>//个人
#define INCH 2.54
int main(void)
{
	float height;
	printf("请输入身高(厘米,输入非正值结束):");
	scanf_s("%f",&height);
	while (height>0)
	{
		printf("%.2f厘米=%.2f英寸\n",height,height/INCH);
		printf("请输入身高(厘米,输入非正值结束):");
		scanf_s("%f", &height);
	}
	return 0;
}

5.5

修改程序addemup.c(程序清单5.13),你可以认为addemup.c是计算20天里赚多少钱的程序(假设第1天赚$1、第2天赚$2、第3天赚$3,以此类推)。修改程序,使其可以与用户交互,根据用户输入的数进行计算(即,用读入的一个变量来代替20)。

//程序清单5.13 addemup.c程序    此非答案而是题目的一部分
/* addemup.c -- 几种常见的语句 */
#include <stdio.h>
int main(void)
{
	int count, sum;
	count = 0;
	sum = 0;
	while (count++ < 20)
		sum = sum + count;
	printf("sum=%d\n", sum);
	return 0;
}
/* Programming Exercise 5-5 */ 
#include <stdio.h> 
int main(void)    /* finds sum of first n integers */ 
{ 
  int count, sum;             
  int n; 
   
  printf("Enter the upper limit: "); 
  scanf("%d", &n); 
  count = 0;                   
  sum = 0;                   
  while (count++ < n) 
     sum = sum + count;  
  printf("sum = %d\n", sum); 
  return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	int day;
	unsigned long long sum = 0, count = 0;
	printf("请输入你的工作天数:");
	scanf_s("%d",&day);
	while (count++ < day)
		sum = sum + count;
	printf("你可以挣%lld¥的财富!\n", sum);
	return 0;
}

5.6

修改编程练习5的程序,使其能计算整数的平方和(可以认为第1天赚$1、第2天赚$4、第3天赚$9,以此类推,这看起来很不错)。C没有平方函数,但是可以用n * n来表示n的平方。

#include <stdio.h>//个人
int main(void)
{
	int day, count = 0;
	unsigned long long sum = 0, income=1;
	printf("请输入你的工作天数:");
	scanf_s("%d",&day);
	while (count++ < day)
	{
		sum += income;
		income *= 2;
	}
	printf("你可以挣%lld¥的财富!\n", sum);
	return 0;
}

5.7

编写一个程序,提示用户输入一个double类型的数,并打印该数的立方值。自己设计一个函数计算并打印立方值。main函数要把用户输入的值传递给该函数。

/* Programming Exercise 5-7 */ 
#include <stdio.h> 
void showCube(double x); 
int main(void)    /* finds cube of entered number */ 
{ 
     double val; 
      
     printf("Enter a floating-point value: "); 
     scanf("%lf", &val); 
     showCube(val); 
      
    return 0; 
} 
void showCube(double x) 
{ 
    printf("The cube of %e is %e.\n", x, x*x*x ); 
}
#include <stdio.h>//个人
void cube(double n);
int main(void)
{
	double number;
	printf("请输入一个数:");
	scanf_s("%lf", &number);
	cube((double)number);
	return 0;
}
void cube(double n)
{
	printf("该数的立方值为:%.2f\n",n*n*n);
}

5.8

编写一个程序,显示求模运算的结果。把用户输入的第1个整数作为求模运算符的第2个运算对象,该数在运算过程中保持不变。用户后面输入的数是第1个运算对象。当用户输入一个非正值时,程序结束。其输出示例如下:

This program computes moduli.

Enter an integer to serve as the second operand: 256

Now enter the first operand: 438

438 % 256 is 182

Enter next number for first operand (<= 0 to quit): 1234567

1234567 % 256 is 135

Enter next number for first operand (<= 0 to quit): 0

Done

#include <stdio.h>//个人
int main(void)
{
	int divisor;
	int dividend;
	printf("求余运算器\n");
	printf("请输入求余运算中的求余数:");
	scanf_s("%d",&divisor);
	printf("\n请输入求余运算中的被求余数(输入非正值结束):");
	scanf_s("%d",&dividend);
	const int DIVISOR = divisor;
	while (dividend > 0)
	{
		printf("%d%%%d得%d\n",dividend, DIVISOR,dividend% DIVISOR);
		printf("请输入求余运算中的被求余数(输入非正值结束):");
		scanf_s("%d", &dividend);
	}
	return 0;
}

5.9

编写一个程序,要求用户输入一个华氏温度。程序应读取double类型的值作为温度值,并把该值作为参数传递给一个用户自定义的函数Temperatures。该函数计算摄氏温度和开氏温度,并以小数点后面两位数字的精度显示3种温度。要使用不同的温标来表示这3个温度值。下面是华氏温度转摄氏温度的公式:

摄氏温度 = 5.0 / 9.0 * (华氏温度 - 32.0)

开氏温标常用于科学研究,0表示绝对零,代表最低的温度。下面是摄氏温度转开氏温度的公式:

开氏温度 = 摄氏温度 + 273.16

Temperatures函数中用const创建温度转换中使用的变量。在main函数中使用一个循环让用户重复输入温度,当用户输入 q 或其他非数字时,循环结束。scanf函数返回读取数据的数量,所以如果读取数字则返回1,如果读取q则不返回1。可以使用==运算符将scanf的返回值和1作比较,测试两值是否相等。

#include <stdio.h>//个人
void Temperatures(double n);
int main(void)
{
	double Fahrenheit;
	printf("请输入华氏度:");
	while (scanf_s("%lf", &Fahrenheit) == 1)
	{
		Temperatures(Fahrenheit);
		printf("请输入华氏度(输入非数字结束):");
	}
	return 0;
}
void Temperatures(double n)
{
	const double FAHRENHEIT = n;
	double Celsius, Kelvin;
	Celsius = 5.0 / 9.0 * (FAHRENHEIT - 32.0);
	Kelvin = Celsius + 273.16;
	printf("华氏度℉:%.2lf\t摄氏度℃:%.2lf\t开氏度K:%.2lf\n", FAHRENHEIT, Celsius, Kelvin);
}

第六章

6.1

编写一个程序,创建一个包含 26 个元素的数组,并在其中储存 26 个小写字母。然后打印数组的所有内容。

/* pe6-1.c */ 
/* this implementation assumes the character codes */ 
/* are sequential, as they are in ASCII.           */ 
#include <stdio.h> 
#define SIZE 26 
int main( void ) 
{ 
    char lcase[SIZE]; 
    int i; 
     
    for (i = 0; i < SIZE; i++) 
        lcase[i] = 'a' + i; 
    for (i = 0; i < SIZE; i++) 
        printf("%c", lcase[i]); 
    printf("\n");         
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	char letter[26];
	for (int i = 0; i < 26; i++)
	{
		letter[i] = 97+i;
		printf("%c ",letter[i]);
	}
	return 0;
}

6.2

使用嵌套循环,按下面的格式打印字符:

#include <stdio.h>//个人
int main(void)
{
	for (int i = 1; i <= 5; i++)
	{
		for (int j = 1; j <= i; j++)
			printf("$");
		printf("\n");
	}
	return 0;
}

6.3

使用嵌套循环,按下面的格式打印字母:

F
FE
FED
FEDC
FEDCB
FEDCBA

注意:如果你的系统不使用 ASCII 或其他以数字顺序编码的代码,可以把字符数组初始化为字母表中的字母:
char 1et S [27 ] = "ABCDEFGHI JKLMNOPQRSTUVWXYZ " ;
然后用数组下标选择单独的字母,例如 1ets [0]是A',等等。

/* pe6-3.c */ 
/* this implementation assumes the character codes */ 
/* are sequential, as they are in ASCII.           */ 
#include <stdio.h> 
int main( void ) 
{ 
    char let = 'F'; 
    char start; 
    char end; 
     
    for (end = let; end >= 'A'; end--) 
    { 
        for (start = let; start >= end; start--) 
            printf("%c", start); 
        printf("\n"); 
    } 
     
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	for (int i = 1; i <= 6; i++)
	{
		for (int j = 0; j < i; j++)
			printf("%c",70-j);
		printf("\n");
	}
	return 0;
}

6.4

使用嵌套循环,按下面的格式打印字母:

A
BC
DEF
GHIJ
KLMNO
PQRSTU

如果你的系统不使用以数字顺序编码的代码,请参照练习3的方案解决。

#include <stdio.h>//个人
int main(void)
{
	for (int i = 1,A=65; i <= 6; i++)
	{
		for (int j = 1; j <= i; j++, A++)
			printf("%c", A);
		printf("\n");
	}
	return 0;
}

6.5

编写一个程序,提示用户输入大写字母。使用嵌套循环以下面金字塔型的格式打印字母:

         A
       ABA
     ABCBA
   ABCDCBA
ABCDEDCBA

打印这样的图形,要根据用户输入的字母来决定。例如,上面的图形是在用户输入E后的打印结果。

提示:用外层循环处理行,每行使用3个内层循环,分别处理空格、以升序打印字母、以降序打印字母。如果系统不使用 ASCⅡI或其他以数字顺序编码的代码,请参照练习3的解决方案。

#include <stdio.h>//个人
int main(void)
{
	for (int i = 1; i < 6; i++)
	{
		for (int j = 6; j > i; j--)
			printf(" ");
		for (int k = 0; k < i; k++)
			printf("%c",65+k);
		for (int g = i-2; g >= 0; g--)
			printf("%c", 65 + g);
		printf("\n");
	}
	return 0;
}

6.6

编写一个程序打印一个表格,每一行打印一个整数、该数的平方、该数的立方。要求用户输入表格
的上下限。 使用一个 for 循环。

/* pe6-6.c */ 
#include <stdio.h> 
int main( void ) 
{ 
    int lower, upper, index; 
    int square, cube; 
     
    printf("Enter starting integer: "); 
    scanf("%d", &lower); 
    printf("Enter ending integer: "); 
    scanf("%d", &upper); 
     
    printf("%5s %10s %15s\n", "num", "square", "cube"); 
    for (index = lower; index <= upper; index++) 
    { 
        square = index * index; 
        cube = index * square; 
        printf("%5d %10d %15d\n", index, square, cube); 
    } 
         
    return 0; 
}
#include <stdio.h>//个人
int square(int a);
int cube(int a);
int main(void)
{
	int start, end;
	printf("此程序将打印由你输入的整数范围内每个整数的平方与立方所构成的表格\n");
	printf("请输入起始整数:");
	scanf_s("%d",&start);
	printf("请输入终末整数:");
	scanf_s("%d", &end);
	printf("原数\t平方\t立方\n");
	for (int i = start; i <= end; i++)
		printf("%d\t%d\t%d\n",i,square(i),cube(i));
	return 0;
}
int square(int a)
{
	return a * a;
}
int cube(int a)
{
	return a * a * a;
}

6.7

编写一个程序把一个单词读入一个字符数组中,然后倒序打印这个单词。提示:strlen ()函数(第4章介绍过)可用于计算数组最后一个字符的下标。

#include <stdio.h>//个人
#include <string.h>
int main(void)
{
	char word[40] = {0};
	printf("请输入一个单词:");
	scanf_s("%s",word,40);
	for (int i = strlen(word); i >= 0; i--)
		printf("%c ", word[i]);
	return 0;
}

6.8

编写一个程序,要求用户输入两个浮点数,并打印两数之差除以两数乘积的结果。在用户输入非数
字之前,程序应循环处理用户输入的每对值。

/* pe6-8.c */ 
#include <stdio.h> 
int main( void ) 
{ 
    double n, m; 
    double res; 
     
    printf("Enter a pair of numbers: "); 
     
    while (scanf("%lf %lf", &n, &m) == 2) 
    { 
        res = (n - m) / (n * m); 
        printf("(%.3g - %.3g)/(%.3g*%.3g) = %.5g\n", n, m, n, m, res); 
        printf("Enter next pair (non-numeric to quit): "); 
    }
    return 0; 
}
#include <stdio.h>//个人
double count(double a, double b);
int main(void)
{
	double num1, num2;
	printf("请输入要计算的数字:");
	for (int i= scanf_s("%lf%lf", &num1, &num2);i==2; i=scanf_s("%lf%lf", &num1, &num2))
	{
		printf("%lf\n",count(num1,num2));
		printf("请输入要计算的数字:");
	}
	return 0;
}
double count(double a, double b)
{
	return (a - b) / (a * b);
}

6.9

修改练习8,使用一个函数返回计算的结果

#include <stdio.h>//个人
double count(double a, double b);
int main(void)
{
	double num1, num2;
	printf("请输入要计算的数字:");
	while (scanf_s("%lf%lf", &num1, &num2) == 2)
	{
		printf("%lf\n", count(num1, num2));
		printf("请输入要计算的数字:");
	}
	return 0;
}
double count(double a, double b)
{
	return (a - b) / (a * b);
}

6.10

编写一个程序,要求用户输入一个上限整数和一个下限整数,计算从上限到下限范围内所有整数
的平方和,并显示计算结果。然后程序继续提示用户输入上限和下限整数,并显示结果,直到用
户输入的上限整数小于下限整数为止。程序的运行示例如下:

Enter lower and upper integer 1imits: 5 9
The sums of the squares from 25 to 81 is 255
Enter next set of limi ts: 3 25
The sums of the squares from 9 to 625 is 5520
Enter next set of limits: 5 5
Done

#include <stdio.h>//个人
double square(double a);
int main(void)
{
	int low, upper;
	printf("该程序返回由你输入的整数范围内所有整数的平方和\n");
	printf("请输入上限和下限:");
	for (; scanf_s("%d%d", &low, &upper) == 2 && low < upper;)
	{
		int sum = 0;
		for (int i = low;i<=upper;i++)
			sum += square(i);
		printf("[%d,%d]范围内所有整数的平方和为%d\n",low,upper,sum);
	}
	return 0;
}
double square(double a)
{
	return a*a;
}

6.11

编写一个程序,在数组中读入8个整数然后按倒序打印这8个整数。

/* pe6-11.c */ 
#include <stdio.h> 
#define SIZE 8 
int main( void ) 
{ 
    int vals[SIZE]; 
    int i;     
     
    printf("Please enter %d integers.\n", SIZE); 
    for (i = 0; i < SIZE; i++) 
        scanf("%d", &vals[i]); 
    printf("Here, in reverse order, are the values you entered:\n"); 
    for (i = SIZE - 1; i >= 0; i--) 
        printf("%d ", vals[i]); 
    printf("\n"); 
                 
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	int a[8];
	printf("请输入8个数字(我们将倒序打印它们):");
	for (int i = 0; i < 8; i++)
		scanf_s("%d",&a[i]);
	printf("\n");
	for (int i=7;i>=0;i--)
		printf("%2d",a[i]);
	return 0;
}

6.12

考虑下面两个无限序列:
1.0 +1.0/2.0 + 1.0/3.0 +1.0/4.0 + …
1.0 - 1.0/2.0 + 1.0/3.0 - 1.0/4.0 + …
编写一个程序计算这两个无限序列的总和,直到到达某次数。提示:奇数个-1 相乘得-1,偶数个
-1相乘得1。让用户交互地输入指定的次数,当用户输入0或负值时结束输入。查看运行100项、
1000 项、10000 项后的总和,是否发现每个序列都收敛于某值?

#include <stdio.h>//个人
int main(void)
{
	int count = 0;
	printf("请输入要求和的项数:");
	for (scanf_s("%d", &count); count > 0; scanf_s("%d", &count))
	{
		double sum1 = 0;
		for (int i = 1; i <= count; i++)
			sum1 += 1.0 / i;
		double sum2 = 0;
		for (int i = 1; i <= count; i += 2)
			sum2 += 1.0 / i;
		for (int i = 2; i <= count; i += 2)
			sum2 -= 1.0 / i;
		printf("数列1:%lf,数列2:%lf\n\n", sum1,sum2);
		printf("请输入要求和的项数:");
	}
	return 0;
}

6.13

编写一个程序,创建一个包含 8个元素的 int 类型数组,分别把数组元素设置为 2 的前 8 次幂。
使用 for 循环设置数组元素的值,使用 do  while 循环显示数组元素的值。

/* pe6-13.c */ 
/* This version starts with the 0 power */ 
#include <stdio.h> 
#define SIZE 8 
int main( void ) 
{ 
    int twopows[SIZE]; 
    int i; 
    int value = 1;    /* 2 to the 0 */ 
     
    for (i = 0; i < SIZE; i++) 
    { 
        twopows[i] = value; 
        value *= 2; 
    } 
     
    i = 0; 
    do 
    { 
        printf("%d ", twopows[i]); 
        i++; 
    } while (i < SIZE); 
    printf("\n"); 
                     
    return 0; 
}
#include <stdio.h>//个人
#define SIZE 8
int main(void)
{
	int tow[SIZE] = {0};
	for (int i = 0; i < SIZE; i++)
	{
		int power=1;
		for (int j = 0 ; j <= i; j++)
			power *= 2;
		tow[i] = power;
	}
	int i = 0;
	do
	{
		printf("2的%d次方是%d\n", i + 1, tow[i]);
		i++;
	} while (i < SIZE);
	return 0;
}

6.14

编写一个程序,创建两个包含 8个元素的 double类型数组,使用循环提示用户为第一个数组输入
8 个值。第二个数组元素的值设置为第一个数组对应元素的累积之和。例如,第二个数组的第 4个元素的值是第一个数组前 4个元素之和,第二个数组的第5个元素的值是第一个数组前5个元
素之和(用嵌套循环可以完成,但是利用第二个数组的第5个元素是第二个数组的第4个元素与
第一个数组的第5个元素之和,只用一个循环就能完成任务,不需要使用嵌套循环)。最后,使用
循环显示两个数组的内容,第一个数组显示成一行,第二个数组显示在第一个数组的下一行,而
且每个元素都与第一个数组各元素相对应。

/* pe-14.c */ 
/* Programming Exercise 6-14 */ 
#include <stdio.h> 
#define SIZE 8 
int main(void) 
{ 
    double arr[SIZE]; 
    double arr_cumul[SIZE]; 
    int i;
    printf("Enter %d numbers:\n", SIZE); 
     
    for (i = 0; i < SIZE; i++) 
    { 
        printf("value #%d: ", i + 1); 
        scanf("%lf", &arr[i]); 
    /* or scanf("%lf", arr + i);    */ 
    } 
     
    arr_cumul[0] = arr[0];      /* set first element */ 
    for (i = 1; i < SIZE; i++) 
        arr_cumul[i] = arr_cumul[i-1] + arr[i]; 
     
    for (i = 0; i < SIZE; i++) 
        printf("%8g ", arr[i]); 
    printf("\n"); 
    for (i = 0; i < SIZE; i++) 
        printf("%8g ", arr_cumul[i]); 
    printf("\n"); 
     
                 
    return 0; 
}
#include <stdio.h>//个人
#define SIZE 8
int main(void)
{
	double item[SIZE], total[SIZE],sum=0;
	printf("请输入8个数字:");
	for (int i = 0; i < SIZE; i++)
	{
		scanf_s("%lf", &item[i]);
		sum += item[i];
		total[i] = sum;
		printf("%.2lf\t",item[i]);
	}
	printf("\n");
	for (int i = 0; i < SIZE; i++)
		printf("%.2lf\t",total[i]);
	return 0;
}

6.15

编写一个程序,读取一行输入,然后把输入的内容倒序打印出来。可以把输入储存在 char类型的
数组中,假设每行字符不超过 255。回忆一下,根据%c 转换说明, scanf()函数一次只能从输入中
读取一个字符,而且在用户按下Enter键时 scanf()函数会生成一个换行字符 (\n)。

#include <stdio.h>//个人
#include <string.h>
int main(void)
{
	char a[255] = "";
	int i = 0;
	printf("请输入要倒叙打印的话:");
	do
	{
		scanf_s("%c",&a[i],1);
		i++;
	} while (a[i-1]!='\12');//检查上一次输入是否为回车,若为回车则结束输入
	for (int j = strlen(a); i >= 0; i--)
		printf("%c",a[i]);
	return 0;
}
#include <stdio.h>//个人
#include <string.h>
int main(void)
{
	char ch[255]="";
	//printf("%zd", strlen(ch));
	for (int i = 0; (ch[i] = getchar()) != '\n'; i++);
	//printf("%zd", strlen(ch));
	for (int i = strlen(ch); i >= 0; putchar(ch[i]), i--);
	return 0;
}

6.16

Daphne 以 10%的单利息投资了 100美元(也就是说,每年投资获利相当于原始投资的 10%)。Deirdre以5%的复合利息投资了100 美元(也就是说,利息是当前余额的5%,包含之前的利息)。编写一个程序,计算需要多少年 Deirdre 的投资额才会超过 Daphne,并显示那时两人的投资额。

/* pe6-16.c */ 
#include <stdio.h> 
#define RATE_SIMP 0.10 
#define RATE_COMP 0.05 
#define INIT_AMT 100.0 
int main( void ) 
{ 
    double daphne = INIT_AMT; 
    double deidre = INIT_AMT; 
    int years = 0; 
     
    while (deidre <= daphne) 
    { 
        daphne += RATE_SIMP * INIT_AMT; 
        deidre += RATE_COMP * deidre; 
        ++years; 
    } 
    printf("Investment values after %d years:\n", years); 
    printf("Daphne: $%.2f\n", daphne); 
    printf("Deidre: $%.2f\n", deidre); 
    return 0; 
}

#include <stdio.h>//个人
#define SINGLE_INYEREST_RATE 0.1
#define COMPOUND_INTEREST_RATE 0.05
#define BALANCE 100
double Single_interest(double a,int b);
double Compound_interest(double a, int b);
int main()
{
	double Daphne = BALANCE;
	double Deirdre = BALANCE;
	int year=1;
	for (int i = 1; Compound_interest(Deirdre, i)< Single_interest(Daphne,i); i++)
	{
		printf("第%d年\tDaphne:%lf\tDeirdre:%lf\n",
		i, Single_interest(Daphne, i), Compound_interest(Deirdre, i));
		year++;
	}
	printf("需要%d年\n",year);
	return 0;
}
double Single_interest(double a,int b)
{
	double balance = a;
	const double interest = a * SINGLE_INYEREST_RATE;
	for (int i = 1; i <= b; i++)
		balance += interest;
	return balance;
}
double Compound_interest(double a, int b)
{
	double balance = a;
	for (int i = 1; i <= b; i++)
		balance += balance * COMPOUND_INTEREST_RATE;
	return balance;
}

6.17

Chuckie Lucky 赢得了 100 万美元 (税后),他把奖金存入年利率 8%的账户。在每年的最后一天,Chuckie 取出 10 万美元。编写一个程序,计算多少年后 Chuckie 会取完账户的钱?

#include <stdio.h>//个人
#define SINGLE_INYEREST_RATE 0.08
#define COMPOUND_INTEREST_RATE 0.08
#define BALANCE 100
double Single_interest(double a,int b);
double Compound_interest(double a, int b);
int main()
{
	double Chuckie = BALANCE;
	int year = 1;
	for (int i = 1; Chuckie > 10; i++)
	{
		Chuckie=Compound_interest(Chuckie, 1);//注意这里年份始终为1
		//printf("第%d年:%lf\n",year,Chuckie);
		Chuckie -= 10;
		printf("第%d年:%lf\n", year, Chuckie);
		year++;
	}
	printf("需要%d年\n",year);
	return 0;
}
double Single_interest(double a,int b)
{
	double balance = a;
	const double interest = a * SINGLE_INYEREST_RATE;
	for (int i = 1; i <= b; i++)
		balance += interest;
	return balance;
}
double Compound_interest(double a, int b)
{
	double balance = a;
	for (int i = 1; i <= b; i++)
		balance += balance * COMPOUND_INTEREST_RATE;
	return balance;
}

6.18

Rabnud 博士加入了一个社交圈。起初他有 5 个朋友。他注意到他的朋友数量以下面的方式增长。
第1周少了1个朋友,剩下的朋友数量翻倍:第2周少了2个朋友,剩下的朋友数量翻倍。一般
而言,第N周少了 N 个朋友,剩下的朋友数量翻倍。编写一个程序,计算并显示 Rabnud 博士每
周的朋友数量。该程序一直运行,直到超过邓巴数(Dunbar 's number)。邓巴数是粗略估算一个人在社交圈中有稳定关系的成员的最大值,该值大约是150。

#include <stdio.h>//个人
#define Dunbar_number 150
int main()
{
	int Rabnud_friend = 5;
	for (int i=1; Rabnud_friend<150;i++)
	{
		Rabnud_friend -= i;
		Rabnud_friend *= 2;
		printf("第%d周Rabnud_friend有%d个朋友\n",i, Rabnud_friend);
	}
	return 0;
}

第七章

7.1

编写一个程序读取输入,读到#字符停止,然后报告读取的空格数、换行符数和所有其他字符的数量。

/* Programming Exercise 7-1 */ 
#include <stdio.h> 
int main(void)     
{ 
     char ch; 
     int sp_ct = 0; 
     int nl_ct = 0; 
     int other = 0; 
     while ((ch = getchar()) != '#') 
     { 
         if (ch == ' ') 
             sp_ct++; 
         else if (ch == '\n') 
             nl_ct++; 
         else 
             other++; 
     } 
     printf("spaces: %d, newlines: %d, others: %d\n", sp_ct, nl_ct, other); 
      
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
	char ch;
	int space = 0, newline = 0, other = 0;
	printf("请输入要计数的文本(请以#结尾):");//一个汉字占三个字节
	while ((ch = getchar()) != '#')
	{
		if (ch == ' ')
		{
			space++;
			continue;
		}
		if (ch == '\n')
		{
			newline++;
			continue;
		}
		other++;
	}
	printf("空格:%d 换行:%d 其它字符:%d\n",space,newline,other);
	return 0;
}

7.2

编写一个程序读取输入,读到#字符停止。程序要打印每个输入的字符以及对应的ASCII码(十进制)。一行打印8个字符。建议:使用字符计数和求模运算符(%)在每8个循环周期时打印一个换行符。

#include <stdio.h>//个人
int main(void)
{
	char ch;
	printf("请输入文本(以#号结束):");
	for (int i = 0; (ch = getchar()) != '#'; i++)
	{
		printf("%c %d\t ",ch,(int)ch);
		if ((i+1) % 8 == 0)//i从0开始,故加1
			printf("\n");
	}
	return 0;
}

7.3

编写一个程序,读取整数直到用户输入 0。输入结束后,程序应报告用户输入的偶数(不包括 0)个数、这些偶数的平均值、输入的奇数个数及其奇数的平均值。

/* Programming Exercise 7-3 */ 
#include <stdio.h> 
int main(void)     
{ 
     int n; 
     double sumeven = 0.0; 
     int ct_even = 0; 
     double sumodd = 0.0; 
     int ct_odd = 0; 
       
     while (scanf("%d", &n) == 1 && n != 0) 
     { 
         if (n % 2 == 0) 
         { 
             sumeven += n; 
             ++ct_even; 
         } 
         else  // n % 2 is either 1 or -1 
         { 
              sumodd += n; 
             ++ct_odd; 
        } 
     } 
     printf("Number of evens: %d", ct_even); 
     if (ct_even > 0) 
         printf("  average: %g", sumeven / ct_even); 
     putchar('\n'); 
          
     printf("Number of odds: %d", ct_odd); 
     if (ct_odd > 0) 
         printf("  average: %g", sumodd / ct_odd); 
     putchar('\n'); 
     printf("\ndone\n"); 
      
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	int number;
	int even = 0, odd_number = 0;
	float even_sum = 0.0, odd_number_sum = 0.0;
	printf("请输入整数(以0结束):");
	for (int i = 0; scanf_s("%d",&number)==1 && number!=0; i++)
	{
		if (number % 2 == 0)
		{
			even++;
			even_sum += number;
		}
		else
		{
			odd_number++;
			odd_number_sum += number;
		}
	}
	printf("偶数个数:%d\t偶数平均值:%f\n奇数个数:%d\t奇数平均值:%f\n",
			even,even_sum/even,odd_number,odd_number_sum/odd_number);
	return 0;
}

7.4

使用if else语句编写一个程序读取输入,读到#停止。用感叹号替换句号,用两个感叹号替换原来的感叹号,最后报告进行了多少次替换。

#include <stdio.h>//个人
int main(void)
{
	char ch;
	int sum = 0;
	printf("请输入文本(以#结束):");
	while ((ch = getchar()) != '#')
	{
		if (ch == '.')
		{
			ch = '!';
			printf("%c", ch);
			sum++;
			continue;
		}
		else if (ch == '!'||ch=='!')
		{
			printf("%c%c", ch,ch);
			sum++;
			continue;
		}
		else
			printf("%c",ch);
	}
	printf("\n经行了%d次替换\n", sum);
	return 0;
}

7.5

使用switch重写练习7.4。

/* Programming Exercise 7-5 */ 
#include <stdio.h> 
int main(void)     
{ 
     char ch; 
     int ct1 = 0; 
     int ct2 = 0; 
     while ((ch = getchar()) != '#') 
     { 
         switch(ch) 
         { 
              case '.' :  putchar('!'); 
                          ++ct1; 
                          break; 
              case '!' :  putchar('!'); 
                          putchar('!'); 
                          ++ct2; 
                          break; 
             default   :  putchar(ch); 
         } 
     } 
     printf("%d replacement(s) of . with !\n", ct1); 
     printf("%d replacement(s) of ! with !!\n", ct2); 
       
    return 0; 
} 
#include <stdio.h>//个人
int main(void)
{
	char ch;
	int sum = 0;
	printf("请输入文本(以#结束):");
	while ((ch = getchar()) != '#')
	{
		switch ((int)ch)
		{
		case 46:
			ch = '!';
			printf("%c", ch);
			sum++;
			break;
		case 33:
			printf("%c%c", ch, ch);
			sum++;
			break;
		default:
			printf("%c",ch);
		}
	}
	printf("\n替换了%d次\n",sum);
	return 0;
}

7.6

编写程序读取输入,读到#停止,报告ei出现的次数。

注意

该程序要记录前一个字符和当前字符。用“Receive your eieio award”这样的输入来测试。

#include <stdio.h>//个人
int main(void)
{
	char ch;
	char a=' ', b = ' ';
	int sum_ei = 0;
	printf("请输入文本(以#结束):");
	for (int i = 1; (ch = getchar()) != '#'; i++)
	{
		if (a == 'e' && ch == 'i')
			sum_ei++;
		a = ch;//a始终为上一次输入
	}
	printf("出现了%d个‘ei’\n",sum_ei);
	return 0;
}

7.7

编写一个程序,提示用户输入一周工作的小时数,然后打印工资总额、税金和净收入。做如下假设:

a.基本工资 = 10.00美元/小时

b.加班(超过40小时) = 1.5倍的时间

c.税率: 前300美元为15%,续150美元为20%,余下的为25%

用#define定义符号常量。不用在意是否符合当前的税法。

// Programming Exercise 7-7 
#include <stdio.h> 
#define BASEPAY    10       // $10 per hour 
#define BASEHRS    40       // hours at basepay 
#define OVERTIME    1.5     // 1.5 time 
#define AMT1      300       // 1st rate tier 
#define AMT2      150       // 2st rate tier 
#define RATE1       0.15    // rate for 1st tier 
#define RATE2       0.20    // rate for 2nd tier 
#define RATE3       0.25    // rate for 3rd tier 
int main(void)     
{ 
    double hours; 
    double gross; 
    double net; 
    double taxes; 
     
    printf("Enter the number of hours worked this week: "); 
    scanf("%lf", &hours); 
    if (hours <= BASEHRS) 
        gross = hours * BASEPAY; 
    else 
        gross = BASEHRS * BASEPAY + (hours - BASEHRS) * BASEPAY * OVERTIME; 
    if (gross <= AMT1) 
        taxes = gross * RATE1; 
    else if (gross <= AMT1 + AMT2) 
        taxes = AMT1 * RATE1 + (gross - AMT1) * RATE2; 
    else 
        taxes = AMT1 * RATE1 + AMT2 * RATE2 + (gross - AMT1 - AMT2) * RATE3; 
    net = gross - taxes; 
    printf("gross: $%.2f; taxes: $%.2f; net: $%.2f\n", gross, taxes, net); 
       
    return 0; 
} 
#include <stdio.h>//个人
#define BASIC_WAGE 10.0
#define TIME 40
#define OVERTIME 1.5
#define DOLLAR1 300
#define DOLLAR2 450
#define RATE1 0.15
#define RATE2 0.20
#define RATE3 0.25
int main(void)
{
	double working_hours;
	double total, taxes, net_income;
	printf("请输入工时:");
	while (scanf_s("%lf", &working_hours)==1)
	{
		if (working_hours < 0)
		{
			printf("输入错误,请重新输入工时:");
			continue;
		}
		if (working_hours > TIME)
			working_hours = (working_hours - TIME) * OVERTIME+TIME;
		total = working_hours * BASIC_WAGE;
		if (total < DOLLAR1)
			taxes = total * RATE1;
		else if (total < DOLLAR2)
			taxes = DOLLAR1 * RATE1 + (total - DOLLAR1) * RATE2;
		else
			taxes = DOLLAR1 * RATE1 + (DOLLAR2 - DOLLAR1) * RATE2 + (total - DOLLAR2) * RATE3;
		printf("工资总额:%lf\t税金:%lf\t净收入:%lf\t\n\n",total,taxes,total-taxes);
		printf("请输入工时:");
	}
	return 0;
}

7.8

修改练习7.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 <stdio.h>//个人
#define BASIC_WAGE1 8.75
#define BASIC_WAGE2 9.33
#define BASIC_WAGE3 10.0
#define BASIC_WAGE4 11.2
#define TIME 40
#define OVERTIME 1.5
#define DOLLAR1 300
#define DOLLAR2 450
#define RATE1 0.15
#define RATE2 0.20
#define RATE3 0.25
int main(void)
{
	double working_hours;
	double total, taxes, net_income;
	double basic_wage;
	printf("请输入工时:");
	while (scanf_s("%lf", &working_hours)==1)
	{
		int grade;
		printf(
		"*****************************************************************\n"

		"Enter the number corresponding to the desired pay rate or action:\n"

		"(1) $%.2lf / hr   (2) $%.2lf / hr\n"

		"(3) $%.2lf / hr   (4) $%.2lf / hr\n"

		"(5) quit\n"

		"*****************************************************************\n" 
		"请输入工资等级:",
		BASIC_WAGE1,BASIC_WAGE2,BASIC_WAGE3,BASIC_WAGE4);
		scanf_s("%d",&grade);
		switch (grade)
		{
		case 1:basic_wage = BASIC_WAGE1;break;
		case 2:basic_wage = BASIC_WAGE2;break;
		case 3:basic_wage = BASIC_WAGE3;break;
		case 4:basic_wage = BASIC_WAGE4;break;
		default:goto end;
		}
		if (working_hours < 0)
		{
			printf("输入错误,请重新输入工时:");
			continue;
		}
		if (working_hours > TIME)
			working_hours = (working_hours - TIME) * OVERTIME+TIME;
		total = working_hours * basic_wage;
		if (total < DOLLAR1)
			taxes = total * RATE1;
		else if (total < DOLLAR2)
			taxes = DOLLAR1 * RATE1 + (total - DOLLAR1) * RATE2;
		else
			taxes = DOLLAR1 * RATE1 + (DOLLAR2 - DOLLAR1) * RATE2 + (total - DOLLAR2) * RATE3;
		printf("工资总额:%lf\t税金:%lf\t净收入:%lf\t\n\n",total,taxes,total-taxes);
		printf("请输入工时:");
	}
	end:printf("感谢使用该系统!\n");
	return 0;
}

7.9

编写一个程序,只接受正整数输入,然后显示所有小于或等于该数的素数。

/* Programming Exercise 7-9 */ 
#include <stdio.h> 
#include <stdbool.h> 
int main(void) 
{ 
    int limit; 
    int num; 
    int div; 
    bool numIsPrime;  // use int if stdbool.h not available 
     
    printf("Enter a positive integer: "); 
    while (scanf("%d", &limit) == 1 && limit > 0) 
    { 
        if (limit > 1) 
            printf("Here are the prime numbers up through %d\n", limit); 
        else 
            printf("No primes.\n"); 
        for (num = 2; num <= limit; num++) 
        {  
              for (div = 2, numIsPrime = true; (div * div) <= num; div++) 
                 if (num % div == 0) 
                          numIsPrime = false; 
              if (numIsPrime) 
                 printf("%d is prime.\n", num); 
        } 
        printf("Enter a positive integer (q to quit): "); 
    } 
    printf("Done!\n"); 
                 
    return 0; 
}
#include <stdio.h>//个人
#include <stdbool.h>
int main(void)
{
	float positive_integer;
	printf("请输入数字:");
	scanf_s("%f", &positive_integer);
	if (positive_integer < 0)
		printf("输入错误!这不是一个正整数!\n");
	else if ((int)positive_integer != positive_integer)
		printf("输入错误!这不是一个正整数!\n");
	else
	{
		int a = (int)positive_integer;
		for (int i = 2; i <= a; i++)
		{
			bool mark = true;
			for (int j = 2; j*j < i; j++)
			{
				if (i % j == 0)
				{
					mark = false;
					break;
				}
			}
			if (mark == false)
				continue;
			else
				printf("%d\t", i);
		}
	}
	return 0;
}

7.10

1988年的美国联邦税收计划是近代最简单的税收方案。它分为4个类别,每个类别有两个等级。

下面是该税收计划的摘要(美元数为应征税的收入):

例如,一位工资为20000美元的单身纳税人,应缴纳税费0.15×17850+0.28×(20000−17850)美元。编写一个程序,让用户指定缴纳税金的种类和应纳税收入,然后计算税金。程序应通过循环让用户可以多次输入。

#include <stdio.h>//个人
#define SINGLE 17850
#define HOUSEHOLD 23900
#define MARRIED 29750
#define DIVORCED 14875
#define BASE_RATE 0.15
#define OVER_RATE 0.28
int main(void)
{
	double wages, taxes=0;
	int label;
	printf("请输入工资:");
	while (scanf_s("%lf",&wages)==1)
	{
		printf(
			"*************************\n"

			" 请 选 择 纳 税 类 别 :\n"

			"(1) 单身   (2) 户主\n"

			"(3) 已婚   (4) 离异\n"

			"*************************\n"
			"请输入选择的类别标号:");
		scanf_s("%d", &label);
		switch (label)
		{
		case 1:
			if (wages < SINGLE)
				taxes = wages * BASE_RATE;
			else
				taxes = SINGLE * BASE_RATE + (wages - SINGLE) * OVER_RATE;
			break;
		case 2:
			if (wages < HOUSEHOLD)
				taxes = wages * BASE_RATE;
			else
				taxes = HOUSEHOLD * BASE_RATE + (wages - HOUSEHOLD) * OVER_RATE;
			break;
		case 3:
			if (wages < MARRIED)
				taxes = wages * BASE_RATE;
			else
				taxes = MARRIED * BASE_RATE + (wages - MARRIED) * OVER_RATE;
			break;
		case 4:
			if (wages < DIVORCED)
				taxes = wages * BASE_RATE;
			else
				taxes = DIVORCED * BASE_RATE + (wages - DIVORCED) * OVER_RATE;
			break;
		default:
			break;
		}
		printf("应缴纳税金%lf美元\n\n", taxes);
		printf("请输入工资:");
	}
	return 0;
}

7.11

ABC 邮购杂货店出售的洋蓟售价为 2.05 美元/磅,甜菜售价为 1.15 美元/磅,胡萝卜售价为 1.09美元/磅。在添加运费之前,100美元的订单有5%的打折优惠。少于或等于5磅的订单收取6.5美元的运费和包装费,5磅~20磅的订单收取14美元的运费和包装费,超过20磅的订单在14美元的基础上每续重1磅增加0.5美元。编写一个程序,在循环中用switch语句实现用户输入不同的字母时有不同的响应,即输入a的响应是让用户输入洋蓟的磅数,b是甜菜的磅数,c是胡萝卜的磅数,q 是退出订购。程序要记录累计的重量。即,如果用户输入 4 磅的甜菜,然后输入 5磅的甜菜,程序应报告9磅的甜菜。然后,该程序要计算货物总价、折扣(如果有的话)、运费和包装费。随后,程序应显示所有的购买信息:物品售价、订购的重量(单位:磅)、订购的蔬菜费用、订单的总费用、折扣(如果有的话)、运费和包装费,以及所有的费用总额。

/* pe7-11.c */ 
/* Programming Exercise 7-11 */ 
#include <stdio.h> 
#include <ctype.h> 
int main(void) 
{ 
  const double price_artichokes = 2.05; 
  const double price_beets = 1.15; 
  const double price_carrots = 1.09; 
  const double DISCOUNT_RATE = 0.05; 
  const double under5 = 6.50; 
  const double under20 = 14.00; 
  const double base20 = 14.00; 
  const double extralb =  0.50; 
   
  char ch; 
  double lb_artichokes = 0; 
  double lb_beets = 0; 
  double lb_carrots = 0; 
  double lb_temp; 
  double lb_total; 
   
  double cost_artichokes; 
  double cost_beets; 
  double cost_carrots; 
  double cost_total; 
  double final_total; 
  double discount; 
  double shipping; 
  printf("Enter a to buy artichokes, b for beets, "); 
  printf("c for carrots, q to quit: "); 
  while ((ch = getchar()) != 'q' && ch != 'Q') 
  { 
      if (ch == '\n') 
          continue; 
      while (getchar() != '\n')
          continue; 
       ch = tolower(ch); 
      switch (ch) 
      { 
          case 'a' : printf("Enter pounds of artichokes: "); 
                     scanf("%lf", &lb_temp); 
                     lb_artichokes += lb_temp; 
                     break; 
          case 'b' : printf("Enter pounds of beets: "); 
                     scanf("%lf", &lb_temp); 
                     lb_beets += lb_temp; 
                     break; 
      
          case 'c' : printf("Enter pounds of carrots: "); 
                     scanf("%lf", &lb_temp); 
                     lb_carrots += lb_temp; 
                     break; 
          default  : printf("%c is not a valid choice.\n", ch); 
    } 
    printf("Enter a to buy artichokes, b for beets, "); 
    printf("c for carrots, q to quit: "); 
  } 
     
  cost_artichokes = price_artichokes * lb_artichokes; 
  cost_beets = price_beets * lb_beets; 
  cost_carrots = price_carrots * lb_carrots; 
  cost_total = cost_artichokes + cost_beets + cost_carrots; 
  lb_total = lb_artichokes + lb_beets + lb_carrots; 
  if (lb_total <= 0) 
      shipping = 0.0; 
  else if (lb_total < 5.0) 
      shipping = under5; 
  else if (lb_total < 20) 
      shipping = under20; 
  else 
      shipping =  base20 + extralb * lb_total; 
  if (cost_total > 100.0) 
      discount = DISCOUNT_RATE * cost_total; 
  else 
    discount = 0.0; 
  final_total = cost_total + shipping - discount; 
  printf("Your order:\n"); 
  printf("%.2f lbs of artichokes at $%.2f per pound:$ %.2f\n", 
            lb_artichokes, price_artichokes, cost_artichokes);   
  printf("%.2f lbs of beets at $%.2f per pound: $%.2f\n", 
            lb_beets, price_beets, cost_beets);   
  printf("%.2f lbs of carrots at $%.2f per pound: $%.2f\n", 
            lb_carrots, price_carrots, cost_carrots); 
  printf("Total cost of vegetables: $%.2f\n", cost_total); 
  if (cost_total > 100) 
      printf("Volume discount: $%.2f\n", discount); 
  printf("Shipping: $%.2f\n", shipping); 
  printf("Total charges: $%.2f\n", final_total);  
  return 0; 
}
#include <stdio.h>//个人
#define ARTICHOKE 2.05
#define BEET 1.15
#define CARROT 1.09
#define DISCOUNT_DOLLAR 100
#define DISCOUNT 0.95
#define WEIGHT1 5
#define WEIGHT2 20
#define FREIGHT1 6.5
#define FREIGHT2 14
#define FREIGHT3 0.5
#define A "洋蓟"
#define B "甜菜"
#define C "胡萝卜"
#define KIND 3
int main(void)
{
	char mark1;
	double weight;
	double weight_mark[3] = {0};
	double weight_sum=0;
	double cost=0;
	double freight = 0;
	printf("请选择要购买的商品\n"
		   "a.%s\tb.%s\tc.%s\n",A,B,C);
	printf("请输入选择:");
	while (scanf_s("%c", &mark1,1))
	{
		int mark2 = 0;
		if (mark1 != 'a' && mark1 != 'b' && mark1 != 'c')
		{
			printf("\n未找到该商品,请检查输入!\n");
			printf("请输入选择:");
			scanf_s("%c", &mark1, 1);
			continue;
		}
		printf("请输入要购买的的重量(磅):");
		scanf_s("%lf",&weight);
		switch (mark1)
		{
		case 'a':cost += weight * ARTICHOKE; weight_mark[0] += weight; break;
		case 'b':cost += weight * BEET;  weight_mark[1] += weight; break;
		case 'c':cost += weight * CARROT;  weight_mark[2] += weight; break;
		default:printf("\n未找到该商品,请检查输入!\n"); break;
		}
		printf("现已购买:");
		weight_sum = 0;
		for (int i = 0; i < KIND; i++)
		{
			weight_sum += weight_mark[i];
			if (weight_mark[i] != 0)
			{
				switch (i)
				{
				case 0:printf("洋蓟%.2lf磅 ", weight_mark[i]); break;
				case 1:printf("甜菜%.2lf磅 ", weight_mark[i]); break;
				case 2:printf("胡萝卜%.2lf磅 ", weight_mark[i]); break;
				default:break;
				}
			}
		}
		printf("\n总重%.2lf磅,商品费用%.2lf\n",weight_sum,(cost>=100)?cost*DISCOUNT:cost);
		printf("是否继续购买?\n");
		printf("1.继续\t2.结算\n");
		printf("请输入选择:");
		scanf_s("%d",&mark2);
		if (mark2 == 1)
		{
			printf("请选择要购买的商品\n"
				"a.%s\tb.%s\tc.%s\n", A, B, C);
			printf("请输入选择:");
			scanf_s("%c", &mark1, 1);
			continue;
		}
		else
			break;
	}
	printf("\nABC邮购杂货店\n");
	for (int i = 0; i < KIND; i++)
	{
		if (weight_mark[i] != 0)
		{
			switch (i)
			{
			case 0:
				printf("洋蓟\t单价:%.2lf$\t 数量:%.2lf磅 —— %.2lf$\n",
					ARTICHOKE, weight_mark[i],weight_mark[i]*ARTICHOKE); 
				break;
			case 1:
				printf("甜菜\t单价:%.2lf$\t 数量:%.2lf磅 —— %.2lf$\n",
					BEET,weight_mark[i],weight_mark[i]*BEET); 
				break;
			case 2:printf("胡萝卜 单价:%.2lf$\t 数量:%.2lf磅 —— %.2lf$\n",
				CARROT,weight_mark[i], weight_mark[i]*CARROT);
				break;
			default:break;
			}
		}
	}
	if (weight_sum < 0)
		printf("重量错误!\n");
	else if (weight_sum < WEIGHT1)
		freight = FREIGHT1;
	else if (weight_sum < WEIGHT2)
		freight = FREIGHT2;
	else
		freight = FREIGHT2 + (weight_sum - WEIGHT2) * FREIGHT3;
	printf("蔬菜总费用——————————————————————%.2lf$\n", (cost >= 100) ? cost * DISCOUNT : cost);
	printf("折扣————————————————————————————%.2lf$\n", (cost >= 100) ? cost - (cost * DISCOUNT) : 0);
	printf("运费和包装费————————————————————%.2lf$\n", freight);
	printf("总计——————————————————————————————%.2lf$\n", ((cost >= 100) ? cost * DISCOUNT : cost) + freight);
	return 0;
}

第八章

8.1

设计一个程序,统计在读到文件结尾之前读取的字符数。

/* Programming Exercise 8-1 */ 
#include <stdio.h> 
int main(void) 
{ 
    int ch; 
    int ct = 0; 
     
    while ((ch = getchar()) != EOF) 
        ct++; 
    printf("%d characters read\n", ct); 
     
    return 0; 
}
#include <stdio.h>//个人
int main(void)
{
    int ch;
    int count = 0;
    while ((ch = getchar()) != EOF)
    {
        count++;
        putchar(ch);
    }
    printf("共计%d个字符\n", count);
    return 0;
}

8.2

编写一个程序,在遇到 EOF 之前,把输入作为字符流读取。程序要打印每个输入的字符及其相应的ASCII十进制值。注意,在ASCII序列中,空格字符前面的字符都是非打印字符,要特殊处理这些字符。如果非打印字符是换行符或制表符,则分别打印\n或\t。否则,使用控制字符表示法。例如,ASCII的1是Ctrl+A,可显示为^A。注意,A的ASCII值是Ctrl+A的值加上64。其他非打印字符也有类似的关系。除每次遇到换行符打印新的一行之外,每行打印10对值。(注意:不同的操作系统其控制字符可能不同。)

#include <stdio.h>//个人
int main(void)
{
	int ch;
	int count = 0;
	printf("请输入字符(ctrl+z或ctrl+c结束):");
	while ((ch = getchar()) != EOF)
	{
		printf("%d:", ch);
		if (ch < 32)
		{
			if (ch == 10)
			{
				printf("\\n");
				count = 0;
			}
			else if (ch == 9)
				printf("\\t");
			else
				printf("^%c", ch + 64);
		}
		else
		{
			putchar(ch);
			count++;
		}
		putchar('\t');
		if (count % 10 == 0)
		{
			putchar('\n');
			count = 0;
		}
	}
	return 0;
}

8.3

编写一个程序,在遇到 EOF 之前,把输入作为字符流读取。该程序要报告输入中的大写字母和小写字母的个数。假设大小写字母数值是连续的。或者使用ctype.h库中合适的分类函数更方便。

/* Programming Exercise 8-3 */ 
/* Using ctype.h eliminates need to assume consecutive coding */ 
#include <stdio.h> 
#include <ctype.h> 
int main(void) 
{ 
    int ch; 
    unsigned long uct = 0; 
    unsigned long lct = 0; 
    unsigned long oct = 0; 
     
    while ((ch = getchar()) != EOF) 
        if (isupper(ch)) 
            uct++; 
        else if (islower(ch)) 
            lct++; 
        else 
            oct++; 
    printf("%lu uppercase characters read\n", uct); 
    printf("%lu lowercase characters read\n", lct); 
    printf("%lu other characters read\n", oct); 
     
    return 0; 
}
    /* 
     or you could use 
     if (ch >= 'A' && ch <= 'Z') 
         uct++; 
     else if (ch >= 'a' && ch <= 'z') 
         lct++; 
     else 
        oct++; 
    */
#include <stdio.h>//个人
#include <ctype.h>
int main(void)
{
	int ch;
	int lower = 0, upper = 0;
	printf("请输入字符(ctrl+z或ctrl+c结束):");
	while ((ch = getchar()) != EOF)
	{
		if (islower((char)ch))
			lower++;
		else if (isupper((char)ch))
			upper++;
		else
			continue;
	}
	printf("大写字母%d个,小写字母%d个\n",upper,lower);
	return 0;
}

8.4

编写一个程序,在遇到EOF之前,把输入作为字符流读取。该程序要报告平均每个单词的字母数。不要把空白统计为单词的字母。实际上,标点符号也不应该统计,但是现在暂时不同考虑这么多(如果你比较在意这点,考虑使用ctype.h系列中的ispunct函数)。

#include <stdio.h>//个人
#include <ctype.h>
int main(void)
{
	int ch;
	float letter = 0;
	float word = 0;
	printf("请输入字符(ctrl+z或ctrl+c结束):");
	while ((ch = getchar()) != EOF)
	{
		if (isalpha((char)ch))
			letter++;
		else if (isblank((char)ch) || ispunct((char)ch))
			word++;
	}
	printf("共计%.0f个单词,%.0f个字母,平均每个单词%.2f个字母",word,letter,letter/word);
	return 0;
}

8.5

修改程序清单8.4的猜数字程序,使用更智能的猜测策略。例如,程序最初猜50,询问用户是猜大了、猜小了还是猜对了。如果猜小了,那么下一次猜测的值应是50和100中值,也就是75。如果这次猜大了,那么下一次猜测的值应是50和75的中值,等等。使用二分查找(binary search)策略,如果用户没有欺骗程序,那么程序很快就会猜到正确的答案。

/* 程序清单8.4 guess.c程序 */    //此非答案,而是题目的一部分!
/* guess.c -- 一个拖沓且错误的猜数字程序 */
#include <stdio.h>
int main(void)
{
	int guess = 1;
	printf("Pick an integer from 1 to 100. I will try to guess ");
	printf("it.\nRespond with a y if my guess is right and with");
	printf("\nan n if it is wrong.\n");
	printf("Uh...is your number %d?\n",guess);
	while (getchar() != 'y')
		printf("Well, then, is it %d?\n",++guess);
	printf("I knew I could do it!\n");
	return 0;
}
/* Programming Exercise 8-5 */ 
/* binaryguess.c -- an improved number-guesser */ 
/* but relies upon truthful, correct responses */ 
#include <stdio.h> 
#include <ctype.h> 
int main(void) 
{ 
  int high = 100; 
  int low = 1; 
  int guess = (high + low) / 2; 
  char response; 
  printf("Pick an integer from 1 to 100. I will try to guess "); 
  printf("it.\nRespond with a y if my guess is right, with"); 
  printf("\na h if it is high, and with an l if it is low.\n"); 
  printf("Uh...is your number %d?\n", guess); 
  while ((response = getchar()) != 'y')     /* get response */ 
  { 
      if (response == '\n') 
          continue; 
      if (response != 'h' && response != 'l') 
      { 
           printf("I don't understand that response. Please enter h for\n"); 
           printf("high, l for low, or y for correct.\n"); 
           continue; 
       } 
     
      if (response == 'h') 
          high = guess - 1; 
      else if (response == 'l') 
          low = guess + 1; 
      guess = (high + low) / 2; 
    printf("Well, then, is it %d?\n", guess); 
  } 
  printf("I knew I could do it!\n"); 
  return 0; 
}
#include <stdio.h>//个人
#define START 1
#define END 100
int main(void)
{
	int left = START;
	int right = END;
	int mid=0;
	int number;
	printf("请输入[%d,%d]范围内的整数,我会尝试猜出它:",START,END);
	while (scanf_s("%d", &number)!=1 || number < START || number > END)
	{
		printf("输入错误!请重新输入:");
		while(getchar()!='\n')//清空scanf读取的错误值
			continue;
	}
	while (left <= right)
	{
		mid = left + (right - left)/2;
		if (mid == number) 
		{
			printf("我猜到了,是%d!\n", mid);
			break; 
		}
		if (mid < number)
			left = mid + 1;
		else
			right = mid - 1;
		printf("是%d吗?\n",mid);
	}
	return 0;
}

8.6

修改程序清单8.8中的get_first函数,让该函数返回读取的第1个非空白字符,并在一个简单的程序中测试。

// get_first函数
char get_first(void);
char get_first(void)
{
	int ch;
	ch = getchar();
	while (getchar() != '\n')
		continue;
	return ch;
}
#include <stdio.h>//个人
#include <ctype.h>
char get_first(void);
int main(void)
{
	int number;
	char letter;
	printf("请先输入一个数字:");
	scanf_s("%d",&number);
	printf("\n现在输入一段字符,我将打印第一个非空字符:");
	letter = get_first();
	printf("\n%c\n",letter);
	return 0;
}
char get_first(void)
{
	int ch;
	while ((ch = getchar()) != EOF && isspace(ch))
		;
	while (getchar() != '\n')
		continue;
	return ch;
}

8.7

修改第7章的编程练习8,用字符代替数字标记菜单的选项。用q代替5作为结束输入的标记。

/* Programming Exercise 8-7 */ 
#include <stdio.h> 
#include <ctype.h> 
#include <stdio.h> 
#define BASEPAY1    8.75    // $8.75 per hour 
#define BASEPAY2    9.33    // $9.33 per hour 
#define BASEPAY3    10.00   // $10.00 per hour 
#define BASEPAY4    11.20   // $11.20 per hour 
#define BASEHRS     40      // hours at basepay 
#define OVERTIME    1.5     // 1.5 time 
#define AMT1        300     // 1st rate tier 
#define AMT2        150     // 2st rate tier 
#define RATE1       0.15    // rate for 1st tier 
#define RATE2       0.20    // rate for 2nd tier 
#define RATE3       0.25    // rate for 3rd tier 
int getfirst(void);  
void menu(void); 
int main(void)     
{ 
    double hours; 
    double gross; 
    double net; 
    double taxes; 
    double pay; 
    char response; 
     
     
    menu(); 
    while ((response = getfirst()) != 'q') 
    { 
        if (response == '\n')         /* skip over newlines     */ 
            continue; 
        response = tolower(response); /* accept A as a, etc.    */ 
        switch (response) 
        { 
            case 'a':   pay = BASEPAY1; break; 
            case 'b':   pay = BASEPAY2; break; 
            case 'c':   pay = BASEPAY3; break;
            case 'd':   pay = BASEPAY4; break; 
            default :   printf("Please enter a, b, c, d, or q.\n"); 
                        menu(); 
                        continue;   // go to beginning of loop 
        }     
        printf("Enter the number of hours worked this week: ");     
        scanf("%lf", &hours); 
        if (hours <= BASEHRS) 
            gross = hours * pay; 
        else 
            gross = BASEHRS * pay + (hours - BASEHRS) * pay * OVERTIME; 
        if (gross <= AMT1) 
            taxes = gross * RATE1; 
        else if (gross <= AMT1 + AMT2) 
            taxes = AMT1 * RATE1 + (gross - AMT1) * RATE2; 
        else 
            taxes = AMT1 * RATE1 + AMT2 * RATE2 + (gross - AMT1 - AMT2) * RATE3; 
        net = gross - taxes; 
        printf("gross: $%.2f; taxes: $%.2f; net: $%.2f\n", gross, taxes, 
                net); 
        menu(); 
    } 
    printf("Done.\n"); 
       
    return 0; 
} 
void menu(void) 
{ 
    printf("********************************************************" 
           "*********\n"); 
    printf("Enter the letter corresponding to the desired pay rate" 
           " or action:\n"); 
    printf("a)  $%4.2f/hr                b)  $%4.2f/hr\n", BASEPAY1, 
            BASEPAY2); 
    printf("c) $%5.2f/hr                d) $%5.2f/hr\n", BASEPAY3, 
            BASEPAY4); 
    printf("q) quit\n"); 
    printf("********************************************************" 
           "*********\n"); 
} 
 
int getfirst(void)  
{  
    int ch;  
  
    ch = getchar(); 
    while (isspace(ch)) 
        ch = getchar();  
    while (getchar() != '\n')  
        continue;  
    return ch;  
}
#include <stdio.h>//个人
#define BASIC_WAGE1 8.75
#define BASIC_WAGE2 9.33
#define BASIC_WAGE3 10.0
#define BASIC_WAGE4 11.2
#define TIME 40
#define OVERTIME 1.5
#define DOLLAR1 300
#define DOLLAR2 450
#define RATE1 0.15
#define RATE2 0.20
#define RATE3 0.25
int main(void)
{
	double working_hours;
	double total, taxes, net_income;
	double basic_wage;
	printf("请输入工时:");
	while (scanf_s("%lf", &working_hours) == 1)
	{
		char grade;
		printf(
			"*****************************************************************\n"

			"Enter the number corresponding to the desired pay rate or action:\n"

			"(a) $%.2lf / hr   (b) $%.2lf / hr\n"

			"(c) $%.2lf / hr   (d) $%.2lf / hr\n"

			"(q) quit\n"

			"*****************************************************************\n"
			"请输入工资等级:",
			BASIC_WAGE1, BASIC_WAGE2, BASIC_WAGE3, BASIC_WAGE4);
		while (getchar() != '\n')
			continue;
		grade=getchar();
		switch (grade)
		{
		case 'a':basic_wage = BASIC_WAGE1; break;
		case 'b':basic_wage = BASIC_WAGE2; break;
		case 'c':basic_wage = BASIC_WAGE3; break;
		case 'd':basic_wage = BASIC_WAGE4; break;
		default:goto end;
		}
		if (working_hours < 0)
		{
			printf("输入错误,请重新输入工时:");
			continue;
		}
		if (working_hours > TIME)
			working_hours = (working_hours - TIME) * OVERTIME + TIME;
		total = working_hours * basic_wage;
		if (total < DOLLAR1)
			taxes = total * RATE1;
		else if (total < DOLLAR2)
			taxes = DOLLAR1 * RATE1 + (total - DOLLAR1) * RATE2;
		else
			taxes = DOLLAR1 * RATE1 + (DOLLAR2 - DOLLAR1) * RATE2 + (total - DOLLAR2) * RATE3;
		printf("工资总额:%lf\t税金:%lf\t净收入:%lf\t\n\n", total, taxes, total - taxes);
		printf("请输入工时:");
	}
    end:printf("感谢使用该系统!\n");
	return 0;
}

8.8

编写一个程序,显示一个提供加法、减法、乘法、除法的菜单。获得用户选择的选项后,程序提示用户输入两个数字,然后执行用户刚才选择的操作。该程序只接受菜单提供的选项。程序使用float类型的变量储存用户输入的数字,如果用户输入失败,则允许再次输入。进行除法运算时,如果用户输入0作为第2个数(除数),程序应提示用户重新输入一个新值。该程序的一个运行示例如下:

Enter the operation of your choice:

a. add                s. subtract

m. multiply         d. pide

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. pide

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. pide

q. quit

q

Bye.

#include <stdio.h>//个人
#include <ctype.h>
void menu(void);
char get_choice(void);
float get_float(void);
float operation(char c);
int main(void)
{
	char choice;
	menu();
	printf("请选择要进行的运算:");
	while ((choice=get_choice())!= 'q')
	{
		printf("%.2f\n\n",operation(choice));
		menu();
		printf("请选择要进行的运算:");
	}
	return 0;
}
void menu(void)
{
	printf("两位四则运算器\n");
	printf("a.加法\ts.减法\t"
		   "m.乘法\td.除法\t"
		   "q.退出\n");
}
char get_choice(void)
{
	int ch;
	while ((ch=getchar())!=EOF && ch != 'a' && ch != 's' && ch != 'm' && ch != 'd' && ch != 'q')
	//如果输入不为菜单选项则要求用户重新输入,直至输入正确
	{
		printf("输入错误!请重新输入:");
		if (isspace(ch))//如果输入的第一个字符为空字符则要求用户重新输入,直至输入正确
			continue;
		while (getchar() != '\n')//清空错误输入
			continue;
	}
	return ch;
}
float get_float(void)
{
	float number;
	while (scanf_s("%f", &number) != 1)//输入不为数字要求用户重新输入,直至输入正确
	{
		printf("输入错误!请重新输入:");
		while (getchar() != '\n')//清空错误输入
			continue;
	}
	while (getchar() != '\n')//清空数字后的换行符
		continue;
	return number;
}
float operation(char c)
{
	float a, b;
	char operator='c';
	printf("请输入第一个数字:");
	a = get_float();
	printf("请输入第二个数字:");
	b = get_float();
	while (c == 'd' && b == 0)
	{
		printf("除数不能为0,请重新输入:");
		b = get_float();
	}
	float result=0;
	switch (c)
	{
	case 'a':result = a + b; operator='+'; break;
	case 's':result = a - b; operator='-'; break;
	case 'm':result = a * b; operator='*'; break;
	case 'd':result = a / b; operator='/'; break;
	}
	printf("%.2f%c%.2f=", a, operator,b);
	return result;
}

第九章

9.1

设计一个函数min(x, y),返回两个double类型值的较小值。在一个简单的驱动程序中测试该函数。

/* Programming Exercise 9-1 */ 
#include <stdio.h> 
 
double min(double, double); 
int main(void)
{ 
    double x, y; 
     
    printf("Enter two numbers (q to quit): "); 
    while (scanf("%lf %lf", &x, &y) == 2) 
    { 
        printf("The smaller number is %f.\n", min(x,y)); 
        printf("Next two values (q to quit): "); 
    } 
    printf("Bye!\n"); 
       
    return 0; 
} 
 
double min(double a, double b) 
{ 
    return a < b ? a : b; 
 
} 
 
/* alternative implementation 
double min(double a, double b) 
{ 
    if (a < b) 
        return a; 
    else 
        return b; 
} 
*/
#include <stdio.h>//个人
double min(double, double);
int main()
{
	double x, y;
	printf("请输入要测试的两个数:");
	scanf_s("%lf%lf",&x,&y);
	printf("较小的是:%lf\n",min(x, y));
	return 0;
}
double min(double x, double y)
{
	return (x < y) ? x : y;
}

9.2

设计一个函数chline(ch, i, j),打印指定的字符j行i列。在一个简单的驱动程序中测试该函数。

#include <stdio.h>//个人
void chline(char,int,int);
int main()
{
	char ch;
	int i, j;
	printf("请输入要打印的字符:");
	ch = getchar();
	printf("请输入要打印的行数、列数:");
	scanf_s("%d%d",&j,&i);
	chline(ch, i, j);
	return 0;
}
void chline(char ch, int i, int j)
{
	for (int n = 1; n <= j; n++)
	{
		for (int m = 1; m <= i; m++)
			printf("%c", ch);
		printf("\n");
	}
}

9.3

编写一个函数,接受3个参数:一个字符和两个整数。字符参数是待打印的字符,第1个整数指定一行中打印字符的次数,第2个整数指定打印指定字符的行数。编写一个调用该函数的程序。

/* Programming Exercise 9-3 */ 
#include <stdio.h> 
 
void chLineRow(char ch, int c, int r); 
int main(void)     
{ 
    char ch; 
    int col, row; 
     
    printf("Enter a character (# to quit): "); 
    while ( (ch = getchar()) != '#') 
    { 
        if (ch == '\n') 
            continue; 
        printf("Enter number of columns and number of rows: "); 
        if (scanf("%d %d", &col, &row) != 2) 
            break; 
        chLineRow(ch, col, row); 
        printf("\nEnter next character (# to quit): "); 
    } 
    printf("Bye!\n"); 
       
    return 0; 
} 
 
// start rows and cols at 0 
void chLineRow(char ch, int c, int r) 
{ 
    int col, row; 
 
    for (row = 0; row < r ; row++) 
    {
         for (col = 0; col < c; col++) 
            putchar(ch); 
        putchar('\n'); 
    } 
    return; 
}
#include <stdio.h>//个人
void chline(char,int,int);
int main()
{
	char ch;
	int i, j;
	printf("请输入要打印的字符:");
	ch = getchar();
	printf("请输入要打印的行数、列数:");
	scanf_s("%d%d",&j,&i);
	chline(ch, i, j);
	return 0;
}
void chline(char ch, int i, int j)
{
	for (int n = 1; n <= i; n++)
	{
		for (int m = 1; m <= j; m++)
			printf("%c", ch);
		printf("\n");
	}
}

9.4

两数的调和平均数这样计算:先得到两数的倒数,然后计算两个倒数的平均值,最后取计算结果的倒数。编写一个函数,接受两个double类型的参数,返回这两个参数的调和平均数。

#include <stdio.h>//个人
double harmonic_mean(double,double);
int main()
{
	double a, b;
	printf("请输入要计算调和平均值的两个数:");
	scanf_s("%lf%lf",&a,&b);
	printf("调和平均值为:%lf\n",harmonic_mean(a,b));
	return 0;
}
double harmonic_mean(double a, double b)
{
	double reciprocal_a = a / a / a;
	double reciprocal_b = b / b / b;
	double average_value = (reciprocal_a + reciprocal_b) / 2;
	double reciprocal_average_value = average_value / average_value / average_value;
	return reciprocal_average_value;
}

9.5

编写并测试一个函数larger_of,该函数把两个double类型变量的值替换为较大的值。例如, larger_of(x, y)会把x和y中较大的值重新赋给两个变量。

/* Programming Exercise 9-5 */ 
#include <stdio.h> 
 
void larger_of(double *p1, double *p2); 
int main(void)     
{ 
    double x, y; 
     
    printf("Enter two numbers (q to quit): "); 
    while (scanf("%lf %lf", &x, &y) == 2) 
    { 
        larger_of(&x, &y); 
        printf("The modified values are %f and %f.\n", x, y); 
        printf("Next two values (q to quit): "); 
    } 
    printf("Bye!\n"); 
       
    return 0; 
} 
 
void larger_of(double *p1, double *p2) 
{ 
    if (*p1 > *p2) 
        *p2 = *p1; 
    else 
        *p1 = *p2; 
} 
 
 
// alternatively: 
/* 
void larger_of(double *p1, double *p2) 
{ 
    *p1= *p2 = *p1 > *p2 ? *p1 : *p2; 
} 
*/
#include <stdio.h>//个人
void larger_of(double*, double*);
int main()
{
	double x, y;
	printf("请输入两个数:");
	scanf_s("%lf%lf", &x, &y);
	larger_of(&x, &y);
	printf("\n%lf %lf", x, y);
	return 0;
}

void larger_of(double* x, double* y)
{
	(*x > * y) ? (*y = *x) : (*x = *y);
}

9.6

编写并测试一个函数,该函数以3个double变量的地址作为参数,把最小值放入第1个变量,中间值放入第2个变量,最大值放入第3个变量。

#include <stdio.h>//个人
void sort3(double*, double*, double*);
int main()
{
	double a, b, c;
	printf("请输入三个数:");
	scanf_s("%lf %lf %lf",&a,&b,&c);
	sort3(&a, &b, &c);
	printf("\n%.2lf %.2lf %.2lf",a,b,c);
	return 0;
}

void sort3(double* x, double* y, double* z)
{
	double number[3] = { *x,*y,*z };
	double temp = 0;
	for (int i = 0; i < 2; i++) 
	{
		for (int j = 0; j < 2 - i; j++) 
		{
			if (number[j] > number[j + 1]) 
			{
				double temp = number[j];
				number[j] = number[j + 1];
				number[j + 1] = temp;
			}
		}
	}
	*x = number[0];
	*y = number[1];
	*z = number[2];
}

void sort3(double* x, double* y, double* z)
//{
//	double a = *x, b = *y, c = *z;
//	double temp;
//
//	// 三个数的简单排序
//	if (a > b) { temp = a; a = b; b = temp; }
//	if (a > c) { temp = a; a = c; c = temp; }
//	if (b > c) { temp = b; b = c; c = temp; }
//
//	*x = a;
//	*y = b;
//	*z = c;
//}

9.7

编写一个函数,从标准输入中读取字符,直到遇到文件结尾。程序要报告每个字符是否是字母。如果是,还要报告该字母在字母表中的数值位置。例如,c和C在字母表中的位置都是3。合并一个函数,以一个字符作为参数,如果该字符是一个字母则返回一个数值位置,否则返回-1。

#include <stdio.h>//个人
#include <ctype.h>
void word(void);
void get(void);
int letter(char);
int main()
{
	printf("请输入文本,以^z结尾:");
	word();
	return 0;
}

void word(void)
{
	int ch;
	while ((ch = getchar()) != EOF)
	{
		if (letter(ch) == -1)
			printf("'%c'不是字母\n", ch);
		else
			printf("'%c'是字母,位置%d\n", ch, letter(ch));
	}
}

int letter(char a)
{
	if (isalpha(a))
		if ((int)a < 97)
			return ((int)a - 64);
		else
			return ((int)a - 96);
	else
		return -1;
}

9.8

第 6 章的程序清单 6.20 中,power()函数返回一个 double 类型数的正整数次幂。改进该函数,使其能正确计算负幕。另外, 函数要处理 0 的任何次幕都为 0,任何数的 0 次幕都为 1 (函数报告 0 的0 次幂未定义, 因此把该值处理为 1)。要使用一个循环,并在程序中测试该函数。

//程序清单 6.20 power.c程序    //此非答案,而是题目的一部分
// power.c -- 计算数的整数幂
#include <stdio.h>
double power(double n, int p); // ANSI 函数原型
int main(void)
{
    double x, xpow;
    int exp;
    
    printf("Enter a number and the positive integer power");
    printf(" to which\nthe number will be raised. Enter q");
    printf(" to quit.\n");
    while (scanf("%lf%d", &x, &exp) == 2)
    {
        xpow = power(x,exp);   // 函数调用
        printf("%.3g to the power %d is %.5g\n", x, exp, xpow);
        printf("Enter next pair of numbers or q to quit.\n");
    }
    printf("Hope you enjoyed this power trip -- bye!\n");
    
    return 0;
}

double power(double n, int p)  // 函数定义
{
    double pow = 1;
    int i;
    
    for (i = 1; i <= p; i++)
        pow *= n;
    
    return pow;                // 返回pow的值
}
/* Programming Exercise 9-8 */ 
#include <stdio.h> 
double power(double a, int b);  /* ANSI prototype */ 
int main(void) 
{ 
  double x, xpow; 
  int n; 
 
  printf("Enter a number and the integer power"); 
  printf(" to which\nthe number will be raised. Enter q"); 
  printf(" to quit.\n"); 
  while (scanf("%lf%d", &x, &n) == 2) 
  { 
       xpow = power(x,n);       /* function call           */ 
       printf("%.3g to the power %d is %.5g\n", x, n, xpow); 
       printf("Enter next pair of numbers or q to quit.\n");
  } 
  printf("Hope you enjoyed this power trip -- bye!\n"); 
  return 0; 
} 
 
double power(double a, int b)   /* function definition     */ 
{ 
  double pow = 1; 
  int i; 
   
  if (b == 0) 
  { 
      if (a == 0) 
          printf("0 to the 0 undefined; using 1 as the value\n"); 
      pow = 1.0; 
  } 
  else if (a == 0) 
      pow = 0.0; 
  else if (b > 0) 
      for(i = 1; i <= b; i++) 
       pow *= a; 
  else    /* b < 0 */ 
      pow = 1.0 / power(a, - b); 
  return pow;                  /* return the value of pow  */ 
}
#include <stdio.h>//个人
double power(double n, int p); // ANSI 函数原型
int main(void)
{
    double x, xpow;
    int exp;

    printf("Enter a number and the positive integer power");
    printf(" to which\nthe number will be raised. Enter q");
    printf(" to quit.\n");
    while (scanf_s("%lf%d", &x, &exp) == 2)
    {
        xpow = power(x, exp);   // 函数调用
        printf("%.3g to the power %.d is %.5g\n", x, exp, xpow);
        printf("Enter next pair of numbers or q to quit.\n");
    }
    printf("Hope you enjoyed this power trip -- bye!\n");

    return 0;
}

double power(double n, int p)  // 函数定义
{
    if (n == 0 && p == 0)
        printf("无定义!\n");
    double pow = 1;
    int i;
    if (p > 0)
        for (i = 1; i <= p; i++)
            pow *= n;
    else if (p == 0)
        pow = 1;
    else
        for (i = 1; i <= -p; i++)
            pow /= n;

    return pow;                // 返回pow的值
}

9.9

使用递归函数重写编程练习 8。

#include <stdio.h>//个人
double power(double n, int p); // ANSI 函数原型
int main(void)
{
    double x, xpow;
    int exp;

    printf("Enter a number and the positive integer power");
    printf(" to which\nthe number will be raised. Enter q");
    printf(" to quit.\n");
    while (scanf_s("%lf%d", &x, &exp) == 2)
    {
        xpow = power(x, exp);   // 函数调用
        printf("%.3g to the power %.d is %.5g\n", x, exp, xpow);
        printf("Enter next pair of numbers or q to quit.\n");
    }
    printf("Hope you enjoyed this power trip -- bye!\n");

    return 0;
}

double power(double n, int p)  // 函数定义
{
    if (n == 0 && p == 0)
        printf("无定义!\n");
    double pow = 1;
    int i;
    if (p > 0)
        pow = n * power(n, p - 1);
    else if (p == 0)
        pow = 1;
    else
        pow = n / n / n / power(n, -p - 1);

    return pow;                // 返回pow的值
}

9.10

为了 让程序清单 9.8 中的 to_binary()函数更通用,编写一个 to_base_n()函数接受两个参数,且第二个参数在2~10范围内,然后以第 2 个参数中指定的进制打印第1 个参数的数值。例如,to_base_n(129,8)显示的结果为 201,也就是129 的八进制数。在一个完整的程序中测试该函数。

//程序清单 9.8 binary.c程序    此非答案,而是题目的一部分
/* binary.c -- 以二进制形式打印整数 */
#include <stdio.h>
void to_binary(unsigned long n);

int main(void)
{
    unsigned long number;
    printf("Enter an integer (q to quit):\n");
    while (scanf("%lu", &number) == 1)
    {
        printf("Binary equivalent: ");
        to_binary(number);
        putchar('\n');
        printf("Enter an integer (q to quit):\n");
    }
    printf("Done.\n");
    
    return 0;
}

void to_binary(unsigned long n)   /* 递归函数 */
{
    int r;
    
    r = n % 2;
    if (n >= 2)
        to_binary(n / 2);
     putchar(r == 0 ? '0' : '1');
    
    return;
}
/* Programming Exercise 9-10 */ 
#include <stdio.h> 
void to_base_n(int x, int base); 
int main(void) 
{ 
  int number; 
  int b; 
  int count; 
   
  printf("Enter an integer (q to quit):\n"); 
  while (scanf("%d", &number) == 1) 
  { 
     printf("Enter number base (2-10): "); 
     while ((count = scanf("%d", &b))== 1 
            &&  (b < 2 || b > 10)) 
     { 
         printf("base should be in the range 2-10: "); 
     } 
     if (count != 1) 
         break; 
     printf("Base %d equivalent: ", b); 
     to_base_n(number, b); 
     putchar('\n'); 
     printf("Enter an integer (q to quit):\n"); 
  } 
  printf("Done.\n"); 
  return 0; 
} 
 
void to_base_n(int x, int base)   /* recursive function */ 
{ 
  int r; 
 
  r = x % base; 
  if (x >= base) 
     to_base_n(x / base, base);
  putchar('0' + r); 
  return; 
}
#include <stdio.h>//个人
void to_binary(unsigned long n, unsigned int a);

int main(void)
{
    unsigned long number;
    unsigned int binary;
    printf("Enter an integer (q to quit):\n");
    while (scanf_s("%lu%lu", &number,&binary) == 2)
    {
        printf("Binary equivalent: ");
        to_binary(number,binary);
        putchar('\n');
        printf("Enter an integer (q to quit):\n");
    }
    printf("Done.\n");

    return 0;
}

void to_binary(unsigned long n,unsigned int a)
{
    int r;

    r = n % a;
    if (n >= a)
        to_binary(n / a,a);
    printf("%d",n%a);

    return;
}

9.11

编写并测试 Fibonacci()函数,该函数用循环代替递归计算斐波那契数。

斐波那契数列是指这样一个数列:0,1,1,2,3,5,8,13,21,34,55,89……这个数列从第3项开始 ,每一项都等于前两项之和。

(斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称“兔子数列”,其数值为:0、1、1、2、3、5、8、13、21、34……在数学上,这一数列以如下递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。)

unsigned long Fibonacci(unsigned n)//递归写法
{
    if (n > 2)
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    else
        return 1;
}
#include <stdio.h>//个人
void Fibonacci(unsigned n);
int main(void)
{
    unsigned Number_of_items;
    printf("请输入项数:");
    scanf_s("%u",&Number_of_items);
    Fibonacci(Number_of_items);
    return 0;
}
void Fibonacci(unsigned n)
{
    if (n == 0)
    {
        printf("项数为0,无输出\n");
        return;
    }
    unsigned sequence[n];
    sequence[0] = 0;
    if (n >= 2)
        sequence[1] = 1;
    sequence[1] = 1;
    for (unsigned i = 2; i < n; i++)
    {
        sequence[i] = sequence[i - 1] + sequence[i - 2];
    }
    for (unsigned i = 0; i < n; i++)
        printf("%u ",sequence[i]);
}

第十章

10.1

修改程序清单 10.7的 rain.c 程序,用指针进行计算 (仍然要声明并初始化数组)。

/* rain.c  -- finds yearly totals, yearly average, and monthly
 average for several years of rainfall data */
#include <stdio.h>    //此非答案,而是题目的一部分
#define MONTHS 12    // number of months in a year
#define YEARS   5    // number of years of data
int main(void)
{
    // initializing rainfall data for 2010 - 2014
    const float rain[YEARS][MONTHS] =
    {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    int year, month;
    float subtot, total;
    
    printf(" YEAR    RAINFALL  (inches)\n");
    for (year = 0, total = 0; year < YEARS; year++)
    {             // for each year, sum rainfall for each month
        for (month = 0, subtot = 0; month < MONTHS; month++)
            subtot += rain[year][month];
        printf("%5d %15.1f\n", 2010 + year, subtot);
        total += subtot; // total for all years
    }
    printf("\nThe yearly average is %.1f inches.\n\n",
           total/YEARS);
    printf("MONTHLY AVERAGES:\n\n");
    printf(" Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct ");
    printf(" Nov  Dec\n");
    
    for (month = 0; month < MONTHS; month++)
    {             // for each month, sum rainfall over years
        for (year = 0, subtot =0; year < YEARS; year++)
            subtot += rain[year][month];
        printf("%4.1f ", subtot/YEARS);
    }
    printf("\n");
    
    return 0;
}
/* Programming Exercise 10-1 */ 
#include <stdio.h> 
#define MONTHS 12    // number of months in a year 
#define YRS   5      // number of years of data 
int main(void) 
{ 
 // initializing rainfall data for 2010 - 2014 
    const float rain[YRS][MONTHS] = { 
     {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6}, 
     {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3}, 
     {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4}, 
     {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2}, 
     {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2} 
    }; 
    int year, month; 
    float subtot, total; 
     
    printf(" YEAR    RAINFALL  (inches)\n"); 
    for (year = 0, total = 0; year < YRS; year++) 
    {             /* for each year, sum rainfall for each month */ 
        for (month = 0, subtot = 0; month < MONTHS; month++) 
            subtot += *(*(rain + year) + month); 
        printf("%5d %15.1f\n", 2010 + year, subtot); 
        total += subtot;                  /* total for all years */ 
    } 
    printf("\nThe yearly average is %.1f inches.\n\n", total/YRS); 
    printf("MONTHLY AVERAGES:\n\n"); 
    printf(" Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct "); 
    printf(" Nov  Dec\n"); 
     
    for (month = 0; month < MONTHS; month++) 
    {               /* for each month, sum rainfall over years */ 
        for (year = 0, subtot =0; year < YRS; year++) 
            subtot += *(*(rain + year) + month); 
        printf("%4.1f ", subtot/YRS); 
    } 
    printf("\n"); 
    return 0; 
}
#include <stdio.h> //个人
#define MONTHS 12
#define YEARS   5
int main(void)
{
    const float rain[YEARS][MONTHS] =
    {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    float subtot;
    float total=0;
    for (int year = 0; year < YEARS; year++)
    {
        subtot = 0;
        for (int month = 0; month < MONTHS; month++)
        {
            //printf("%f ", *(*(rain + year) + month));
            subtot += *(*(rain + year) + month);
        }
        //printf("\n");
        printf("第%d年总降水量%.1f\n", 2010+year, subtot);
        total += subtot;
    }
    printf("5年总计降水量:%.1f\n",total);
    printf("5年平均降水量:%.1f\n\n", total/YEARS);
    for (int month = 0; month < MONTHS; month++)
    {
        subtot = 0;
        for (int year = 0; year < YEARS; year++)
        {
            subtot += *(*(rain + year) + month);
        }
        printf("%d月平均降水量:%.1f\n",month+1,subtot/5);
    }
    return 0;
}

10.2

编写一个程序,初始化一个 double 类型的数组,然后把该数组的内容拷贝至3个其他数组中 (在
main()中声明这4个数组)。使用带数组表示法的函数进行第1份拷贝。使用带指针表示法和指针递增的函数进行第2份拷贝。把目标数组名、源数组名和待拷贝的元素个数作为前两个函数的参数。第3个函数以目标数组名、源数组名和指向源数组最后一个元素后面的元素的指针。也就是说,给定以下声明,则函数调用如下所示:
double source[5] = { 1.1,2.2,3.3,4.4,5.5 };
double target1[5];
double target2[5];
double target3[5];
copy_arr(target1, source, 5);
copy_ptr(target2, source, 5);
copy_ptrs(target3, source, source + 5);

#include <stdio.h> //个人
void copy_arr(double [],double [],int);
void copy_ptr(double*, double*, int);
void copy_ptrs(double*, double*, double*);
void show_arr(double[],int);
int main(void)
{
    double source[5] = { 1.1,2.2,3.3,4.4,5.5 };
    double target1[5];
    double target2[5];
    double target3[5];
    copy_arr(target1, source, 5);
    show_arr(target1,5);
    copy_ptr(target2, source, 5);
    show_arr(target2, 5);
    copy_ptrs(target3, source, source + 5);
    show_arr(target3, 5);
    return 0;
}

void copy_arr(double target[], double source[], int size)
{
    for (int i = 0; i < size; i++)
        target[i] = source[i];
}

void copy_ptr(double* target, double* source, int size)
{
    for (int i = 0; i < size; i++)
    {
        *target = *source;
        target++;
        source++;
    }
}

void copy_ptrs(double* target, double* source, double* tail)
{
    for (; source <= tail; source++)
    {
        *target = *source;
        target++;
    }
}

void show_arr(double arr[],int size)
{
    for (int i = 0; i < size; i++)
        printf("%.1lf ", arr[i]);
    printf("\n");
}

10.3

编写一个函数,返回储存在 int 类型数组中的最大值,并在一个简单的程序中测试该函数。

/* Programming Exercise 10-3 */ 
#include <stdio.h> 
#define LEN 10  
 
int max_arr(const int ar[], int n); 
void show_arr(const int ar[], int n); 
 
int main(void) 
{ 
    int orig[LEN] = {1,2,3,4,12,6,7,8,9,10}; 
    int max; 
    show_arr(orig, LEN); 
    max = max_arr(orig, LEN); 
    printf("%d = largest value\n", max); 
     
    return 0; 
} 
 
int max_arr(const int ar[], int n) 
{ 
    int i; 
    int max = ar[0]; 
/* don't use 0 as initial max value -- fails if all array values are neg */ 
     
    for (i = 1; i < n; i++) 
        if (max < ar[i]) 
            max = ar[i]; 
    return max; 
} 
 
void show_arr(const int ar[], int n) 
{ 
    int i; 
     
    for (i = 0; i < n; i++) 
        printf("%d ", ar[i]); 
    putchar('\n'); 
}
#include <stdio.h> //个人
int max_number(int[],int);
int main(void)
{
    int number[10] = { 1,2,3,52,5,6,7,66,9,10 };
    printf("%d\n",max_number(number, 10));
    return 0;
}

int max_number(int a[],int lenth)
{
    int max=a[0];
    for (int i = 0; i < lenth; i++)
    {
        if (max < a[i])
            max = a[i];
    }
    return max;
}

10.4

编写一个函数,返回储存在 doouble 类型数组中最大值的下标,并在一个简单的程序中测试该函数。

#include <stdio.h> //个人
int max_number(double[],int);
int main(void)
{
    double number[10] = { 1,2,3,52,502,88,7,66,9,100 };
    printf("%d\n",max_number(number, 10));
    return 0;
}

int max_number(double a[],int lenth)
{
    double max=a[0];
    int subscript = 0;
    for (int i = 0; i < lenth; i++)
    {
        if (max < a[i])
            max = a[i];
    }
    for (int i = 0; i < lenth; i++)
    {
        if (max == a[i])
            subscript = i;
    }
    return subscript;
}

10.5

编写一个函数,返回储存在 double 类型数组中最大值和最小值的差值,并在一个简单的程序中测
试该函数。

/* Programming Exercise 10-5 */ 
#include <stdio.h> 
#define LEN 10  
 
double  max_diff(const double  ar[], int n); 
void show_arr(const double  ar[], int n); 
 
int main(void) 
{ 
    double  orig[LEN] = {1.1,2,3,4,12,61.3,7,8,9,10}; 
    double  max; 
     
    show_arr(orig, LEN); 
    max = max_diff(orig, LEN); 
    printf("%g = maximum difference\n", max); 
     
    return 0; 
} 
 
double  max_diff(const double  ar[], int n) 
{ 
    int i; 
    double  max = ar[0]; 
    double  min = ar[0]; 
     
    for (i = 1; i < n; i++) 
    { 
        if (max < ar[i]) 
            max = ar[i]; 
        else if (min > ar[i])   
            min = ar[i]; 
    } 
    return max - min; 
}

void show_arr(const double  ar[], int n) 
{ 
    int i; 
     
    for (i = 0; i < n; i++) 
        printf("%g ", ar[i]); 
    putchar('\n'); 
}
#include <stdio.h> //个人
int max_diff(double[],int);
int main(void)
{
    double number[10] = { 3,2,3,52,502,88,7,66,9,100 };
    printf("%d\n",max_diff(number, 10));
    return 0;
}

int max_diff(double a[],int lenth)
{
    double max = a[0];
    double min = a[0];
    int subscript = 0;
    for (int i = 0; i < lenth; i++)
    {
        if (max < a[i])
            max = a[i];
        if (min > a[i])
            min = a[i];
    }
    return max-min;
}

10.6

编写一个函数,返回double类型数组中的倒序排列,并在一个简单的程序中测试该函数。

#include <stdio.h> //个人
reverse_order(const double[],double[],int);
show_arr(const double[],int);
int main(void)
{
    double number[10] = { 1,2,3,4,5,6,7,8,9,10 };
	double reverse[10];
	reverse_order(number, reverse, 10);
	show_arr(number,10);
	show_arr(reverse,10);
    return 0;
}

reverse_order(const double a[],double b[],int length)
{
	for (int i = 0; i < length; i++)
		b[i] = a[length - i-1];
}

show_arr(const double a[],int length)
{
	for (int i = 0; i < length; i++)
		printf("%lf ", a[i]);
	printf("\n");
}

10.7

编写一个程序,初始化一个 double 类型的二维数组,使用编程练习 2 中的一个拷贝函数把该数组
中的数据拷贝至另一个二维数组中(因为二维数组是数组的数组,所以可以使用处理一维数组的拷
贝函数来处理数组中的每个子数组)。

#include <stdio.h> //个人
void copy_arr(double [],double [],int);
void show_arr2(double[][2],int);
int main(void)
{
    double source1[2] = { 1.1,2.2 };
    double source2[2] = { 3.3,4.4 };
    double source3[2] = { 5.5,6.6 };
    double target[3][2];
    copy_arr(target[0], source1, 2);
    copy_arr(target[1], source2, 2);
    copy_arr(target[2], source3, 2);
    show_arr2(target, 3);
    return 0;
}

void copy_arr(double target[], double source[], int size)
{
    for (int i = 0; i < size; i++)
        target[i] = source[i];
}

void show_arr2(double arr[][2], int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < 2; j++)
            printf("%.1lf ", arr[i][j]);
        printf("\n");
    }
}

10.8

使用编程练习2中的拷贝函数,把一个内含7个元素的数组中第3~5个元素拷贝至内含3个元素的数组中。该函数本身不需要修改,只需要选择合适的实际参数(实际参数不需要是数组名和数组大小,只需要是数组元素的地址和待处理元素的个数)。

/* Programming Exercise 10-8 */ 
#include <stdio.h> 
#define LEN1 7  
#define LEN2 3 
 
void copy_arr(int ar1[], const int ar2[], int n); 
void show_arr(const int [], int); 
 
int main(void) 
{ 
    int orig[LEN1] = {1,2,3,4,5,6,7}; 
    int copy[LEN2]; 
     
    show_arr(orig, LEN1); 
    copy_arr(copy, orig + 2, LEN2); 
    show_arr(copy, LEN2); 
         
    return 0; 
} 
 
void copy_arr(int ar1[], const int ar2[], int n) 
{ 
    int i; 
     
    for (i = 0; i < n; i++) 
        ar1[i] = ar2[i]; 
} 
 
void show_arr(const int ar[], int n) 
{ 
    int i; 
     
    for (i = 0; i < n; i++) 
        printf("%d ", ar[i]); 
    putchar('\n'); 
} 
#include <stdio.h> //个人
void copy_arr(double [],double [],int);
void copy_ptr(double*, double*, int);
void copy_ptrs(double*, double*, double*);
void show_arr1(double[],int);
int main(void)
{
    double source[] = { 1,2,3,4,5,6,7 };
    double target[] = { 8,9,10 };
    show_arr1(target, 3);
    //copy_arr(target, source + 2, 3);
    //copy_ptr(target, source + 2, 3);
    copy_ptrs(target, source + 2, source + 4);
    show_arr1(target, 3);
    return 0;
}

void copy_arr(double target[], double source[], int size)
{
    for (int i = 0; i < size; i++)
        target[i] = source[i];
}

void copy_ptr(double* target, double* source, int size)
{
    for (int i = 0; i < size; i++)
    {
        *target = *source;
        target++;
        source++;
    }
}

void copy_ptrs(double* target, double* source, double* tail)
{
    for (; source <= tail; source++)
    {
        *target = *source;
        target++;
    }
}

void show_arr1(double arr[],int size)
{
    for (int i = 0; i < size; i++)
        printf("%.1lf ", arr[i]);
    printf("\n");
}

10.9

编写一个程序,初始化一个 double 类型的 3×5二维数组,使用一个处理变长数组的函数将其拷
贝至另一个二维数组中。还要编写一个以变长数组为形参的函数以显示两个数组的内容。这两个函
数应该能处理任意N×M数组(如果编译器不支持变长数组,就使用传统C函数处理N×5的数组)。

#include <stdio.h> //个人
void copy_arr(double[][5],double[][5],int);
void show_arr2(double[][5],int);
int main(void)
{
    double source[3][5] =
    {
        {1,2,3,4,5},
        {6,7,8,9,10},
        {11,12,13,14,15}
    };
    double target[3][5];
    copy_arr(target, source, 3);
    show_arr2(target,3);
    return 0;
}

void copy_arr(double target[][5],double source[][5],int n)
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < 5; j++)
            target[i][j] = source[i][j];
}

void show_arr2(double arr[][5], int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < 5; j++)
            printf("%.1lf ", arr[i][j]);
        printf("\n");
    }
}

10.10

编写一个函数,把两个数组中相对应的元素相加,然后把结果储存到第3个数组中。也就是说,
如果数组1中包含的值是2、4、5、8,数组2中包含的值是1、0、4、6,那么该函数把3、4、
9、14 赋给第3个数组。函数接受3个数组名和一个数组大小。在一个简单的程序中测试该函数。

#include <stdio.h> //个人
void sum_arr(int[], int[], int[], int);
void show_arr(int[], int);
int main(void)
{
    int arr1[] = { 2,4,5,8 };
    int arr2[] = { 1,0,4,6 };
    int result_arr[4];
    sum_arr(arr1, arr2, result_arr, 4);
    show_arr(result_arr,4);
    return 0;
}

void sum_arr(int addend1[], int addend2[], int result[], int size)
{
    for (int i = 0; i < size; i++)
        result[i] = addend1[i] + addend2[i];
}

void show_arr(int arr[], int size)
{
    for (int i = 0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

10.11

编写一个程序,声明一个 int 类型的 3×5二维数组,并用合适的值初始化它。该程序打印数组中的值,然后各值翻倍(即是原值的2倍),并显示出各元素的新值。编写一个函数显示数组的内容,再编写一个函数把各元素的值翻倍。这两个函数都以函数名和行数作为参数。

/* Programming Exercise 10-11 */ 
#include <stdio.h> 
#define ROWS 3 
#define COLS 5  
 
void times2(int ar[][COLS], int r); 
void showarr2(int ar[][COLS], int r); 
 
int main(void) 
{ 
    int stuff[ROWS][COLS] = {    {1,2,3,4,5}, 
                                {6,7,8,-2,10}, 
                                {11,12,13,14,15}
                            }; 
    showarr2(stuff, ROWS); 
    putchar('\n'); 
    times2(stuff, ROWS); 
    showarr2(stuff, ROWS); 
         
    return 0; 
} 
 
void times2(int ar[][COLS], int r) 
{ 
    int row, col; 
     
    for (row = 0; row < r; row++) 
        for (col = 0; col < COLS; col++) 
            ar[row][col] *= 2; 
 
} 
 
void showarr2(int ar[][COLS], int r) 
{ 
    int row, col; 
     
    for (row = 0; row < r; row++) 
    { 
        for (col = 0; col < COLS; col++) 
            printf("%d ", ar[row][col]); 
        putchar('\n'); 
    } 
}
#include <stdio.h> //个人
void two_times(int[][5], int);
void show_arr(int[][5], int);
int main(void)
{
    int source[][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };
	show_arr(source, 3);
	two_times(source, 3);
	show_arr(source, 3);
    return 0;
}

void two_times(int source[][5], int rows)
{
	for (int i = 0; i < rows; i++)
		for (int j = 0; j < 5; j++)
			source[i][j] *= 2;
}

void show_arr(int source[][5], int rows)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < 5; j++)
			printf("%d ", source[i][j]);
		printf("\n");
	}
}

10.12

重写程序清单 10.7 的 rain.c 程序,把 main()中的主要任务都改成用函数来完成。

/* rain.c  -- finds yearly totals, yearly average, and monthly
 average for several years of rainfall data */
#include <stdio.h>
#define MONTHS 12    // number of months in a year
#define YEARS   5    // number of years of data
int main(void)        //此非答案,而是题目的一部分
{
    // initializing rainfall data for 2010 - 2014
    const float rain[YEARS][MONTHS] =
    {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    int year, month;
    float subtot, total;

    printf(" YEAR    RAINFALL  (inches)\n");
    for (year = 0, total = 0; year < YEARS; year++)
    {             // for each year, sum rainfall for each month
        for (month = 0, subtot = 0; month < MONTHS; month++)
            subtot += rain[year][month];
        printf("%5d %15.1f\n", 2010 + year, subtot);
        total += subtot; // total for all years
    }
    printf("\nThe yearly average is %.1f inches.\n\n",
        total / YEARS);
    printf("MONTHLY AVERAGES:\n\n");
    printf(" Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct ");
    printf(" Nov  Dec\n");

    for (month = 0; month < MONTHS; month++)
    {             // for each month, sum rainfall over years
        for (year = 0, subtot = 0; year < YEARS; year++)
            subtot += rain[year][month];
        printf("%4.1f ", subtot / YEARS);
    }
    printf("\n");
    return 0;
}
#include <stdio.h> //个人
#define MONTHS 12
#define YEARS   5
float each_year(float[][12], int);
void each_month(float[][12], int);
int main(void)
{
    const float rain[YEARS][MONTHS] =
    {
        {4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
        {8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
        {9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
        {7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
        {7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
    };
    printf(" YEAR    RAINFALL  (inches)\n");
    each_year(rain, 5);
    printf("\nThe yearly average is %.1f inches.\n\n",
        each_year(rain, 5) / YEARS);
    printf("MONTHLY AVERAGES:\n\n");
    printf(" Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct ");
    printf(" Nov  Dec\n");
    each_month(rain, 5);
    return 0;
}

float each_year(float arr[][12], int length)
{
    float subtot, total=0;
    for (int i = 0; i < length; i++)
    {
        subtot = 0;
        for (int j = 0; j < 12; j++)
            subtot += arr[i][j];
        printf("%5d %15.1f\n", 2010 + i, subtot);
        total += subtot;
    }
    return total;
}

void each_month(float arr[][12], int length)
{
    float subtot;
    for (int i = 0; i < 12; i++)
    {
        subtot = 0;
        for(int j=0;j<length;j++)
            subtot += arr[j][i];
        printf("%4.1f ", subtot / YEARS);
    }
    printf("\n");
}

10.13

编写一个程序,提示用户输入 3 组数,每组数包含5个 double 类型的数 (假设用户都正确地响
应,不会输入非数值数据)。该程序应完成下列任务。
a.把用户输入的数据储存在3×5的数组中
b.计算每组(5个)数据的平均值
c.计算所有数据的平均值
d.找出这 15 个数据中的最大值

e.打印结果
每个任务都要用单独的函数来完成(使用传统C处理数组的方式)。完成任务b,要编写一个计算
并返回一维数组平均值的函数,利用循环调用该函数3次。对于处理其他任务的函数,应该把整
个数组作为参数,完成任务c和d的函数应把结果返回主调函数。

#include <stdio.h> //个人
#define ROWS 3
#define COLS 5
void get_arr(double[][COLS],int);
double five_average(double[], int);
double total_average(double[][COLS], int);
double max_arr(double[][COLS], int);
void print(double[][COLS], int);
int main(void)
{
    double arr[ROWS][COLS];
    get_arr(arr, ROWS);
    print(arr, ROWS);
    return 0;
}

void get_arr(double arr[][COLS], int row)
{
    for (int i = 0; i < row; i++)
    {
        printf("\n请输入第%d组数:", i + 1);
        for (int j = 0; j < COLS; j++)
            scanf_s("%lf", &arr[i][j]);
    }
}

double five_average(double arr[], int cols)
{
    double sum = 0;
    double average = 0;
    for (int i = 0; i < cols; i++)
    {
        sum += arr[i];
    }
    average = sum / cols;
    return average;
}

double total_average(double arr[][COLS], int rows)
{
    double sum = 0;
    double average = 0;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < COLS; j++)
            sum += arr[i][j];
    average = sum / (rows * COLS);
    return average;
}

double max_arr(double arr[][COLS], int rows)
{
    double max=arr[0][0];
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < COLS; j++)
            if (max < arr[i][j])
                max = arr[i][j];
    return max;
}

void print(double arr[][COLS], int rows)
{
    for (int i = 0; i < ROWS; i++)
        printf("%d组的平均值为%lf\n", i + 1, five_average(arr[i], COLS));
    printf("平均值:%lf\n", total_average(arr, rows));
    printf("最大值:%lf\n", max_arr(arr, rows));
}

10.14

以变长数组作为函数形参,完成编程练习13。

/* Programming Exercise 10-14 */ 
#include <stdio.h> 
#define ROWS 3 
#define COLS 5  
 
void store(double ar[], int n); 
double average2d(int rows, int cols, double ar[rows][cols]); 
double max2d(int rows, int cols, double ar[rows][cols]); 
void showarr2(int rows, int cols, double ar[rows][cols]); 
double average(const double ar[], int n); 
 
int main(void) 
{ 
    double stuff[ROWS][COLS]; 
    int row; 
     
    for (row = 0; row < ROWS; row++) 
    { 
        printf("Enter %d numbers for row %d\n", COLS, row + 1); 
        store(stuff[row], COLS); 
    } 
     
    printf("array contents:\n"); 
    showarr2(ROWS, COLS, stuff); 
     
    for (row = 0; row < ROWS; row++) 
        printf("average value of row %d = %g\n", row + 1, average(stuff[row], COLS)); 
    printf("average value of all rows = %g\n", average2d(ROWS, COLS, stuff)); 
    printf("largest value = %g\n", max2d(ROWS, COLS, stuff));  
    printf("Bye!\n");     
    return 0; 
} 
 
void store(double ar[], int n) 
{ 
    int i; 
    for (i = 0; i < n; i++) 
    { 
        printf("Enter value #%d: ", i + 1); 
        scanf("%lf", & ar[i]); 
    } 
}  
 
double average2d(int rows, int cols, double ar[rows][cols]) 
{ 
    int r, c; 
    double sum = 0.0; 
     
    for (r = 0; r < rows; r++) 
        for (c = 0; c < cols; c++) 
            sum += ar[r][c]; 
    if (rows * cols > 0) 
        return sum / (rows * cols); 
    else 
        return 0.0; 
} 
 
double max2d(int rows, int cols, double ar[rows][cols]) 
{ 
    int r, c; 
    double max = ar[0][0]; 
     
    for (r = 0; r < rows; r++) 
        for (c = 0; c < cols; c++) 
            if (max < ar[r][c]) 
                max = ar[r][c]; 
    return max; 
} 
 
void showarr2(int rows, int cols, double ar[rows][cols]) 
{ 
    int row, col; 
     
    for (row = 0; row < rows; row++) 
    { 
        for (col = 0; col < cols; col++) 
            printf("%g ", ar[row][col]); 
        putchar('\n'); 
    } 
} 
 
double average(const double ar[], int n) 
{ 
    int i; 
    double sum = 0.0; 
     
    for (i = 0; i < n; i++) 
        sum += ar[i]; 
    if (n > 0) 
        return sum / n; 
    else 
        return 0.0; 
}

第十一章

11.1

设计并测试一个函数,从输入中获取n个字符(包括空白、制表符、换行符),把结果存储在一个数组里,它的地址被传递作为一个参数。

/* Programming Exercise 11-1 */ 
#include <stdio.h> 
#define LEN 10 
char * getnchar(char * str, int n); 
int main(void) 
{ 
    char input[LEN]; 
    char *check; 
     
    check = getnchar(input, LEN - 1); 
    if (check == NULL) 
        puts("Input failed."); 
    else 
        puts(input); 
    puts("Done.\n"); 
     
    return 0; 
} 
 
char * getnchar(char * str, int n) 
{ 
    int i; 
    int ch; 
 
    for (i = 0; i < n; i++) 
    { 
        ch = getchar(); 
        if (ch != EOF) 
            str[i] = ch; 
        else 
            break; 
    } 
    if (ch == EOF) 
        return NULL; 
    else 
    { 
        str[i] = '\0'; 
        return str; 
    } 
} 
#include <stdio.h>//个人
#define LENGTH 20
void get_character(char*, int);
int main()
{
	char group[LENGTH];
	puts("请输入字符:");
	get_character(group, LENGTH);
	for (int i = 0; i < LENGTH; i++)
		putchar(group[i]);
    return 0;
}

void get_character(char* arr, int size)
{
	int i = 0;
	while ((*(arr+i)=getchar())!='\0' && i<size-1)
		i++;
    *(arr + i) = '\0';
}

11.2

修改并编程练习1 的函数,在n 个字符后停止,或在读到第1个空白、制表符或换行符时停止,哪
个先遇到哪个停止。不能只使用 scanf ()。

#include <stdio.h>//个人
#include <string.h>
#define LENGTH 20
void get_character(char*, int);
int main()
{
	char group[LENGTH];
	puts("请输入字符:");
	get_character(group, LENGTH);
	for (int i = 0; i < strlen(group); i++)
		putchar(group[i]);
    return 0;
}

void get_character(char* arr, int size)
{
	int i = 0;
	while ((*(arr + i) = getchar()) != '\0' && i < size - 1)
	{
		if (*(arr + i) == ' ' || *(arr + i) == '\t' || *(arr + i) == '\n')
			break;
		i++;
	}
	*(arr + i) = '\0';
}

11.3

设计并测试一个函数,从一行输入中把一个单词读入一个数组中,并丢弃输入行中的其余字符。该
函数应该跳过第1个非空白字符前面的所有空白。将一个单词定义为没有空白、制表符或换行符的字符序列。

/* Programming Exercise 11-3 */ 
#include <stdio.h> 
#define LEN 80 
char * getword(char * str); 
int main(void) 
{ 
    char input[LEN]; 
     
    while (getword(input) != NULL) 
        puts(input); 
    puts("Done.\n"); 
     
    return 0; 
} 
 
#include <ctype.h>
char * getword(char * str) 
{ 
    int ch; 
    char * orig = str; 
// skip over initial whitespace 
    while ((ch = getchar()) != EOF && isspace(ch)) 
        continue; 
    if (ch == EOF) 
        return NULL; 
    else 
        *str++ = ch;   // first character in word 
// get rest of word 
    while ((ch = getchar()) != EOF && !isspace(ch)) 
        *str++ = ch; 
    *str = '\0'; 
    if (ch == EOF) 
        return NULL; 
    else 
    { 
        while (ch != '\n') 
            ch = getchar(); 
        return orig; 
    } 
}
#include <stdio.h>//个人
#include <string.h>
#define LENGTH 20
void get_character(char*);
int main()
{
	char group[LENGTH];
	puts("请输入单词:");
	get_character(group);
	for (int i = 0; i < strlen(group); i++)
		putchar(group[i]);
    return 0;
}

void get_character(char* arr)
{
	int ch;
	int i = 0;
	int mark = 0;
	while ((ch=getchar())!=EOF)
	{
		if (ch != ' ' && ch != '\t' && ch != '\n')
		{
			mark = 1;
			*(arr+i) = ch;
			i++;
		}
		else if (mark == 1)
			*(arr + i) = '\0';
		if (ch == '\n' && mark == 1)
			break;
	}
}

11.4

设计并测试一个函数,它类似编程练习3的描述,只不过它接受第2个参数指明可读取的最大字符数。

#include <stdio.h>//个人
#include <string.h>
#define LENGTH 10
void get_character(char*,int);
int main()
{
	char group[LENGTH];
	puts("请输入单词:");
	get_character(group,LENGTH);
	for (int i = 0; i < strlen(group); i++)
		putchar(group[i]);
    return 0;
}

void get_character(char* arr,int size)
{
	int ch;
	int i = 0;
	int mark = 0;
	int count = 0;
	while ((ch=getchar())!=EOF && count<size-1)
	{
		count++;
		if (ch != ' ' && ch != '\t' && ch != '\n')
		{
			mark = 1;
			*(arr+i) = ch;
			i++;
		}
		if (ch == '\n' && mark == 1)
			break;
	}
	*(arr + i) = '\0';
}

11.5

设计并测试一个函数,搜索第1个函数形参指定的字符串,在其中查找第2个函数形参指定的字符首次出现的位置。如果成功,该函数返指向该字符的指针,如果在字符串中未找到指定字符,则返回空指针 (该函数的功能与 strchr ()函数相同)。在一个完整的程序中测试该函数,使用一个循环给函数提供输入值。

#include <stdio.h>//个人
#include <string.h>
char* search_char(char*, char);
int main()
{
	char* string = "xize is king of the world!";
	for (int i = 0; i < 10; i++)
	{
		printf("%c的地址%p\n", *(string + i), string+i);
	}
	printf("search_char查找到的地址%p\n", search_char(string, 's'));
    return 0;
}

char* search_char(char* string, char target)
{
	for (int i = 0; i < strlen(string); i++)
	{
		if (*(string + i) == target)
			return (string + i);
	}
	string = NULL;
	return string;
}

11.6

编写一个名为 is _ within ()的函数,接受一个字符和一个指向字符串的指针作为两个函数形参。
如果指定字符在字符串中,该函数返回一个非零值 (即为真)。否则,返回0 (即为假)。在一个完整的程序中测试该函数,使用一个循环给函数提供输入值。

/* Programming Exercise 11-6 */ 
#include <stdio.h> 
#include <string.h> 
#define LEN 80 
_Bool is_within(const char * str, char c); 
char * s_gets(char * st, int n); 
 
int main(void) 
{ 
    char input[LEN]; 
    char ch; 
    int found;; 
     
    printf("Enter a string: "); 
    while (s_gets(input, LEN) && input[0] != '\0') 
    { 
        printf("Enter a character: "); 
        ch = getchar(); 
        while (getchar() != '\n') 
            continue; 
        found = is_within(input, ch); 
        if (found == 0) 
            printf("%c not found in string.\n", ch); 
        else 
            printf("%c found in string %s\n", ch, input); 
        printf("Next string: "); 
    } 
    puts("Done.\n"); 
     
    return 0; 
} 
 
_Bool is_within(const char * str, char ch) 
{ 
    while (*str != ch && *str != '\0') 
        str++; 
    return *str;   /* = 0 if \0 reached, non-zero otherwise */
} 
         
char * s_gets(char * st, int n) 
{ 
    char * ret_val; 
    char * find; 
     
    ret_val = fgets(st, n, stdin); 
    if (ret_val) 
    { 
        find = strchr(st, '\n');   // look for newline 
        if (find)                  // if the address is not NULL, 
            *find = '\0';          // place a null character there 
        else 
            while (getchar() != '\n') 
                continue; 
    } 
    return ret_val; 
}
#include <stdio.h>//个人
#include <string.h>
#include <stdbool.h>
#define SIZE 40
bool is_within(char*, char);
int main()
{
	char string[SIZE];
	char target;
	while (1)
	{
		fputs("请输入字符串:", stdout);
		fgets(string, SIZE,stdin);
		printf("\n请输入要在字符串中查找的字符:");
		target = getchar();
		if (is_within(string, target))
			printf("%s中包含%c\n", string, target);
		else
			printf("%s中不包含%c\n", string, target);
		int ch;
		while ((ch = getchar()) != '\n')
			continue;
	}
    return 0;
}

bool is_within(char* string, char target)
{
	for (int i = 0; i < strlen(string); i++)
	{
		if (*(string + i) == target)
			return true;
	}
	return false;
}

11.7

strncpy(s1, s2, n)函数把 s2 中的 n 个字符拷贝至 s1 中,截断 s2,或者有必要的话在末尾
添加空字符。如果 s2 的长度是 n 或多于 n,目标字符串不能以空字符结尾。该函数返回 s1。自己
编写一个这样的函数,名为 mystrncpy()。在一个完整的程序中测试该函数,使用一个循环给函
数提供输入值。

#include <stdio.h>//个人
#include <string.h>
#define SIZE 40
char* mystrncpy(char*, char*, int);
int main()
{
	char string1[SIZE];
	char string2[SIZE];
	while (1)
	{
		fputs("请输入字符串1:",stdout);
		gets_s(string1, SIZE);
		fputs("请输入字符串2:",stdout);
		gets_s(string2, SIZE);
		puts(mystrncpy(string1, string2, 5));
	}
    return 0;
}

char* mystrncpy(char* string1, char* string2, int n)
{
	int i = 0;
	int j = 0;
	while (*(string1+j)!='\0')
		j++;
	while (i<n && *(string2+i)!='\0')
	{
		*(string1+j+i) = *(string2 + i);
		i++;
	}
	*(string1 + j + i) = '\0';
	return string1;
}

11.8

编写一个名为 string_in()的函数,接受两个指向字符串的指针作为参数。如果第 2 个字符串中
包含第 1 个字符串,该函数将返回第 1 个字符串开始的地址。例如, string_in("hats”,"at")
将返回hats 中 a 的地址。否则,该函数返回空指针。在一个完整的程序中测试该函数,使用一个
循环给函数提供输入值。

/* Programming Exercise 11-8 */ 
#include <stdio.h> 
#define LEN 20 
char * string_in(const char * s1, const char * s2); 
int main(void) 
{ 
    char orig[LEN] = "transportation"; 
    char * find; 
         
    puts(orig); 
    find = string_in(orig, "port"); 
    if (find) 
        puts(find); 
    else 
        puts("Not found"); 
    find = string_in(orig, "part"); 
    if (find) 
        puts(find); 
    else 
        puts("Not found"); 
     
    return 0; 
} 
 
#include <string.h> 
char * string_in(const char * s1, const char * s2) 
{ 
    int l2 = strlen(s2); 
    int tries;            /* maximum number of comparisons    */ 
    int nomatch = 1;    /* set to 0 if match is found        */ 
     
    tries = strlen(s1) + 1 - l2; 
    if (tries > 0) 
        while (( nomatch = strncmp(s1, s2, l2)) && tries--) 
            s1++; 
    if (nomatch) 
        return NULL; 
    else 
        return (char *) s1;  /* cast const away */ 
}
#include <stdio.h>//个人
#include <string.h>
#define SIZE 40
char* string_in(char*, char*);
int main()
{
	char string1[SIZE];
	char string2[SIZE];
	while (1)
	{
		fputs("请输入字符串1:",stdout);
		gets_s(string1, SIZE);
		fputs("请输入字符串2:",stdout);
		gets_s(string2, SIZE);
		for (int i = 0; *(string1+i)!='\0'; i++)
		{
			printf("%c的地址:%p\n", *(string1 + i), string1 + i);
		}
		printf("%p\n",string_in(string1, string2));
	}
    return 0;
}

char* string_in(char* string1, char* string2)
{
	int mark;
	int j;
	for (int i = 0; *(string1+i)!='\0'; i++)
	{
		mark = 0;
		j = 0;
		for (; *(string2 + j)!='\0'; j++)
		{
			if (*(string1 + i + j) != *(string2 + j))
			{
				j++;
				break;
			}
			else
				mark++;
		}
		if (mark == j)
			return(string1 + i);
	}
	string1 = NULL;
	return string1;
}

11.9

编写一个函数,把字符串中的内容用其反序字符串代替。在一个完整的程序中测试该函数,使用一
个循环给函数提供输入值。

#include <stdio.h>//个人
#include <string.h>
#define SIZE 40
void reverse(char* string);
int main()
{
	char string[SIZE];
	while (1)
	{
		fputs("请输入字符串:",stdout);
		gets_s(string, SIZE);
		reverse(string);
		printf("逆序字符串:%s\n", string);
	}
    return 0;
}

void reverse(char* string)
{
	int i = 0;
	while (*(string+i)!='\0')
		i++;
	int k=i-1;//这里i代表终止符的位置,故减1后得到最后一个字符的位置
	char temp;
	for (int j = 0; j < i/2; j++)//n个字符需要对换[n/2]次,即n除2取整次
								//但是c语言的趋0截断特性会自动取整,故未采取(i-i%2)/2
								//c语言的这种取整特性可在计算机组成原理中得到解释
	{
		temp = *(string + j);
		*(string + j) = *(string + k);
		*(string + k) = temp;
		k--;
	}
}

对换方法源于前不久学习的线性代数,下面是我自推导的一个公式(结果是对的,推导过程有一点谬误懒的改了)

11.10(复看)

编写一个函数接受一个字符串作为参数,并删除字符串中的空格。在一个程序中测试该函数,使
用循环读取输入行,直到用户输入一行空行。该程序应该应用该函数读取每个输入的字符串,并显
示处理后的结果。

/* Programming Exercise 11-10 */ 
#include <stdio.h> 
#include <string.h>     // for strchr(); 
#define LEN 81 
int drop_space(char * s); 
char * s_gets(char * st, int n); 
 
int main(void) 
{ 
    char orig[LEN]; 
     
    puts("Enter a string of 80 characters or less:"); 
    while (s_gets(orig, LEN) && orig[0] != '\0') 
    {     
        drop_space(orig); 
        puts(orig);     
        puts("Enter next string (or just Enter to quit):");     
    } 
    puts("Bye!"); 
    return 0; 
} 
 
int drop_space(char * s) 
{ 
    char * pos; 
    while (*s)     /* or while (*s != '\0') */ 
    { 
        if (*s == ' ') 
        { 
            pos = s; 
            do 
            { 
                *pos = *(pos + 1); 
                pos++; 
            } while (*pos); 
        } 
        else 
            s++; 
    } 
         
} 
         
char * s_gets(char * st, int n) 
{ 
    char * ret_val; 
    char * find; 
     
    ret_val = fgets(st, n, stdin); 
    if (ret_val) 
    { 
        find = strchr(st, '\n');   // look for newline 
        if (find)                  // if the address is not NULL, 
            *find = '\0';          // place a null character there 
        else 
            while (getchar() != '\n') 
                continue; 
    } 
    return ret_val; 
} 
#include <stdio.h>//个人
#include <string.h>
#define SIZE 40
void delete_space(char* string);
int main()
{
	char string[SIZE];
	while (1)
	{
		fputs("请输入字符串:",stdout);
		fgets(string, SIZE,stdin);
		delete_space(string);
		printf("删除空格后的字符串:%s\n", string);
	}
    return 0;
}

void delete_space(char* string)
{
	for (int i = 0; *(string+i)!='\n'; i++)//i带表一段连续的没有空格的字符串的结束位置
	{
		if (*(string + i) == '\t' || *(string + i) == ' ')
		{
			int j;//j带表一段连续空格字符串的结束位置
			for (j = i; *(string + j) == '\t' || *(string + j) == ' '; j++)
				;
			int k;//k代表j后面字符串的长度
			//j+k=源字符串总长度,i+k=删除空白字符后的总长度    注:k为最大值时左式才成立
			for (k = 0; *(string + j + k) != '\n'; k++)
				*(string + i + k) = *(string + j + k);
			*(string + k + j) =	'\0';
			*(string+k+i) = '\n';
		}
			
	}
}

11.11(复看)

编写一个函数,读入10个字符串或者读到EOF时停正。该程序为用户提供一个有5个选项的菜
单:打印源字符串列表、以ASCII中的顺序打印字符串、按长度递增顺序打印字符串、按字符串
中第1个单词的长度打印字符串、退出。菜单可以循环显示,除非用户选择退出选项。当然,该
程序要能真正完成菜单中各选项的功能。

#include <stdio.h>//个人
#include <string.h>
#define ROW 10
#define COL 50
void menu(void);
void get_string(char[][COL]);
char get_choice(void);
void ASCII_shot_string(char[][COL]);
void sort_string(char[][COL]);
void head_length(char[][COL]);
int main()
{
	char string[ROW][COL];
	get_string(string);
	int mark = 0;
	while (1)
	{
		menu();
		switch (get_choice())
		{
		case 'a':
			for (int i = 0; i < ROW; i++)
				fputs(string[i], stdout);
			break;
		case 'b':
			ASCII_shot_string(string);
			for (int i = 0; i < ROW; i++)
				fputs(string[i], stdout);
			break;
		case 'c':
			sort_string(string);
			for (int i = 0; i < ROW; i++)
				fputs(string[i], stdout);
			break;
		case 'd':
			head_length(string);
			for (int i = 0; i < ROW; i++)
				fputs(string[i], stdout);
			break;
		case 'e':
		default:mark = 1;
			break;
		}
		if (mark == 1)
			break;
	}
    return 0;
}

void menu(void)
{
	puts("");
	puts("字符串操作系统");
	puts("a.显示原字符串列表\t\tb.显示按ASCII码表排序后的字符串");
	puts("c.按长度递增顺序显示列表\td.按字符串中第一个单词的长度显示字符串");
	puts("e.退出");
	fputs("请输入选择:",stdout);
}

char get_choice(void)
{
	int ch;
	while (1)
	{
		ch = getchar();
		if (ch >= 97 && ch <= 101)
		{
			while (getchar() != '\n')
				;
			break;
		}
		while (getchar() != '\n')
			;
		puts("输入错误,请重新输入");
	}
	return ch;
}

void get_string(char string[][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		printf("请输入字符串%d:", i + 1);
		fgets(string[i], COL, stdin);
	}
	while (getchar() != '\n')
		;
}

void ASCII_shot_string(char string[][COL])
{
	char temp;
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < strlen(string[i]) - 1; j++)
		{
			for (int k = j + 1; k < strlen(string[i]); k++)
			{
				if (string[i][j] > string[i][k])
				{
					temp = string[i][j];
					string[i][j] = string[i][k];
					string[i][k] = temp;
				}
			}
		}
	}
}

void sort_string(char string[][COL])
{
	for (int i = 0; i < ROW-1; i++)
	{
		for (int j = i+1; j < ROW; j++)
		{
			char temp[COL];
			if (strlen(string[i])>strlen(string[j]))
			{
				strcpy_s(temp,COL, string[i]);
				strcpy_s(string[i],COL,string[j]);
				strcpy_s(string[j],COL,temp);
			}
		}
	}
}

void head_length(char string[][COL])
{
	int length[10];
	for (int i = 0; i < ROW; i++)
	{
		int j=0;
		for (; string[i][j] != ' ' && string[i][j] != '\t' && string[i][j]!='\n'; j++)
			;
		length[i] = j;
	}
	for (int i = 0; i < ROW-1; i++)
	{
		char temp[COL];
		for (int j = i + 1; j < ROW; j++)
		{
			if (length[i]>length[j])
			{
				strcpy_s(temp, COL, string[i]);
				strcpy_s(string[i], COL, string[j]);
				strcpy_s(string[j], COL, temp);
			}
		}
	}
}

11.12

编写一个程序,读取输入,直至读到 EOF,报告读入的单词数、大写字母数、小写字母数、标点
符号数和数字字符数。使用 ctype.h 头文件中的函数。

/* pe11-12.c -- counts words and certain characters */
/* Programming Exercise 11-11                       */ 
#include <stdio.h> 
#include <ctype.h>       // for isspace()   
#include <stdbool.h>     // for bool, true, false           
int main(void) 
{ 
   char c;               // read in character  
   int low_ct = 0;       // number of lowercase characters      
   int up_ct = 0;        // number of uppercase characters      
   int dig_ct = 0;       // number of digits           
   int n_words = 0;      // number of words  
   int punc_ct = 0;      // number of punctuation marks         
   bool inword = false;  // == true if c is in a word   
 
   printf("Enter text to be analyzed (EOF to terminate):\n"); 
   while ((c = getchar()) != EOF) 
   { 
        if (islower(c)) 
           low_ct++; 
        else if (isupper(c)) 
           up_ct++; 
        else if (isdigit(c)) 
           dig_ct++; 
        else if (ispunct(c)) 
           punc_ct++; 
      if (!isspace(c) && !inword) 
      { 
         inword = true;  // starting a new word  
         n_words++;      // count word           
      } 
      if (isspace(c) && inword) 
         inword = false; // reached end of word 
   } 
   printf("\nwords = %d, lowercase = %d, uppercase = %d, " 
          "digits = %d, punctuation = %d\n", 
           n_words,low_ct,up_ct, dig_ct, punc_ct); 
   return 0; 
}
#include <stdio.h>//个人
#include <string.h>
#include <ctype.h>
int main()
{
	int ch;
	int count_word = 0;
	int count_capital = 0;
	int count_low_letter = 0;
	int count_symbol = 0;
	int count_number = 0;
	int inword = 0;
	puts("请输入字符串(ctrl+Z结束):");
	while ((ch=getchar())!=EOF)
	{
		if (isupper(ch))
			count_capital++;
		else if (islower(ch))
			count_low_letter++;
		else if (ispunct(ch))
			count_symbol++;
		else if (isdigit(ch))
			count_number++;
		if (!isspace(ch) && !inword)
		{
			inword = 1;
			count_word++;
		}
		if (isspace(ch) && inword)
			inword = 0;
	}
	printf("共计%d个单词,%d个大写字母,%d个小写字母,%d个标点符号,%d个数字\n",
		count_word, count_capital, count_low_letter, count_symbol, count_number);
    return 0;
}

11.13

编写一个程序,反序显示命令行参数的单词。例如,命令行参数是 see you later,该程序应
打印 later you see。

#include <stdio.h> //个人

int main(int argc,char* argv[])
{
	for (int i = 0; i < argc; i++)
		printf("%s\n", argv[argc - i-1]);
    return 0;
}

11.14

编写一个通过命令行运行的程序计算幂。第1个命令行参数是 double类型的数,作为幂的底数,
第2个参数是整数,作为幂的指数。

/* Programming Exercise 11-14 */ 
#include <stdio.h> 
#include <stdlib.h>      /* for atof() */ 
#include <math.h>        /* for pow()  */ 
 
int main(int argc, char *argv[]) 
{ 
    double num, exp; 
     
    if (argc != 3) 
        printf("Usage: %s number exponent\n", argv[0]); 
    else 
    { 
        num = atof(argv[1]); 
        exp = atof(argv[2]); 
        printf("%f to the %f power = %g\n", num, exp, pow(num,exp)); 
    } 
     
    return 0; 
}
#include <stdio.h> //个人
#include <stdlib.h>
int main(int argc,char* argv[])
{
	double temp = atof(argv[1]);
	for (int i = 0; i < atoi(argv[2])-1; i++)
		temp *= atof(argv[1]);
	printf("%s的%s次方为:%lf\n", argv[1], argv[2], temp);
    return 0;
}

11.15

使用字符分类函数实现 atoi()函数。如果输入的字符串不是纯数字,该函数返回 0。

#include <stdio.h> //个人(比题目描述的更为强大,可以自动滤去非数字)
#include <ctype.h>
#include <string.h>
int	atio_s(const char* str);
int main(void)
{
	printf("转换后的数字为:%d", atio_s("asd-fashdf"));
    return 0;
}

int	atio_s(const char* str)
{
	int len = strlen(str);
	int star = 0; //首个数字出现的位置
	int result = 0;
	for (star = 0; star < len; star++)
		if (isdigit(str[star]))
			break;
	if (star == len)
		printf("字符串中没有数字!\n");
	for (int i = star; i < len; i++)
	{
		if (!isdigit(str[i]))
			continue;
		result = result * 10 + (str[i] - '0');//其它字符数字的ASCII码减去字符0的ASCII码刚好等于其数值
	}										  //从高位开始,每多一个数就乘10
	if (str[star-1] == '-')
		return -result;
	else
		return result;
}

11.16

编写一个程序读取输入,直至读到文件结尾,然后把字符串打印出来。该程序识别和实现下面的
命令行参数:
-p        按原样打印
-u        把输入全部转换成大写
-l        把输入全部转换成小写
如果没有命令行参数,则让程序像是使用了-p参数那样运行。

/* Programming Exercise 11-16 */
#include <stdio.h> 
#include <ctype.h> 

int main(int argc, char* argv[])
{
    char mode = 'p';
    int ok = 1;
    int ch;

    if (argc > 2)
    {
        printf("Usage: %s [-p | -u | -l]\n", argv[0]);
        ok = 0;                /* skip processing input */
    }
    else if (argc == 2)
    {
        if (argv[1][0] != '-')
        {
            printf("Usage: %s [-p | -u | -l]\n", argv[0]);
            ok = 0;
        }
        else
            switch (argv[1][1])
            {
            case 'p':
            case 'u':
            case 'l':mode = argv[1][1];
                break;
            default:printf("%s is an invalid flag; ", argv[1]);
                printf("using default flag (-p).\n");
            }
    }

    if (ok)
        while ((ch = getchar()) != EOF)
        {
            switch (mode)
            {
            case 'p':putchar(ch);
                break;
            case 'u':putchar(toupper(ch));
                break;
            case 'l':putchar(tolower(ch));
            }
        }
    return 0;
}
#include <stdio.h> //个人
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc,char* argv[])
{
	FILE* fp;
	errno_t err;
	int ch;
	err = fopen_s(&fp, argv[1], "r");
	if (err!=0)
	{
		printf("%s打开失败!\n", argv[1]);
		exit(EXIT_FAILURE);
	}
	if (argv[2] == NULL)
	{
		while ((ch = getc(fp)) != EOF)
			putc(ch, stdout);
		fclose(fp);
		return 0;
	}
	switch (argv[2][1])
	{
	case 'p':
		while ((ch = getc(fp)) != EOF)
			putc(ch, stdout);
		break;
	case 'u':
		while ((ch=getc(fp))!=EOF)
			putc(toupper(ch), stdout);
		break;
	case 'l':
		while ((ch = getc(fp)) != EOF)
			putc(tolower(ch), stdout);
		break;
	default:printf("参数输入异常!\n");
		break;
	}
	fclose(fp);
    return 0;
}

第十二章

12.1

不使用全局变量,重写程序清单12.4。

//程序清单 12.4 global.c程序
/* global.c  -- uses an external variable */
#include <stdio.h>
int units = 0;         /* an external variable      */
void critic(void);
int main(void)
{
    extern int units;  /* an optional redeclaration */
    
    printf("How many pounds to a firkin of butter?\n");
    scanf("%d", &units);
    while ( units != 56)
        critic();
    printf("You must have looked it up!\n");
    
    return 0;
}

void critic(void)
{
    /* optional redeclaration omitted */
    printf("No luck, my friend. Try again.\n");
    scanf("%d", &units);
}
/* pe12-1.c  -- deglobalizing global.c */ 
/* Programming Exercise 12-1           */ 
/* one of several approaches */ 
#include <stdio.h> 
void critic(int * u); 
int main(void) 
{ 
   int units;   /* units now local */ 
   printf("How many pounds to a firkin of butter?\n"); 
   scanf("%d", &units); 
   while ( units != 56) 
       critic(&units); 
   printf("You must have looked it up!\n"); 
   return 0; 
} 
 
void critic(int * u) 
{ 
   printf("No luck, my friend. Try again.\n"); 
   scanf("%d", u); 
} 
 
// or use a return value: 
// units = critic();  
 
// and have critic look like this: 
/* 
int critic(void) 
{ 
   int u; 
   printf("No luck, my friend. Try again.\n"); 
   scanf("%d", &u); 
   return u; 
} 
*/ 
 
// or have main() collect the next value for units
#include <stdio.h>//个人
int critic(void);
int main(void)
{
    printf("一小块黄油有多少磅?\n");
    while (critic() != 56)
        printf("不走运,我的朋友。再试一次。\n");
    printf("你一定查过了!\n");
    return 0;
}

int critic()
{
    int a;
    scanf_s("%d", &a);
    return a;
}

12.2

在美国,通常以英里/加仑来计算油耗:在欧洲,以升/100 公里来计算。下面是程序的一部分,提
示用户选择计算模式 (美制或公制),然后接收数据并计算油耗。

// pe12-2b.c

// 与 pe12-2a.c 一起编译

#include <stdint.h>
#include "pe12-2a.h"
int main(void)
{
    int mode;
    printf("Enter 0 for metric mode, 1 for US mode: ");
    scnaf("%d", &mode);
    while (mode>=0)
    {
        set_mode(mode);
        get_info();
        show_info();
        printf("Enter 0 for metric mode, 1 for US mode");
        printf(" (-1 to quit): ");
        scanf("%d", &mode);
    }
    printf("Done.\n");
    return 0;
}

下面是是一些输出示例:
Enter 0 for metric mode, 1 for Us mode: 0
Enter distance traveled in kilometers: 600
Enter fuel consumed in liters: 78.8
Fuel consumption is 13.13 liters per 100 km.
Enter 0 for metric mode, 1 for US mode (-l to quit) : 1
Enter distance traveled in miles: 434
Enter fuel consumed in gallons: 12. 7
Fuel consumption is 34.2 miles per gallon.
Enter 0 for metric mode, 1 for Us mode (-l to quit) : 3
Invalid mode specified. Mode 1 (Us) used .
Enter distance traveled in miles: 388
Enter fuel consumed in gallons: 15.3
Fuel consumption is 25. 4 miles per gallon.
Enter 0 for metric mode, 1 for Us mode (-l to quit) : -1
Done .

如果用户输入了不正确的模式,程序向用户给出提示消息并使用上一次输入的正确模式。请提供
pe12-2a.h 头文件和 pe12-2a.c 源文件。源代码文件应定义 3 个具有文件作用域、 内部链接的
变量。一个表示模式、一个表示距离、一个表示消耗的燃料。 get_info()函数根据用户输入的模
式提示用户输入相应数据,并将其储存到文件作用域变量中。 show_info()函数根据设置的模式
计算并显示油耗。可以假设用户输入的都是数值数据。

#include <stdio.h> //pe12-2b.c    个人
#include "pe12-2a.h"
int main (void)
{
	int mode;
	printf("输入0表示公制模式,输入1表示美制模式:");
	scanf_s("%d", &mode);
	while (mode>=0)
	{
		set_mode(mode);//设置模式
		get_info();//获得里程数和消耗的燃油量
		show_info();//计算并显示单位油耗
		printf("\n输入0表示公制模式,输入1表示美制模式");
		printf(" (-1 退出): ");
		scanf_s("%d", &mode);
	}
	printf("结束。\n");
	return 0;
}
#include <stdio.h> //pe12-2a.c    个人
#include "pe12-2a.h"

static int mode;
static double distance = 0.0;
static double fuel = 0.0;
static int temp = 0;
void set_mode(int mode1)
{
	if (mode1 != 1 && mode1 != 0)
	{
		mode = temp;
		printf("输入错误,将使用上一次正确选择的模式。\n");
	}
	else
	{
		mode = mode1;
		temp = mode1;
	}
}
void get_info(void)
{
	switch (mode)
	{
	case 0:
		printf("\n请输入公里数:");
		scanf_s("%lf", &distance);
		printf("请输入消耗的燃油总量(升):");
		scanf_s("%lf", &fuel);
		break;
	case 1:
		printf("\n请输入英里数:");
		scanf_s("%lf", &distance);
		printf("请输入消耗的燃油总量(加仑):");
		scanf_s("%lf", &fuel);
		break;
	default:
		break;
	}
}
void show_info(void)
{
	if(mode==0)
		printf("百公里耗油量为:%.2lf升\n", fuel*100/distance);
	else
		printf("每加仑可行驶:%.2lf英里\n", distance/fuel);
}
void set_mode(int); //pe12-2a.h    个人
void get_info(void);
void show_info(void);

12.3

重新设计编程练习2,要求只使用自动变量。该程序提供的用户界面不变,即提示用户输入模式等。但是,函数调用要作相应变化。

//pe12-3a.h 
 
#define METRIC 0 
#define US 1 
#define USE_RECENT 2 
 
void check_mode(int *pm); 
void get_info(int mode, double * pd, double * pf); 
void show_info(int mode, double distance, double fuel);
// pe12-3a.c 
// compile with pe12-3b.c 
#include <stdio.h> 
#include "pe12-3a.h" 
 
void check_mode(int *pm) 
{ 
    if (*pm != METRIC && *pm != US) 
    { 
        printf("Invalid mode specified. Mode %d\n", *pm); 
        printf("Previous mode will be used.\n"); 
        *pm = USE_RECENT; 
    } 
} 
 
void get_info(int mode, double * pd, double * pf) 
{ 
    if (mode == METRIC) 
        printf("Enter distance traveled in kilometers: "); 
    else
        printf("Enter distance traveled in miles: "); 
    scanf("%lf",pd); 
    if (mode == METRIC) 
        printf("Enter fuel consumed in liters: "); 
    else 
        printf("Enter fuel consumed  in gallons: "); 
    scanf("%lf", pf); 
} 
 
void show_info(int mode, double distance, double fuel) 
{ 
    printf("Fuel consumption is "); 
    if (mode == METRIC) 
        printf("%.2f liters per 100 km.\n", 100 * fuel / distance); 
    else 
        printf("%.1f miles per gallon.\n", distance / fuel); 
}
// pe12-3b.c 
// compile with pe12-3a.c 
#include <stdio.h> 
#include "pe12-3a.h" 
int main(void) 
{ 
  int mode; 
  int prev_mode = METRIC; 
  double distance, fuel; 
   
  printf("Enter 0 for metric mode, 1 for US mode: "); 
  scanf("%d", &mode); 
  while (mode >= 0) 
  { 
      check_mode(&mode); 
      if (mode == USE_RECENT) 
          mode = prev_mode; 
      prev_mode = mode; 
      get_info(mode, &distance, &fuel); 
      show_info(mode, distance, fuel); 
      printf("Enter 0 for metric mode, 1 for US mode"); 
      printf(" (-1 to quit): "); 
      scanf("%d", &mode); 
  } 
  printf("Done.\n"); 
   
  return 0; 
}
#include <stdio.h> //pe12-2b.c    个人
#include "pe12-2a.h"
int main (void)
{
	int mode;
	int temp = 0;
	double distance;
	double fuel;
	printf("输入0表示公制模式,输入1表示美制模式:");
	scanf_s("%d", &mode);
	while (mode>=0)
	{
		set_mode(mode,&mode,temp,&temp);//设置模式
		get_info(mode,&distance,&fuel);//获得里程数和消耗的燃油量
		show_info(mode,distance,fuel);//计算并显示单位油耗
		printf("\n输入0表示公制模式,输入1表示美制模式");
		printf(" (-1 退出): ");
		scanf_s("%d", &mode);
	}
	printf("结束。\n");
	return 0;
}
#include <stdio.h> //pe12-2a.c    个人
#include "pe12-2a.h"

void set_mode(int mode1,int* mode2,int temp1,int* temp2)
{
	if (mode1 != 1 && mode1 != 0)
	{
		*mode2 = temp1;
		printf("输入错误,将使用上一次正确选择的模式。\n");
	}
	else
	{
		*mode2 = mode1;
		*temp2 = mode1;
	}
}
void get_info(int mode1,double* distance1,double* fuel1)
{
	switch (mode1)
	{
	case 0:
		printf("\n请输入公里数:");
		scanf_s("%lf", distance1);
		printf("请输入消耗的燃油总量(升):");
		scanf_s("%lf", fuel1);
		break;
	case 1:
		printf("\n请输入英里数:");
		scanf_s("%lf", distance1);
		printf("请输入消耗的燃油总量(加仑):");
		scanf_s("%lf", fuel1);
		break;
	default:
		break;
	}
}
void show_info(int mode1, double distance1, double fuel1)
{
	if(mode1==0)
		printf("百公里耗油量为:%.2lf升\n", fuel1*100/distance1);
	else
		printf("每加仑可行驶:%.2lf英里\n", distance1/fuel1);
}
void set_mode(int,int*,int,int*); //pe12-2a.h    个人
void get_info(int,double*,double*);
void show_info(int, double, double);

12.4

在一个循环中编写并测试一个函数,该函数返回它被调用的次数。

#include <stdio.h> //个人
int function(void);
int main()
{
	int time;
	int count = 0;
	fputs("请输入要循环的次数:",stdout);
	while (scanf_s("%d",&time)==1)
	{
		for (int i = 0; i < time; i++)
			count=function();
		printf("共调用了function()%d次\n\n", count);
		fputs("请输入要循环的次数:", stdout);
	}
	return 0;
}

int function(void)
{
	static int a = 0;
	a++;
	return a;
}

12.5

编写一个程序,生成100个1~10 范围内的随机数,并以降序排列(可以把第11章的排序算法稍
加改动,便可用于整数排序,这里仅对整数排序)。

/* pe12-5.c  */ 
#include <stdio.h> 
#include <stdlib.h> 
void print(const int array[], int limit); 
void sort(int array[], int limit); 
 
#define SIZE 100 
int main(void) 
{ 
    int i; 
    int arr[SIZE]; 
     
    for (i = 0; i < SIZE; i++) 
        arr[i] = rand() % 10 + 1; 
    puts("initial array");
    print(arr,SIZE); 
    sort(arr,SIZE); 
    puts("\nsorted array"); 
    print(arr,SIZE); 
     
    return 0; 
} 
 
/* sort.c -- sorts an integer array in decreasing order */ 
void sort(int array[], int limit) 
{ 
   int top, search, temp; 
 
   for (top = 0; top < limit -1; top++) 
       for (search = top + 1; search < limit; search++) 
            if (array[search] > array[top]) 
            { 
                 temp = array[search]; 
                 array[search] = array[top]; 
                 array[top] = temp; 
            } 
} 
 
/* print.c -- prints an array */ 
void print(const int array[], int limit) 
{ 
   int index; 
 
   for (index = 0; index < limit; index++) 
   { 
      printf("%2d ", array[index]); 
      if (index % 10 == 9) 
         putchar('\n'); 
   } 
   if (index % 10 != 0) // if last line not complete 
      putchar('\n'); 
}
#include <stdio.h> //个人
#include <stdlib.h>
#include <time.h>
#define ARR_MAX 100
#define RANGE 10
void show(int arr[], int length);
void select_sort(int* source, int length);//选择排序输入的整形数组
int main()
{
	int matrix[ARR_MAX] = { 0 };
	srand((unsigned int)time(0));
	for (int i = 0; i < ARR_MAX; i++)
		matrix[i] = rand() % 10 + 1;
	printf("随机生成的原数组\n");
	show(matrix, ARR_MAX);
	printf("\n排序后的数组\n");
	select_sort(matrix, ARR_MAX);
	show(matrix, ARR_MAX);
	return 0;
}

void show(int arr[], int length)
{
	for (int i = 0; i < length/10; i++)
	{
		for (int j = 0; j < length/10; j++)
			printf("%3d", arr[i + j]);
		putchar('\n');
	}
}

void select_sort(int* source, int length)
{
	int temp = 0;
	for (int i = 0; i < length - 1; i++)
	{
		for (int j = i + 1; j < length; j++)
		{
			if (source[i] < source[j])
			{
				temp = source[i];
				source[i] = source[j];
				source[j] = temp;
			}
		}
	}
}

12.6

编写一个程序,生成1000个1~10 范围内的随机数。不用保存或打印这些数字,仅打印每个数出
现的次数。用10个不同的种子值运行,生成的数字出现的次数是否相同?可以使用本章自定义的
函数或ANSIC 的 rand ()和 srand()函数,它们的格式相同。这是一个测试特定随机数生成器随机性的方法。

#include <stdio.h> //个人
#include <stdlib.h>
#include <time.h>
#define ARR_MAX 1000
#define RANGE 10
void show(int[][RANGE]);
int main()
{
	int number[ARR_MAX / RANGE][RANGE];
	for (int i = 0; i < ARR_MAX / RANGE; i++)
	{
		srand(i);
		for (int j = 0; j < RANGE; j++)
			number[i][j] = rand() % RANGE + 1;
	}
	show(number);
	int count[RANGE] = { 0 };
	for (int i = 0; i < ARR_MAX / RANGE; i++)
	{
		for (int j = 0; j < RANGE; j++)
		{
			for (int k = 0; k < RANGE; k++)
			{
				if (number[i][j] == k+1)
					count[k]++;
			}
		}
	}
	for (int i = 0; i < RANGE; i++)
	{
		printf("%d出现了%d次\n", i+1, count[i]);
	}
	return 0;
}

void show(int arr[][RANGE])
{
	for (int i = 0; i < ARR_MAX / RANGE; i++)
	{
		for (int j = 0; j < RANGE; j++)
			printf("%-3d", arr[i][j]);
		putchar('\n');
	}
}

12.7

编写一个程序,按照程序清单12.13 输出示例后面讨论的内容,修改该程序。使其输出类似:
Enter the number of sets; enter q to stop : 18
How many sides and how many dice? 6 3
Here are 18 sets of 3 6-sided throws .
12 10 6 9 8 14 8 15 9 14 12 17 11 7 10
13 8 14
How many sets? Enter q to stop: q

/* pe12-7.c  */ 
#include <stdio.h> 
#include <stdlib.h>  /* for srand() */ 
#include <time.h>    /* for time()  */ 
int rollem(int); 
 
int main(void) 
{ 
    int dice, count, roll; 
    int sides; 
    int set, sets; 
     
    srand((unsigned int) time(0));  /* randomize rand() */ 
     
    printf("Enter the number of sets; enter q to stop: "); 
    while (scanf("%d", &sets) == 1) 
    { 
          printf("How many sides and how many dice?  "); 
        if (scanf("%d %d", &sides, &dice) != 2) 
        { 
            puts("not integers -- terminating input loop."); 
            break; 
        } 
        printf("Here are %d sets of %d %d-sided throws.\n", sets, dice, sides);
        for (set = 0; set < sets; set++) 
        { 
            for (roll = 0, count = 0; count < dice; count++) 
                roll += rollem(sides); 
                /* running total of dice pips */ 
            printf("%4d ", roll); 
            if (set % 15 == 14) 
                putchar('\n'); 
        } 
        if (set % 15 != 0) 
            putchar('\n'); 
        printf("How many sets? Enter q to stop: "); 
    } 
    puts("GOOD FORTUNE TO YOU!\n"); 
    return 0; 
} 
 
int rollem(int sides) 
{ 
    int roll; 
 
    roll = rand() % sides + 1; 
    return roll; 
}
/* diceroll.c -- dice role simulation */
/* compile with mandydice.c           */
#include "diceroll.h"
#include <stdio.h>
#include <stdlib.h>           /* for library rand()   */

int roll_count = 0;          /* external linkage     */

static int rollem(int sides)  /* private to this file */
{
    int roll;

    roll = rand() % sides + 1;
    ++roll_count;             /* count function calls */

    return roll;
}

int roll_n_dice(int dice, int sides)
{
    int d;
    int total = 0;
    if (sides < 2)
    {
        printf("Need at least 2 sides.\n");
        return -2;
    }
    if (dice < 1)
    {
        printf("Need at least 1 die.\n");
        return -1;
    }

    for (d = 0; d < dice; d++)
        total += rollem(sides);

    return total;
}
//diceroll.h
extern int roll_count;

int roll_n_dice(int dice, int sides);
#include <stdio.h> //个人
#include <stdlib.h>              
#include <time.h>              
#include "diceroll.h"            
int main(void)
{
    int dice;
    int sides;
    int status;
    int sets;
    int* ptd;
    srand((unsigned int)time(0)); 
    printf("Enter the number of sets; enter q to stop :");
    while (scanf_s("%d", &sets) == 1 && sets > 0)
    {
        printf("How many sides and how many dice?");
        if ((status = scanf_s("%d%d", &sides,&dice)) != 2)
        {
            if (status == EOF)
                break;            
            else
            {
                printf("You should have entered two integers.");
                printf(" Let's begin again.\n");
                while (getchar() != '\n')
                    continue; 
                printf("How many sides and how many dice?");
                continue;
            }
        }
        //roll = roll_n_dice(dice, sides);
        printf("Here are %d set %d %d-sided throws.\n",
            sets, dice, sides);
        ptd = (int*)malloc(sets * sizeof(int));
        if (ptd==NULL)
        {
            puts("内存分配失败!");
            break;
        }
        for (int i = 0; i < sets; i++)
            *(ptd + i) = roll_n_dice(dice, sides);
        for (int i = 0; i < sets; i++)
            printf("%d ", *(ptd + i));
        free(ptd);
        printf("\nHow many sets? Enter q to stop:");
    }
    printf("The rollem() function was called %d times.\n",
        roll_count); 
    printf("GOOD FORTUNE TO YOU!\n");

    return 0;
}

12.8

下面是程序的一部分:

提供 make array()和 show array()函数的定义,完成该程序。 make array () 函数接受两个参数,第1个参数是 int 类型数组的元素个数,第 2个参数是要赋给每个元素的值。该函数调用
malloc()创建一个大小合适的数组,将其每个元素设置为指定的值,并返回一个指向该数组的指针。 show array()函数显示数组的内容,一行显示8 个数。

#include <stdio.h> //个人
#include <stdlib.h>
int* make_array(int elem, int val);
void show_array(const int ar[], int n);
int main(void)
{
	int* pa;
	int size;
	int value;
	printf("输入元素数量: ");
	while (scanf_s("%d", &size) == 1 && size > 0)
	{
		printf("输入初始化值: ");
		scanf_s("%d", &value);
		pa = make_array(size, value);
		if (pa)
		{
			show_array(pa, size);
			free(pa);
		}
		printf("\n输入元素数量(<1 退出): ");
	}
	printf("结束。\n");
	return 0;
}

int* make_array(int elem, int val)
{
	int* ptd;
	ptd = (int*)malloc(elem * sizeof(int));
	if (ptd == NULL)
	{
		return printf("内存分配失败!\n");
	}
	for (int i = 0; i < elem; i++)
		*(ptd + i) = val;
	return ptd;
}

void show_array(const int ar[], int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%-2d", ar[i]);
		if ((i+1) % 8 == 0)
			putchar('\n');
	}
}

12.9(没写完,复看)

编写一个符合以下描述的函数。首先,询问用户需要输入多少个单词。然后,接收用户输入的单词,并显示出来,使用 malloc()并回答第1个问题 (即要输入多少个单词),创建一个动态数组, 该数组内含相应的指向 char 的指针 (注意,由于数组的每个元素都是指向 char 的指针,所以用于储存 malloc()返回值的指针应该是一个指向指针的指针,且它所指向的指针指向char)。在读取字符串时,该程序应该把单词读入一个临时的 char 数组,使用 malloc()分配足够的存储空间来储存单词,并把地址存入该指针数组 (该数组中每个元素都是指向 char 的指针)。然后,从临时数组中把单词拷贝到动态分配的存储空间中。因此,有一个字符指针数组,每个指针都指向一个对象,该对象的大小正好能容纳被储存的特定单词。下面是该程序的一个运行示例:
How many words do you wish to enter? 5
Enter 5 words now:
I enjoyed doing this exerise
Here are your words:

I
enjoyed
doing
this
exercise

#include <stdio.h> //个人
#include <stdlib.h>
#define WORD_LENGTH 15
int get_string(char*);
int main(void)
{
	int size;
	char* ptd1;
	char** ptd2;
	fputs("您想输入多少个单词?",stdout);
	scanf_s("%d", &size);
	ptd1 = (char*)malloc(size * WORD_LENGTH);
	if (ptd1==NULL)
		return puts("内存分配失败!\n");
	printf("现在输入%d个单词:", size);
	int string_length=get_string(ptd1);
	fputs(ptd1,stdout);
	for (int i = 0; i < string_length; i++)
	{
		if (*(ptd1 + i) == ' ' || *(ptd1+i)=='\n')
			*(ptd2 + i) = (char**)malloc(i * 1);
	}
	free(ptd1);
	return 0;
}

int get_string(char* string)
{
	while (getchar() != '\n')
		;
	int i = 0;
	while ((*(string+i)=getchar())!= '\n')
		i++;
	*(string + i + 1) = '\0';
	return (i + 1);
}

第十三章

13.1

修改程序清单13.1中的程序,要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。

/* count.c -- using standard I/O */ //这不是答案,而是题目的一部分
#include <stdio.h>
#include <stdlib.h> // exit() prototype

int main(int argc, char *argv[])
{
    int ch;         // place to store each character as read
    FILE *fp;       // "file pointer"
    unsigned long count = 0;
    if (argc != 2)
    {
        printf("Usage: %s filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if ((fp = fopen(argv[1], "r")) == NULL)
    {
        printf("Can't open %s\n", argv[1]);
        exit(EXIT_FAILURE);
    }
    while ((ch = getc(fp)) != EOF)
    {
        putc(ch,stdout);  // same as putchar(ch);
        count++;
    }
    fclose(fp);
    printf("File %s has %lu characters\n", argv[1], count);
    
    return 0;
}
#include <stdio.h> //个人
#include <stdlib.h>
#include <string.h>
#define NAMELEN 20
int main(void)
{
    int ch;
    FILE* fp;
    unsigned long count = 0;
    char name[NAMELEN];
    printf("请输入文件名:");
    if (scanf_s("%s", name,NAMELEN) != 1)
    {
        printf("输入失败!");
        exit(EXIT_FAILURE);
    }
    name[strlen(name)] = '\0';
    errno_t err;
    err = fopen_s(&fp, name, "w");
    if (err!=0)
    {
        printf("Can't open %s\n", name);
        exit(EXIT_FAILURE);
    }
    for (count = 0; name[count] != '\0'; count++)
    {
        putc(name[count], fp);
        count++;
    }
    fclose(fp);
    printf("File %s has %lu characters\n", name, count);

    return 0;
}

13.2

编写一个文件拷贝程序,该程序通过命令行获取原始文件名和拷贝文件名。尽量使用标准I/O 和二
进制模式。

/* Programming Exercise 13-2 */ 
#include <stdio.h> 
#include <stdlib.h> 
 
int main(int argc, char *argv[]) 
{ 
    int byte; 
    FILE * source; 
    FILE * target; 
 
    if (argc != 3) 
    { 
        printf("Usage: %s sourcefile targetfile\n", argv[0]); 
        exit(EXIT_FAILURE); 
    } 
     
    if ((source = fopen(argv[1], "rb")) == NULL) 
    { 
        printf("Could not open file %s for input\n", argv[1]);     
        exit(EXIT_FAILURE); 
    } 
 
    if ((target = fopen(argv[2], "wb")) == NULL) 
    { 
        printf("Could not open file %s for output\n", argv[2]);     
        exit(EXIT_FAILURE); 
    } 
 
    while ((byte = getc(source)) != EOF) 
    { 
        putc(byte, target); 
    }
    if (fclose(source) != 0) 
        printf("Could not close file %s\n", argv[1]); 
 
    if (fclose(target) != 0) 
        printf("Could not close file %s\n", argv[2]); 
         
    return 0; 
}
#include <stdio.h> //个人
#include <stdlib.h>
int main(int argc,char *argv[])
{
    if (argc!=3)
    {
        fprintf(stdout, "参数数量异常,请输入三个猜数(三个参数中程序名也算一个)\n");
        exit(EXIT_FAILURE);
    }
    FILE* fp1, *fp2;
    errno_t err1, err2;
    int ch;
    err1 = fopen_s(&fp1, argv[1], "rb");
    if (err1!=0)
    {
        fprintf(stderr, "%s文件打开失败\n", argv[1]);
        exit(EXIT_FAILURE);
    }
    err2 = fopen_s(&fp2, argv[2], "wb");
    if (err2 != 0)
    {
        fprintf(stderr, "%s文件打开失败\n", argv[2]);
        exit(EXIT_FAILURE);
    }
    while (ch=getc(fp1)!=EOF)   
    {
        putc(ch, fp2);
    }
    if(fclose(fp1)!=0)
        fprintf(stderr, "%s文件关闭异常\n", argv[1]);
    if(fclose(fp2)!=0)
        fprintf(stderr, "%s文件关闭异常\n", argv[2]);
    fprintf(stdout, "拷贝成功!\n");
    return 0;
}

13.3

编写一个文件拷贝程序,提示用户输入文本文件名,并以该文件名作为原始文件名和输出文件名。
该程序要使用 ctype.h 中的 toupper ()函数,在写入到输出文件时把所有文本转换成大写。使
用标准I/O 和文本模式。

#include <stdio.h> //个人
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define NAMELEN 20
int main(void)
{
    FILE* fp1, * fp2;
    char name[NAMELEN];
    int i = 0;
    int ch;
    fprintf(stdout, "请输入要拷贝的文件名:");
    while ((name[i] = getc(stdin)) != '\n')
        i++;
    name[i] = '\0';
    errno_t err1, err2;
    err1 = fopen_s(&fp1, name, "r");
    if (err1!=0)
    {
        fprintf(stdout, "文件%s打开失败!\n", name);
        exit(EXIT_FAILURE);
    }
    char temp_name[NAMELEN + 5];
    strncpy_s(temp_name, sizeof(temp_name), name, sizeof(name));
    strncat_s(temp_name, sizeof(temp_name), ".tmp", 5);
    err2 = fopen_s(&fp2, temp_name, "w+");
    if (err2!=0)
    {
        fprintf(stdout, "临时文件创建失败!\n");
        fclose(fp1);
        exit(EXIT_FAILURE);
    }
    while ((ch=getc(fp1))!=EOF)
    {
        putc(toupper(ch), fp2);
    }
    fclose(fp1);
    fclose(fp2);
    remove(name);
    if (rename(temp_name, name))
        fprintf(stdout, "文件重命名失败");
    return 0;
}

13.4

编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。使用 argc 控制循环。

/* Programming Exercise 13-4 */ 
#include <stdio.h> 
#include <stdlib.h> 
 
int main(int argc, char *argv[]) 
{ 
    int byte; 
    FILE * source; 
    int filect; 
 
    if (argc == 1) 
    { 
        printf("Usage: %s filename[s]\n", argv[0]); 
        exit(EXIT_FAILURE); 
    } 
     
    for (filect = 1; filect < argc; filect++) 
    { 
        if ((source = fopen(argv[filect], "r")) == NULL) 
        { 
            printf("Could not open file %s for input\n", argv[filect]);     
            continue; 
        } 
        while ((byte = getc(source)) != EOF) 
        { 
            putchar(byte); 
        } 
        if (fclose(source) != 0) 
            printf("Could not close file %s\n", argv[1]); 
    }     
         
    return 0; 
}
#include <stdio.h> //个人
#include <stdlib.h>
int main(int argc,char* argv[])
{
	if (argc==1)
	{
		printf("命令行参数中有以下文件:\n");
		printf("%s\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	FILE* fp;
	errno_t err;
	int ch;
	for (int filect = 1; filect < argc; filect++)
	{
		err = fopen_s(&fp, argv[filect], "r");
		if (err!=0)
		{
			printf("文件打开失败!");
			continue;
		}
		printf("%s\n", argv[filect]);
		while ((ch=getc(fp))!=EOF)
			putc(ch,stdout);
		putchar('\n');
		if (fclose(fp) != 0)
			printf("文件关闭失败!\n");
	}
    return 0;
}

13.5

修改程序清单13.5中的程序,用命令行界面代替交互式界面。

/* append.c -- appends files to a file */ //这不是答案,而是题目的一部分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 4096
#define SLEN 81
void append(FILE *source, FILE *dest);
char * s_gets(char * st, int n);

int main(void)
{
    FILE *fa, *fs;	// fa for append file, fs for source file
    int files = 0;  // number of files appended
    char file_app[SLEN];  // name of append file
    char file_src[SLEN];  // name of source file
    int ch;
    
    puts("Enter name of destination file:");
    s_gets(file_app, SLEN);
    if ((fa = fopen(file_app, "a+")) == NULL)
    {
        fprintf(stderr, "Can't open %s\n", file_app);
        exit(EXIT_FAILURE);
    }
    if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0)
    {
        fputs("Can't create output buffer\n", stderr);
        exit(EXIT_FAILURE);
    }
    puts("Enter name of first source file (empty line to quit):");
    while (s_gets(file_src, SLEN) && file_src[0] != '\0')
    {
        if (strcmp(file_src, file_app) == 0)
            fputs("Can't append file to itself\n",stderr);
        else if ((fs = fopen(file_src, "r")) == NULL)
            fprintf(stderr, "Can't open %s\n", file_src);
        else
        {
            if (setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0)
            {
                fputs("Can't create input buffer\n",stderr);
                continue;
            }
            append(fs, fa);
            if (ferror(fs) != 0)
                fprintf(stderr,"Error in reading file %s.\n",
                        file_src);
            if (ferror(fa) != 0)
                fprintf(stderr,"Error in writing file %s.\n",
                        file_app);
            fclose(fs);
            files++;
            printf("File %s appended.\n", file_src);
            puts("Next file (empty line to quit):");
        }
    }
    printf("Done appending. %d files appended.\n", files);
    rewind(fa);
    printf("%s contents:\n", file_app);
    while ((ch = getc(fa)) != EOF)
        putchar(ch);
    puts("Done displaying.");
    fclose(fa);
    
    return 0;
}

void append(FILE *source, FILE *dest)
{
    size_t bytes;
    static char temp[BUFSIZE]; // allocate once
    
    while ((bytes = fread(temp,sizeof(char),BUFSIZE,source)) > 0)
        fwrite(temp, sizeof (char), bytes, dest);
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');   // look for newline
        if (find)                  // if the address is not NULL,
            *find = '\0';          // place a null character there
        else
            while (getchar() != '\n')
                continue;
    }
    return ret_val;
}

/* Programming Exercise 13-5 */ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
 
#define BUFSIZE 4096 
#define SLEN 81 
void append(FILE *source, FILE *dest); 
 
int main(int argc, char *argv[]) 
{ 
    FILE *fa, *fs; 
    int files = 0; 
    int fct; 
 
    if (argc < 3)
    { 
        printf("Usage: %s appendfile sourcefile[s]\n", argv[0]); 
        exit(EXIT_FAILURE); 
    } 
 
    if ((fa = fopen(argv[1], "a")) == NULL) 
    { 
        fprintf(stderr, "Can't open %s\n", argv[1]); 
        exit(EXIT_FAILURE); 
    } 
    if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0) 
    { 
        fputs("Can't create output buffer\n", stderr); 
        exit(EXIT_FAILURE); 
    } 
 
    for (fct = 2; fct < argc; fct++) 
    { 
        if (strcmp(argv[fct], argv[1]) == 0) 
            fputs("Can't append file to itself\n",stderr); 
        else if ((fs = fopen(argv[fct], "r")) == NULL) 
            fprintf(stderr, "Can't open %s\n", argv[fct]); 
        else 
        { 
            if (setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0) 
            { 
                fputs("Can't create output buffer\n",stderr); 
                continue; 
            } 
            append(fs, fa); 
            if (ferror(fs) != 0) 
                fprintf(stderr,"Error in reading file %s.\n", 
                        argv[fct]); 
            if (ferror(fa) != 0) 
                fprintf(stderr,"Error in writing file %s.\n", 
                        argv[1]); 
            fclose(fs); 
            files++; 
            printf("File %s appended.\n", argv[fct]); 
        } 
    } 
    printf("Done. %d files appended.\n", files); 
    fclose(fa); 
 
    return 0; 
} 
 
void append(FILE *source, FILE *dest) 
{ 
    size_t bytes; 
    static char temp[BUFSIZE]; // allocate once 
 
    while ((bytes = fread(temp,sizeof(char),BUFSIZE,source)) > 0) 
        fwrite(temp, sizeof (char), bytes, dest); 
}
#include <stdio.h> //个人与AI
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 4096

void append(FILE* source, FILE* dest);

int main(int argc, char* argv[])
{
    FILE* fa, * fs; // fa 表示追加文件,fs 表示源文件
    int files = 0;  // 附加文件数
    int ch;

    // 检查命令行参数数量
    if (argc < 3)
    {
        fprintf(stderr, "Usage: %s destination_file source_file1 [source_file2 ...]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 打开目标文件(追加模式)
    errno_t err1 = fopen_s(&fa, argv[1], "a+");
    if (err1 != 0)
    {
        fprintf(stderr, "Can't open %s\n", argv[1]); // 无法打开附加文件
        exit(EXIT_FAILURE);
    }

    if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0)
    {
        fputs("Can't create output buffer\n", stderr); // 无法创建输出缓冲区
        exit(EXIT_FAILURE);
    }

    // 处理所有源文件(从第3个参数开始)
    for (int i = 2; i < argc; i++)
    {
        // 检查是否试图将文件附加到自身
        if (strcmp(argv[i], argv[1]) == 0)
        {
            fputs("Can't append file to itself\n", stderr); // 无法将文件附加到自身
            continue; // 跳过这个文件,继续处理下一个
        }

        // 打开源文件
        errno_t err2 = fopen_s(&fs, argv[i], "r");
        if (err2 != 0)
        {
            fprintf(stderr, "Can't open %s\n", argv[i]); // 无法打开源文件
            continue; // 跳过这个文件,继续处理下一个
        }

        // 设置输入缓冲区
        if (setvbuf(fs, NULL, _IOFBF, BUFSIZE) != 0)
        {
            fputs("Can't create input buffer\n", stderr); // 无法创建输入缓冲区
            fclose(fs);
            continue;
        }

        // 附加文件内容
        append(fs, fa);

        // 检查错误
        if (ferror(fs) != 0)
            fprintf(stderr, "Error in reading file %s.\n", argv[i]); // 读取源文件时出错

        if (ferror(fa) != 0)
            fprintf(stderr, "Error in writing file %s.\n", argv[1]); // 写入附加文件时出错

        fclose(fs);
        files++;
        printf("File %s appended.\n", argv[i]); // 已附加文件
    }

    printf("Done appending. %d files appended.\n", files); // 完成附加

    // 显示目标文件内容
    rewind(fa);
    printf("%s contents:\n", argv[1]); // 附加文件内容:
    while ((ch = getc(fa)) != EOF)
        putchar(ch);
    puts("Done displaying."); // 显示完毕
    fclose(fa);
    return 0;
}

void append(FILE* source, FILE* dest)
{
    size_t bytes;
    static char temp[BUFSIZE]; // 分配一次
    while ((bytes = fread(temp, sizeof(char), BUFSIZE, source)) > 0)
        fwrite(temp, sizeof(char), bytes, dest);
}

13.6

使用命令行参数的程序依赖于用户的内存如何正确地使用它们。重写程序清单13.2 中的程序,不
使用命令行参数,而是提示用户输入所需信息。

#include <stdio.h> //个人
#include <stdlib.h>
#include <string.h>
#define LEN 40

int main(void)
{
    FILE* in, * out;
    int ch;
    char srcname[LEN];
    char name[LEN];
    printf("请输入要压缩的文件名称:");
    scanf_s("%s", srcname, LEN);
    errno_t err1, err2;
    srcname[LEN - 1] = '\0';
    err1 = fopen_s(&in, srcname, "r");
    if (err1!=0)
    {
        printf("%s打开失败!\n", srcname);
        exit(EXIT_FAILURE);
    }
    strncpy_s(name, LEN, srcname, LEN - 5);
    name[LEN - 5] = '\0';
    strcat_s(name, LEN, ".red");
    err2 = fopen_s(&out, name, "w");
    if (err2!=0)
    {
        printf("%s打开失败!\n", name);
        exit(EXIT_FAILURE);
    }
    int count = 0;
    while ((ch=getc(in))!=EOF)
        if (count++ % 3 == 0)
            putc(ch, out);
    if (fclose(in) != 0 || fclose(out) != 0)
        fprintf(stderr, "Error in closing files\n");
    return 0;
}

13.7

编写一个程序打开两个文件。可以使用命令行参数或提示用户输入文件名。
a.该程序以这样的顺序打印:打印第1个文件的第1行,第2个文件的第1行,第1个文件的第 2
行,第2个文件的第2行,以此类推,打印到行数较多文件的最后一行。
b.修改该程序,把行号相同的行打印成一行。

/* Programming Exercise 13-7a */ 
/* code assumes that end-of-line immediately precedes end-of-file */ 
 
#include <stdio.h> 
#include <stdlib.h>
int main(int argc, char *argv[]) 
{ 
    int ch1, ch2; 
    FILE * f1; 
    FILE * f2; 
 
    if (argc != 3) 
    { 
        printf("Usage: %s file1 file2\n", argv[0]); 
        exit(EXIT_FAILURE); 
    } 
    if ((f1 = fopen(argv[1], "r")) == NULL) 
    { 
        printf("Could not open file %s for input\n", argv[1]);     
        exit(EXIT_FAILURE); 
    } 
    if ((f2 = fopen(argv[2], "r")) == NULL) 
    { 
        printf("Could not open file %s for input\n", argv[2]);     
        exit(EXIT_FAILURE); 
    } 
    ch1 = getc(f1); 
    ch2 = getc(f2); 
     
    while (ch1 != EOF || ch2 != EOF) 
    { 
        while (ch1 != EOF && ch1 != '\n') /* skipped after EOF reached */ 
        { 
            putchar(ch1); 
            ch1 = getc(f1); 
        } 
        if (ch1 != EOF) 
        { 
            putchar('\n'); 
            ch1 = getc(f1); 
        } 
        while (ch2 != EOF && ch2 != '\n') /* skipped after EOF reached */ 
        { 
            putchar(ch2); 
            ch2 = getc(f2); 
        } 
 
        if (ch2 != EOF) 
        { 
            putchar('\n'); 
            ch2 = getc(f2); 
        } 
    } 
         
    if (fclose(f1) != 0) 
        printf("Could not close file %s\n", argv[1]);     
    if (fclose(f2) != 0) 
        printf("Could not close file %s\n", argv[2]);     
         
    return 0; 
}
/* Programming Exercise 13-7b */ 
/* code assumes that end-of-line immediately precedes end-of-file */ 
 
#include <stdio.h> 
#include <stdlib.h> 
 
int main(int argc, char *argv[]) 
{ 
    int ch1, ch2; 
    FILE * f1; 
    FILE * f2; 
     
    if (argc != 3) 
    { 
        printf("Usage: %s file1 file2\n", argv[0]); 
        exit(EXIT_FAILURE); 
    } 
    if ((f1 = fopen(argv[1], "r")) == NULL) 
    { 
        printf("Could not open file %s for input\n", argv[1]);     
        exit(EXIT_FAILURE); 
    } 
    if ((f2 = fopen(argv[2], "r")) == NULL) 
    { 
        printf("Could not open file %s for input\n", argv[2]);     
        exit(EXIT_FAILURE); 
    } 
    ch1 = getc(f1); 
    ch2 = getc(f2); 
     
    while (ch1 != EOF || ch2 != EOF) 
    { 
        while (ch1 != EOF && ch1 != '\n') /* skipped after EOF reached */ 
        { 
            putchar(ch1); 
            ch1 = getc(f1); 
        } 
        if (ch1 != EOF) 
        { 
            if (ch2 == EOF) 
                putchar('\n'); 
            else 
                putchar(' '); 
            ch1 = getc(f1); 
        } 
        while (ch2 != EOF && ch2 != '\n') /* skipped after EOF reached */ 
        { 
            putchar(ch2); 
            ch2 = getc(f2); 
        } 
 
        if (ch2 != EOF) 
        { 
            putchar('\n'); 
            ch2 = getc(f2); 
        } 
    } 
         
    if (fclose(f1) != 0) 
        printf("Could not close file %s\n", argv[1]);     
    if (fclose(f2) != 0) 
        printf("Could not close file %s\n", argv[2]);     
         
    return 0; 
}
#include  <stdio.h> //个人
#include <string.h>

typedef int Status;

int getchoice(void);
void menu(void);
Status a(char* filename1, char* filenmae2);
Status b(char* filename1, char* filenmae2);
int main(void)
{
	menu();
	int choice;
	choice = getchoice();
	char filname1[50];
	char filname2[50];
	while (choice!='q')
	{
		switch (choice)
		{
		case 'a':
			fputs("请输入要打印的第一个文件名:",stdout);
			scanf_s("%s", filname1,50);
			while (getchar() != '\n');
			fputs("请输入要打印的第二个文件名:",stdout);
			scanf_s("%s", filname2,50);
			a(filname1, filname2);
			break;
		case 'b':
			fputs("请输入要打印的第一个文件名:", stdout);
			scanf_s("%s", filname1, 50);
			while (getchar() != '\n');
			fputs("请输入要打印的第二个文件名:", stdout);
			scanf_s("%s", filname2, 50);
			b(filname1, filname2);
			break;
		}
		putchar('\n');
		menu();
		choice = getchoice();
	}
	return 0;
}

int getchoice(void)
{
	int ch = 0;
	fputs("请输入选择:", stdout);
	ch = getchar();
	while (ch!='a'&&ch!='b'&&ch!='q')
	{
		while (getchar() != '\n');
		fputs("输入错误,请重新输入:",stdout);
		ch = getchar();
	}
	while (getchar() != '\n');
	return ch;
}

void menu(void)
{
	puts("文件打印");
	printf("a.打印第1个文件的第1行,第2个文件的第1行,"
		"第1个文件的第2行,第2个文件的第2\n行,以此类推,"
		"打印到行数较多文件的最后一行。\n" );
	puts("b.把行号相同的行打印成一行。");
}

Status a(char* filename1, char* filename2)
{
	FILE *fp1, *fp2;
	errno_t err;
	err = fopen_s(&fp1, filename1, "r");
	if (err!=0)
	{
		perror("fopen_s(file1): ");
		return 1;
	}
	err = fopen_s(&fp2, filename2, "r");
	if (err != 0)
	{
		perror("fopen_s(file2): ");
		return 1;
	}
	char temp[500];
	int mark = 0;
	int i = 1;
	while (1)
	{
		if (fgets(temp, sizeof(temp), fp1) != NULL)
		{
			printf("文件1的第%d行:", i);
			if (temp[strlen(temp) - 1] != '\n')
				temp[strlen(temp) - 1] = '\n';
			//文件的最后一行没有换行符,手动添加一个
			fputs(temp, stdout);
		}
		else
			mark = 1;
		if (fgets(temp, sizeof(temp), fp2)!=NULL)
		{
			printf("文件2的第%d行:", i);
			fputs(temp, stdout);
			i++;
			continue;
		}
		else if (mark == 1)
			break;
		i++;
	}
	fclose(fp1);fclose(fp2);
	fp1 = NULL; fp2 = NULL;
	return 0;
}

Status b(char* filename1, char* filename2)
{
	FILE* fp1, * fp2;
	errno_t err;
	err = fopen_s(&fp1, filename1, "r");
	if (err != 0)
	{
		perror("fopen_s(file1): ");
		return 1;
	}
	err = fopen_s(&fp2, filename2, "r");
	if (err != 0)
	{
		perror("fopen_s(file2): ");
		return 1;
	}
	char temp[500];
	int mark = 0;
	int i = 1;
	while (1)
	{
		if (fgets(temp, sizeof(temp), fp1) != NULL)
		{
			printf("文件1的第%d行:", i);
			temp[strlen(temp) - 1] = '\0';
			//文件的最后一行没有换行符,手动添加一个
			fputs(temp, stdout);
		}
		else
			mark = 1;
		if (fgets(temp, sizeof(temp), fp2) != NULL)
		{
			printf("文件2的第%d行:", i);
			fputs(temp, stdout);
			i++;
			continue;
		}
		else if (mark == 1)
			break;
		i++;
	}
	fclose(fp1); fclose(fp2);
	fp1 = NULL; fp2 = NULL;
	return 0;
}

13.8

编写一个程序,以一个字符和任意文件名作为命令行参数。如果字符后面没有参数,该程序读取标
准输入:否则,程序依次打开每个文件并报告每个文件中该字符出现的次数。文件名和字符本身也
要一同报告。程序应包含错误检查,以确定参数数量是否正确和是否能打开文件。如果无法打开文
件,程序应报告这一情况,然后继续处理下一个文件。

#include <stdio.h> //个人
#include <string.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		puts("参数不足");
		return 1;
	}
	else if (argc < 3)
	{
		int count = 0;
		char str[200];
		fputs("请输入字符串:", stdout);
		scanf_s("%199s", str, (unsigned)_countof(str));
		str[sizeof(str) - 1] = '\0';
		for (int i = 0; i < strlen(str); i++)
			if (str[i] == argv[1][0])
				count++;
		printf("字符%c在字符串%s中出现了%d次\n", argv[1][0], str, count);
	}
	else
	{
		int file_c = argc - 2;
		int* count = (int*)malloc(file_c * sizeof(int));
		if (count==NULL)
		{
			perror("malloc:");
			return 1;
		}
		for (int i = 0; i < file_c; i++)
			count[i] = 0;
		int ch = 0;
		for (int i = 0; i < file_c; i++)
		{
			FILE* fp;
			errno_t err = fopen_s(&fp, argv[i + 2], "r");
			if (err!=0)
			{
				perror(argv[2]);
				continue;
			}
			while ((ch=fgetc(fp))!=EOF)
				if (ch == argv[1][0])
					count[i]++;
			fclose(fp);
			fp = NULL;
		}
		for (int i = 0; i < file_c; i++)
			printf("%c在%s中出现了%d次\n", argv[1][0], argv[i + 2], count[i]);
	}
	return 0;
}

13.9

修改程序清单 13.3 中的程序,从1开始,根据加入列表的顺序为每个单词编号。当程序下次运行
时,确保新的单词编号接着上次的编号开始。

/* addaword.c -- uses fprintf(), fscanf(), and rewind() */
#include <stdio.h> //此非答案,而是题目的一部分
#include <stdlib.h>
#include <string.h>
#define MAX 41

int main(void)
{
    FILE *fp;
    char words[MAX];
    
    if ((fp = fopen("wordy", "a+")) == NULL)
    {
        fprintf(stdout,"Can't open \"wordy\" file.\n");
        exit(EXIT_FAILURE);
    }
    
    puts("Enter words to add to the file; press the #");
    puts("key at the beginning of a line to terminate.");
    while ((fscanf(stdin,"%40s", words) == 1)  && (words[0] != '#'))
        fprintf(fp, "%s\n", words);
    
    puts("File contents:");
    rewind(fp);           /* go back to beginning of file */
    while (fscanf(fp,"%s",words) == 1)
        puts(words);
    puts("Done!");
    if (fclose(fp) != 0)
        fprintf(stderr,"Error closing file\n");
    
    return 0;
}
/* Programming Exercise 13-9 */ 
/* to simplify accounting, stores one number and word per line */
#include <stdio.h> 
#include <stdlib.h> 
#define MAX 47 
 
int main(void) 
{ 
     FILE *fp; 
     char words[MAX]; 
     int wordct = 0; 
 
     if ((fp = fopen("wordy", "a+")) == NULL) 
     { 
          fprintf(stderr,"Can't open \"words\" file.\n"); 
          exit(EXIT_FAILURE); 
     } 
     // determine current number of lines 
     rewind(fp); 
     while (fgets(words, MAX, fp) != NULL) 
         wordct++; 
     rewind(fp); 
      
     puts("Enter words to add to the file; press the #"); 
     puts("key at the beginning of a line to terminate."); 
     while ((fscanf(stdin,"%40s", words) == 1)  && (words[0] != '#')) 
          fprintf(fp, "%3d: %s\n", ++wordct, words); 
     puts("File contents:"); 
     rewind(fp);           // go back to beginning of file 
     while (fgets(words, MAX, fp) != NULL) // read line including number 
          fputs(words, stdout); 
     if (fclose(fp) != 0) 
          fprintf(stderr,"Error closing file\n"); 
     puts("Done");     
 
     return 0; 
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 41
#define 编号 numbering
int main(void)
{
    FILE* fp;
    char words[MAX];
    int 编号 = 0;
    errno_t err = fopen_s(&fp, "wordy", "a+");
    if (err!=0)
    {
        fprintf(stdout, "Can't open \"wordy\" file.\n");
        exit(EXIT_FAILURE);
    }
    rewind(fp);
    while (fgets(words, MAX, fp) != NULL)
        编号++;
    rewind(fp);
    puts("Enter words to add to the file; press the #");
    puts("key at the beginning of a line to terminate.");
    while ((fscanf_s(stdin, "%40s", words,MAX) == 1) && (words[0] != '#'))
    {
        fprintf(fp, "%s\n", words);
        编号++;
    }
    puts("File contents:");
    //fflush(fp);
    rewind(fp);
    while (fscanf_s(fp, "%s", words, MAX) == 1)
        puts(words);
    puts("Done!");
    if (fclose(fp) != 0)
        fprintf(stderr, "Error closing file\n");
    return 0;
}

13.10

编写一个程序打开一个文本文件,通过交互方式获得文件名。通过一个循环,提示用户输入一个
文件位置。然后该程序打印从该位置开始到下一个换行符之前的内容。用户输入负数或非数值字
符可以结束输入循环。

#include <stdio.h> //个人
#include <stdlib.h>
#define ERRNO -1

typedef int Status;

Status get_location(void);

int main(void)
{
	char filename[50];
	fputs("请输入文件名:", stdout);
	scanf_s("%s", filename, 50);
	filename[sizeof(filename) - 1] = '\0';
	FILE* fp;
	errno_t err = fopen_s(&fp, filename, "r");
	if (err!=0)
	{
		perror("fopen_s");
		exit(EXIT_FAILURE);
	}
	int location = 0;
	char rowfile[200];
	location = get_location();
	while (location >=0)
	{
		//while (getchar() != '\n');
		fseek(fp, location, SEEK_SET);
		fgets(rowfile, 200, fp);
		fputs(rowfile, stdout);
		location = get_location();
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

Status get_location(void)
{
	int location = 0;
	fputs("请输入打印的起始位置:", stdout);
	if (scanf_s("%d", &location) == 1)
		if (location >= 0)
			return location;
		else
			return ERRNO;
	else
		return ERRNO;
}

13.11

编写一个程序,接受两个命令行参数。第1个参数是一个字符串,第2个参数是一个文件名。然
后该程序查找该文件,打印文件中包含该字符串的所有行。因为该任务是面向行而不是面向字符
的,所以要使用 fgets() 而不是 getc()。使用标准 C库函数 strstr()(11.5.7 节简要介绍过)在每一行中查找指定字符串。假设文件中的所有行都不超过255个字符。

/* Programming Exercise 13-11 */ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
 
#define SLEN 256 
const char *errmesg[] = {"Usage: %s string filename]\n", 
                         "Can't open file %s\n" }; 
             
int main(int argc, char *argv[]) 
{ 
    FILE *fp; 
    char line[SLEN]; 
 
    if (argc != 3) 
    { 
        fprintf(stderr, errmesg[0], argv[0]); 
        exit(EXIT_FAILURE); 
    } 
 
    if ((fp = fopen(argv[2], "r")) == NULL) 
    { 
        fprintf(stderr, errmesg[1], argv[2]); 
        exit(EXIT_FAILURE); 
    }
    while (fgets(line, SLEN, fp) != NULL) 
    { 
        if (strstr(line, argv[1]) != NULL) 
            fputs(line, stdout); 
    } 
         
    fclose(fp); 
 
    return 0; 
}
#include <stdio.h> //个人
#include <stdlib.h>
#include <string.h>
#define MAXROW 256

int main(int argc,char* argv[])
{
	FILE* fp;
	errno_t err = fopen_s(&fp, argv[2], "r");
	if (err)
	{
		perror("fopen_s:");
		exit(EXIT_FAILURE);
	}
	char filerow[MAXROW];
	rewind(fp);
	while (fgets(filerow,MAXROW,fp)!=NULL)
	{
		if (strstr(filerow, argv[1]) != NULL)
			fputs(filerow, stdout);
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

13.12

创建一个文本文件,内含 20 行,每行30 个整数。这些整数都在0~9之间,用空格分开。该文件是用数字表示一张图片,0~9 表示逐渐增加的灰度。编写一个程序,把文件中的内容读入一个20×30 的int数组中。一种把这些数字转换为图片的粗略方法是:该程序使用数组中的值初始化一个20×31的字符数组,用值0 对应空格字符,1对应点字符,以此类推。数字越大表示字符所占的空间越大。例如,用#表示9。每行的最后一个字符(第 31个)是空字符,这样该数组包含了20 个字符串。最后,程序显示最终的图片 (即,打印所有的字符串),并将结果储存在文本文件中。例如,下面是开始的数据:

0 0 9 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 5 8 9 9 8 5 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 1 9 8 5 4 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 5 8 9 9 8 5 0 4 5 2 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 4 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 1 8 5 0 0 0 4 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 4 5 2 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 5 8 9 9 8 5 5 5 5 5 5 5 5 5 5 5 5 5 8 8 8 8 8 8 8 8 8 8 8 8 5 8 9 9 8 5 8 8 8 8 8 8 8 8 8 8 8 8 9 9 9 9 0 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 3 9 9 9 9 9 9 9 8 8 8 8 8 8 8 8 8 8 8 8 5 8 9 9 8 5 8 8 8 8 8 8 8 8 8 8 8 8 5 5 5 5 5 5 5 5 5 5 5 5 5 8 9 9 8 5 5 5 5 5 5 5 5 5 5 5 5 5 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 6 6 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 0 0 0 5 8 9 9 8 5 0 0 5 6 0 0 6 5 0 0 0 0 0 0 0 0 3 3 0 0 0 0 0 0 5 8 9 9 8 5 0 5 6 1 1 1 1 6 5 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 5 8 9 9 8 5 0 0 5 6 0 0 6 5 0 0 0 0 0 0 0 0 5 5 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0

根据以上描述选择特定的输出字符,最终输出如下:

/* Programming Exercise 13-12 */ 
#include <stdio.h> 
#include <stdlib.h> 
 
#define ROWS    20 
#define COLS    30 
#define LEVELS  10 
const char trans[LEVELS + 1] = " .':~*=&%@"; 
 
void MakePic(int data[][COLS], char pic[][COLS], int rows); 
void init(char arr[][COLS], char ch); 
 
int main() 
{ 
    int row, col; 
    int picIn[ROWS][COLS]; 
    char picOut[ROWS][COLS]; 
    char fileName[81]; 
    FILE * infile; 
     
    init(picOut, 'S'); 
     
    printf("Enter name of file: "); 
    scanf("%80s", fileName); 
    if ((infile = fopen(fileName, "r")) == NULL) 
    { 
        fprintf(stderr, "Could not open data file.\n");
        exit(EXIT_FAILURE); 
    } 
     
    for (row = 0; row < ROWS; row++) 
        for (col = 0; col < COLS; col++) 
            fscanf(infile, "%d",  &picIn[row][col]); 
    if (ferror(infile)) 
    { 
        fprintf(stderr, "Error getting data from file.\n"); 
        exit(EXIT_FAILURE); 
    } 
    MakePic(picIn, picOut, ROWS); 
 
    for (row = 0; row < ROWS; row++) 
    { 
        for (col = 0; col < COLS; col++) 
            putchar(picOut[row][col]); 
        putchar('\n'); 
    } 
    return 0; 
} 
 
void init(char arr[][COLS], char ch) 
{ 
    int r, c; 
    for (r = 0; r < ROWS; r++) 
        for (c = 0; c < COLS; c++) 
            arr[r][c] = ch; 
} 
 
void MakePic(int data[][COLS], char pic[][COLS], int rows) 
{ 
    int row, col; 
    for (row = 0; row < rows; row++) 
        for (col = 0; col < COLS; col++) 
            pic[row][col] = trans[data[row][col]]; 
}
#include <stdio.h> //个人
#include <stdlib.h>

int main(void)
{
	int ch;
	FILE* fp;
	errno_t err = fopen_s(&fp, "伍.txt", "r");
	if (err!=0)
	{
		perror("fopen_s:");
		exit(EXIT_FAILURE);
	}
	int count = 0;
	while ((ch=fgetc(fp))!=EOF)
	{
		if (count % 30 == 0)
			putchar('\n');
		fputc(ch-17, stdout);
		putchar(' ');
		count++;
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

13.13

用变长数组 (VLA)代替标准数组,完成编程练习12。

13.14

数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12添加消除失
真的函数。该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都大于
1,则用所有相邻值的平均值(四舍五入为整数)代替该值。注意,与边界上的点相邻的点少于4
个,所以做特殊处理。

第十四章

14.1

重新编写复习题 5,用月份名的拼写代替月份号 (别忘了使用 strcmp())。在一个简单的程序中测试该函数。

/* pe14-1.c  */ 
#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
 
struct month { 
    char name[10]; 
    char abbrev[4]; 
    int days; 
    int monumb; 
}; 
 
const struct month months[12] = { 
    {"January", "Jan", 31, 1}, 
    {"February", "Feb", 28, 2}, 
    {"March", "Mar", 31, 3}, 
    {"April", "Apr", 30, 4}, 
    {"May", "May", 31, 5}, 
    {"June", "Jun", 30, 6}, 
    {"July", "Jul", 31, 7}, 
    {"August", "Aug", 31, 8}, 
    {"September", "Sep", 30, 9}, 
    {"October", "Oct", 31, 10}, 
    {"November", "Nov", 30, 11}, 
    {"December", "Dec", 31, 12} 
}; 
 
int days(char * m); 
int main(void) 
{ 
    char input[20]; 
    int daytotal; 
 
    printf("Enter the name of a month: "); 
    while (scanf("%s", input) == 1 && input[0] != 'q') 
    { 
        daytotal = days(input); 
        if (daytotal > 0) 
            printf("There are %d days through %s.\n", daytotal, input); 
        else 
            printf("%s is not valid input.\n", input); 
        printf("Next month (q to quit): "); 
    } 
    puts("bye"); 
     
    return 0; 
} 
 
int days(char * m) 
{ 
    int total = 0; 
    int mon_num = 0; 
    int i; 
    m[0] = toupper(m[0]); 
    for (i = 1; m[i] != '\0'; i++) 
        m[i] = tolower(m[i]); 
    for (i = 0; i < 12; i++) 
        if (strcmp(m, months[i].name) == 0) 
        { 
            mon_num = months[i].monumb; 
            break; 
        } 
    if (mon_num == 0) 
        total = -1; 
    else 
        for (i = 0; i < mon_num; i++) 
            total +=months[i].days; 
 
    return total; 
} 
#include <stdio.h> //个人
#include <string.h>
typedef struct month_name {
	char name[10];
	char abbreviation[3];
	int days;
	int month_num;
}MONTH;

MONTH _2025[12] = {
	{"January","jan",31,1},
	{"Fefruary","feb",28,2},
	{"March","mar",31,3},
	{"April","apr",30,4},
	{"May","may",31,5},
	{"June","jun",30,6},
	{"July","jul",31,7},
	{"August","aug",31,8},
	{"September","sep",30,9},
	{"October","oct",31,10},
	{"November","nov",30,11},
	{"December","dec",31,12},
};

int day_sum(int month);
int get_month();
int main(void)
{
	while (1)
	{
		int a = get_month();
		printf("累计到%d月有%d天\n", a, day_sum(a));
	}
	return 0;
}

int day_sum(int month)
{
	int result = 0;
	for (int i = 0; i < month; i++)
		result += _2025[i].days;
	return result;
}

int get_month()
{
	char name[10];
	printf("请输入月份的英文名:");
	while (scanf_s("%s", name,10))
	{
		for (int j = 0; j < 12; j++)
		{
			if (!strcmp(name, _2025[j].name))
				return _2025[j].month_num;
		}
		printf("输入错误!请重新输入:");
		while (getchar() != '\n');
	}
}

14.2

编写一个函数,提示用户输入日、月和年。月份可以是月份号、月份名或月份名缩写。然后该程序
应返回一年中到用户指定日子(包括这一天)的总天数。

#include <stdio.h> //个人
#include <string.h>
#include <stdlib.h>
typedef struct month_name {
	char name[10];
	char abbreviation[3];
	int days;
	int month_num;
}MONTH;

MONTH _2025[12] = {
	{"January","jan",31,1},
	{"Fefruary","feb",28,2},
	{"March","mar",31,3},
	{"April","apr",30,4},
	{"May","may",31,5},
	{"June","jun",30,6},
	{"July","jul",31,7},
	{"August","aug",31,8},
	{"September","sep",30,9},
	{"October","oct",31,10},
	{"November","nov",30,11},
	{"December","dec",31,12},
};

int day_sum();
int lowercase(char*);
int capital(char*);

int main(void)
{
	printf("%d\n", day_sum());
	return 0;
}

int day_sum()
{
	char name[10];
	int ch = 0;
	int result = 0;
	printf("请输入月份:");
	while (1)
	{
		int i;
		for (i = 0; ch != '\n'; i++)
		{
			ch = getchar();
			name[i] = ch;
		}
		name[i-1] = '\0';
		if (name[0] > 47 && name[0] < 58)
		{
			int temp = atoi(name);
			if (temp > 0 && temp < 13)
			{
				for (int j = 0; j < temp; j++)
					result += _2025[j].days;
				return result;
			}
			else
				printf("输入错误!请重新输入:");
		}
		else if (name[0] > 64 && name[0] < 91 || name[0]>96 && name[0] < 123)
		{
			char* p = &name[1];
			capital(name);
			lowercase(p);
			for (int j = 0; j < 12; j++)
			{
				result += _2025[j].days;
				if (!strncmp(name, _2025[j].name, 3))
					return result;
			}
			printf("输入错误!请重新输入:");
		}
		else
			printf("输入错误!请重新输入:");
		while (getchar != '\n');
	}
}

int lowercase(char* str)
{
	int len = strlen(str);
	for (int i = 0; i < len; i++)
		if (*(str + i) < 97)
			*(str + i) = *(str + i) + 32;
	return 0;
}

int capital(char* str)
{
	int len = strlen(str);
	for (int i = 0; i < len; i++)
		if (*(str + i) > 97)
			*(str + i) = *(str + i) - 32;
	return 0;
}

14.3

修改程序清单14.2 中的图书自录程序,使其按照输入图书的顺序输出图书的信息,然后按照标题
字母的声明输出图书的信息,最后按照价格的升序输出图书的信息。

/* pe14-3.c */ 
#include <stdio.h> 
#include <string.h> 
char * s_gets(char * st, int n); 
#define MAXTITL   40 
#define MAXAUTL   40 
#define MAXBKS   100            /* maximum number of books  */ 
struct book {                   /* set up book template     */ 
    char title[MAXTITL]; 
    char author[MAXAUTL]; 
    float value; 
}; 
 
void sortt(struct book * pb[], int n); 
void sortv(struct book * pb[], int n); 
 
int main(void) 
{ 
     struct book library[MAXBKS]; /* array of book structures */ 
     struct book * pbk[MAXBKS];   /* pointers for sorting     */ 
     int count = 0; 
     int index; 
 
     printf("Please enter the book title.\n"); 
     printf("Press [enter] at the start of a line to stop.\n"); 
     while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL 
                         && library[count].title[0] != '\0') 
     { 
          printf("Now enter the author.\n"); 
          s_gets(library[count].author, MAXAUTL); 
          printf("Now enter the value.\n"); 
          scanf("%f", &library[count].value); 
          pbk[count] = &library[count]; 
          count++; 
          while (getchar() != '\n') 
               continue;                /* clear input line */ 
          if (count < MAXBKS) 
          printf("Enter the next title.\n"); 
     } 
     printf("Here is the list of your books:\n"); 
     for (index = 0; index < count; index++) 
         printf("%s by %s: $%.2f\n", library[index].title, 
          library[index].author, library[index].value); 
           
     printf("Here is the list of your books sorted by title:\n"); 
     sortt(pbk, count); 
     for (index = 0; index < count; index++) 
         printf("%s by %s: $%.2f\n", pbk[index]->title, 
          pbk[index]->author, pbk[index]->value); 
     sortv(pbk, count); 
     printf("Here is the list of your books sorted by value:\n"); 
     for (index = 0; index < count; index++) 
         printf("%s by %s: $%.2f\n", pbk[index]->title, 
          pbk[index]->author, pbk[index]->value); 
 
     return 0; 
} 
 
void sortt(struct book * pb[], int n) 
{ 
   int top, search; 
   struct book * temp; 
 
   for (top = 0; top < n -1; top++) 
       for (search = top + 1; search < n; search++) 
            if (strcmp(pb[search]->title, pb[top]->title) < 0) 
            { 
                 temp = pb[search]; 
                 pb[search] = pb[top]; 
                 pb[top] = temp; 
            } 
} 
 
void sortv(struct book * pb[], int n) 
{ 
   int top, search; 
   struct book * temp; 
 
   for (top = 0; top < n -1; top++) 
       for (search = top + 1; search < n; search++) 
            if (pb[search]->value < pb[top]->value) 
            { 
                 temp = pb[search]; 
                 pb[search] = pb[top]; 
                 pb[top] = temp; 
            } 
} 
 
char * s_gets(char * st, int n) 
{ 
    char * ret_val; 
    char * find; 
     
    ret_val = fgets(st, n, stdin); 
    if (ret_val) 
    { 
        find = strchr(st, '\n');   // look for newline 
        if (find)                  // if the address is not NULL, 
            *find = '\0';          // place a null character there 
        else 
            while (getchar() != '\n') 
                continue;          // dispose of rest of line 
    } 
    return ret_val; 
}
#include <stdio.h> //个人
#include <string.h>
char* s_gets(char* st, int n);
void letter_sort(struct book[],int);
void value_sort(struct book*, int);
#define MAXTITL   40
#define MAXAUTL   40
#define MAXBKS   100              

struct book {                     
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int main(void)
{
    struct book library[MAXBKS]; 
    int count = 0;
    int index;

    printf("Please enter the book title.\n");
    printf("Press [enter] at the start of a line to stop.\n");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL
        && library[count].title[0] != '\0')
    {
        printf("Now enter the author.\n");
        s_gets(library[count].author, MAXAUTL);
        printf("Now enter the value.\n");
        scanf_s("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;      
        if (count < MAXBKS)
            printf("Enter the next title.\n");
    }

    if (count > 0)
    {
        printf("Here is the list of your books:\n");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title,
                library[index].author, library[index].value);
        putchar('\n');
        puts("字母顺序显示:");
        letter_sort(library, count);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title,
                library[index].author, library[index].value);
        puts("价格升序显示:");
        value_sort(library, count);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title,
                library[index].author, library[index].value);
    }
    else
        printf("No books? Too bad.\n");
    
    return 0;
}

char* s_gets(char* st, int n)
{
    char* ret_val;
    char* find;

    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');
        if (find)
            *find = '\0';
        else
            while (getchar() != '\n')
                continue;
    }
    return ret_val;
}

void letter_sort(struct book library[],int count)
{
    struct book temp;   
    for (int i = 0; i < count-1; i++)
    {
        for (int j = i+1; j <count; j++)
        {
            if (library[i].title[0]>library[j].title[0])
            {
                temp = library[i];
                library[i] = library[j];
                library[j] = temp;
            }
        }
    }
}

void value_sort(struct book* library, int count)
{
    struct book temp;
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = i + 1; j < count; j++)
        {
            if (library[i].value > library[j].value)
            {
                temp = library[i];
                library[i] = library[j];
                library[j] = temp;
            }
        }
    }
}

14.4

编写一个程序,创建一个有两个成员的结构模板:
a.第1个成员是社会保险号,第2个成员是一个有3个成员的结构,第1个成员代表名,第2个
成员代表中间名,第3个成员表示姓。创建并初始化一个内含5个该类型结构的数组。该程序
以下面的格式打印数据:
Dribble, Flossie M. -- 302039823
如果有中间名,只打印它的第1个字母,后面加一个点(.):如果没有中间名,则不用打印点。编
写一个程序进行打印,把结构数组传递给这个函数。
b.修改a 部分,传递结构的值而不是结构的地址。

#include <stdio.h> //个人
void show_a(struct person*);
void show_b(struct person);

struct name
{
	char first[20];
	char middle[10];
	char sur[10];
};
struct person
{
	char social_security[10];
	struct name man;
};

int main(void)
{
	struct person five[5] = {
		{"302039823","Dribble","Mrxize","Flossie"},
		{"301054814","Misjan","Cutebaby","Ailisi"},
		{"313542051","Aishili","Goodgirl","Jkwudi"},
		{"327852654","Beirika","Shengwu","talent"},
		{"305641329","Kennidi","Liang","Barui"}
	};
	for (int i = 0; i < 5; i++)
		show_a(five + i);
	putchar('\n');
	for (int i = 0; i < 5; i++)
		show_b(five[i]);
	return 0;
}

void show_a(struct person* one)
{
	printf("%s, %s %c. -- %s\n", one->man.first,
		one->man.sur, one->man.middle[0], one->social_security);
}

void show_b(struct person one)
{
	printf("%s, %s %c. -- %s\n", one.man.first,
		one.man.sur, one.man.middle[0], one.social_security);
}

14.5

编写一个程序满足下面的要求。
a.外部定义一个有两个成员的结构模板 name:一个字符串储存名,一个字符串储存姓。
b. 外部定义一个有 3 个成员的结构模板 student:一个 name 类型的结构,一个 grade 数组储
存3个浮点型分数,一个变量储存3个分数平均数。
c. 在 main () 函数中声明一个内含 CSIZE (CSIZE = 4) 个 student 类型结构的数组,并初始
化这些结构的名字部分。用函数执行 g、e、f 和 g 中描述的任务。
d.以交互的方式获取每个学生的成绩,提示用户输入学生的姓名和分数。把分数储存到 grade 数
组相应的结构中。可以在 main ()函数或其他函数中用循环来完成。
e.计算每个结构的平均分,并把计算后的值赋给合适的成员。
f.打印每个结构的信息。

g.打印班级的平均分,即所有结构的数值成员的平均值。

/* pe14-5.c */ 
#include <stdio.h> 
#include <string.h> 
#define LEN 14 
#define CSIZE 4 
#define SCORES 3 
struct name { 
    char first[LEN]; 
    char last[LEN]; 
}; 
struct student { 
    struct name person; 
    float scores[SCORES]; 
    float mean; 
}; 
void get_scores(struct student ar[], int lim); 
void find_means(struct student ar[], int lim); 
void show_class(const struct student ar[], int lim); 
void show_ave(const struct student ar[], int lim);  
 
int main(void) 
{ 
    struct student class[CSIZE] ={ 
        { "Flip", "Snide"}, 
        { "Clare", "Voyans"}, 
        { "Bingo", "Higgs"}, 
        { "Fawn", "Hunter"} 
    }; 
 
    get_scores(class, CSIZE); 
    find_means(class, CSIZE); 
    show_class(class, CSIZE);
    show_ave(class, CSIZE); 
    return 0; 
} 
 
void get_scores(struct student ar[], int lim) 
{ 
    int i,j; 
    for (i = 0; i < lim; i++) 
    { 
        printf ("Please enter %d scores for %s %s:\n", SCORES, 
            ar[i].person.first, ar[i].person.last); 
        for (j = 0; j < SCORES; j++) 
        { 
            while (scanf("%f", &ar[i].scores[j]) != 1) 
            { 
                scanf("%*s"); 
                puts("Please use numeric input."); 
            } 
        } 
    } 
} 
 
void find_means(struct student ar[], int lim) 
{ 
    int i, j; 
    float sum; 
     
    for (i = 0; i < lim; i++) 
    { 
        for (sum = 0, j = 0; j < SCORES; j++) 
            sum += ar[i].scores[j]; 
        ar[i].mean = sum / SCORES; 
    } 
} 
 
void show_class(const struct student ar[], int lim) 
{ 
    int i, j; 
    char wholename[2*LEN]; 
     
    for (i = 0; i < lim; i++) 
    { 
        strcpy(wholename, ar[i].person.first); 
         strcat(wholename, " "); 
         strcat(wholename, ar[i].person.last); 
          printf("%27s: ", wholename); 
          for (j = 0; j < SCORES; j++) 
            printf("%6.1f ", ar[i].scores[j]); 
        printf(" Average = %5.2f\n", ar[i].mean); 
    } 
} 
 
void show_ave (const struct student ar[], int lim) 
{ 
    int i, j; 
    float total; 
 
    printf("\n%27s: ", "QUIZ AVERAGES"); 
    for (j = 0; j < SCORES; j++) 
    { 
        for (total = 0, i = 0; i < lim; i++) 
            total += ar[i].scores[j]; 
        printf("%6.2f ", total / lim); 
  
    } 
    for (total = 0, i = 0; i < lim; i++) 
        total += ar[i].mean; 
    printf("     All = %5.2f\n", total / lim); 
}
#include <stdio.h> //个人
#include <string.h>
#define CSIZE 4
void get_grade(struct student*);
void show(const struct student*);
void paverage(struct student*,int);

struct name {
	char first_name[10];
	char last_name[10];
};

struct student {
	struct name sname;
	float grade[3];
	float average;
};

int main(void)
{
	struct student glass[CSIZE] = {
		{"Duan","Xiaoyang"},
		{"Wang","Zhihao"},
		{"Song","Shoufeng"},
		{"Yang","Chaoran"}
	};
	float glass_average = 0;
	get_grade(glass);
	paverage(glass, CSIZE);
	for (int i = 0; i < CSIZE; i++)
		show(glass + i);
	for (int i = 0; i < CSIZE; i++)
		glass_average += (glass + i)->average;
	glass_average /= CSIZE;
	printf("班级平均成绩为:%.2f\n", glass_average);
	return 0;
}

void get_grade(struct student* one)
{
	char reference[20];
	char temp[20];
	for (int i = 0; i < CSIZE; i++)
	{
		int j;
		fputs("请输入学生姓名:", stdout);
		gets_s(reference, 20);
		for (j = 0; j < CSIZE; j++)
		{
			strncpy_s(temp, 20, (one + j)->sname.first_name, 10);
			strncat_s(temp, 20, (one + j)->sname.last_name, 10);
			if (!strcmp(reference, temp))
			{
				for (int k = 0; k < 3; k++)
				{
					printf("请输入%s的成绩:", reference);
					scanf_s("%f", &(one + i)->grade[k]);
				}
				while (getchar() != '\n');
				break;
			}
		}
		if (j == CSIZE)
		{
			printf("姓名输入错误!未找到该学生。\n");
			i -= 1;
		}
	}
}

void show(const struct student* one)
{
	printf("%s %s:%.2f、%.2f、%.2f,平均分:%.2f\n",one->sname.first_name,one->sname.last_name,
		one->grade[0],one->grade[1],one->grade[2],one->average);
}

void paverage(struct student* one,int number)
{
	float temp;
	for (int i = 0; i < number; i++)
	{
		temp = 0;
		for (int j = 0; j < 3; j++)
			temp += (one + i)->grade[j];
		(one + i)->average = temp / 3;
	}
}

14.6

一个文本文件中保存着一个垒球队的信息。每行数据都是这样排列:
4 Jessie Joybat 5 2 1 1

第1项是球员号,为方便起见,其范围是0~18。第2项是球员的名。第3项是球员的姓。名和姓都是一个单词。第4项是官方统计的球员上场次数。接着3项分别是击中数、走垒数和打点(RBI)。文件可能包含多场比赛的数据,所以同一位球员可能有多行数据,而且同一位球员的多行数据之间可能有其他球员的数据。编写一个程序,把数据储存到一个结构数组中。该结构中的成员要分别表示球员的名、姓、上场次数、击中数、走垒数、打点和安打率(稍后计算)。可以使用球员号作为数组的索引 。该程序要读到文件结尾,并统计每位球员的各项累计总和。

世界棒球统计与之相关。例如,一次走垒和触垒中的失误不计入上场次数,但是可能产生一个RBI。但是该程序要做的是像下面描述的一样读取和处理数据文件,不会关心数据的实际含义。

要实现这些功能,最简单的方法是把结构的内容都初始化为零,把文件中的数据读入临时变量中,然后将其加入相应的结构中。程序读完文件后,应计算每位球员的安打率,并把计算结果储存到结构的相应成员中。计算安打率是用球员的累计击中数除以上场累计次数。这是一个浮点数计算。最后,程序结合整个球队的统计数据,一行显示一位球员的累计数据。

14.7

修改程序清单 14.14,从文件中读取每条记录并显示出来,允许用户删除记录或修改记录的内容。
如果删除记录,把空出来的空间留给下一个要读入的记录。要修改现有的文件内容,必须用 r+b“
模式,而不是"a+b"模式。而且,必须更加注意定位文件指针,防止新加入的记录覆盖现有记录。
最简单的方法是改动储存在内存中的所有数据,然后再把最后的信息写入文件。跟踪的一个方法是
在book结构中添加一个成员表示是否该项被删除。

14.8

巨人航空公司的机群由 12 个座位的飞机组成。它每天飞行一个航班。根据下面的要求,编写一个
座位预订程序。
a.该程序使用一个内含 12 个结构的数组。每个结构中包括:一个成员表示座位编号、一个成员
表示座位是否已被预订、一个成员表示预订人的名、一个成员表示预订人的姓。
b. 该程序显示下面的菜单:
To choose a function, enter its letter label :
a) Show number of empty seats
b) Show list of empty seats
c) Show alphabetical list of seats
d) Assign a customer to, a seat assignment
e) Delete a seat assignment
f) Qui t
c.该程序能成功执行上面给出的菜单。选择 d)和 e)要提示用户进行额外输入,每个选项都能让
用户中止输入。
d.执行特定程序后,该程序再次显示菜单,除非用户选择 f)。

14.9

巨人航空公司 (编程练习 8) 需要另一架 飞机 (容量相同),每大飞4 班 (航班 102、311、444 和519)。把程序扩展为可以处理4个航班。用一个顶层菜单提供航班选择和退出。选择一个特定航班,就会出现和编程练习8类似的菜单。但是该菜单要添加一个新选项:确认座位分配。而且,菜单中的退出是返回顶层菜单。每次显示都要指明当前正在处理的航班号。另外,座位分配显示要指明确认状态。

14.10

编写一个程序,通过一个函数指针数组实现菜单。例如,选择菜单中的 a,将激活由该数组第 1个元素指向的函数。

14.11

编写一个名为 trans form ()的函数,接受 4 个参数:内含 double 类型数据的源数组名、内含
double 类型数据的目标数组名、一个表示数组元素个数的 int 类型参数、函数名 (或等价的函
数指针)。transform ()函数应把指定函数应用于源数组中的每个元素,并把返回值储存在目标
数组中。例如:transform (source, target, 100, sin) ;
该声明会把 target [0] 设置为 sin (source[0]),等等,共有 100 个元素。在一个程序中调用
transform ()4 次,以测试该函数。分别使用 math.h 函数库中的两个函数以及自定义的两个函
数作为参数。

第十五章

15.1

第十六章

16.1

第十七章

17.1

代码转载自:https://pan.quark.cn/s/133311188eb6 ### C# DllImport功能说明及路径选取问题分析 #### 一、DllImport核心原理 `DllImport`是.NET Framework内的一种技术,用于执行平台调用服务(Platform Invoke, 简称P/Invoke),该机制使得.NET应用程序能够调用非托管代码中的函数,例如Windows API或其他非托管库中的函数。这对于增强.NET应用程序的功能性非常关键,因为许多高级系统级操作(例如文件操作、进程控制等)通常由非托管库负责实现。 `DllImport`特性包含在`System.Runtime.InteropServices`命名空间中,它的主要功能是向CLR(Common Language Runtime)指示如何定位并调用非托管库中的特定函数。 #### 二、DllImport特性包含的主要元素 `DllImport`特性所包含的主要元素有: - **DllName**:必需的字符串参数,用于表明需要导入的非托管库的名称。 - **CallingConvention**:可选参数,用于设定调用协议。在默认情况下,其值为`CallingConvention.Cdecl`。 - **CharSet**:可选参数,用于定义字符集的类型。在默认情况下,其值为`CharSet.Auto`,即根据函数的签名自动决定字符集。 - **EntryPoint**:可选参数,用于指定非托管库中的函数名称。若未提供,则默认使用应用程序的方法名称作为函数名称。 - **ExactSpelling**:可选布尔值,用于确定函数名称是否必须与非托管库中的完全一致。...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值