本章所有编程练习的工程源码可在此处下载(点击打开下载链接),供大家参考交流!
1. 编写一个程序,不断要求用户输入两个数,直到其中的一个为0。对于每两个数,程序将使用一个函数来计算它们的调和平均数,并将结果返回给main(),而后者将报告结果。调和平均数指的是倒数平均值的倒数,计算公式如下:
调和平均数=2.0*x*y/(x+y)
本题要求编写一个函数,该函数接受的输入参数为两个int类型的数,函数内部计算这两个数的调和平均数,然后将结果返回给main(),由main()来显示该结果。对于输入终止,题目设定的是当输入中有一个数是0时,输入就结束。这个输入终止的功能只需要设置一个if判断就可以完成了;另外对于调用函数,我们将输入的循环放在main()里面,然后判断了没有0之后,再把这两个输入的数作为参数来调用计算函数即可。
代码如下:
// 7.1.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
double cal(int x, int y);
int main()
{
int x, y;
double ave;
while (1)
{
cout << "Please enter two number:";
cin >> x >> y;
if (x == 0 || y == 0)
{
cout << "Input terminated\nQuit\n";
break;
}
else
{
ave = cal(x, y);
cout << "The harmonic average is " << ave << endl;
}
}
system("pause");
return 0;
}
double cal(int x, int y)
{
double ave;
ave = 2.0 * double(x * y) / (x + y);
return ave;
}
运行结果如下图所示:
2. 编写一个程序,要求用户输入最多10个高尔夫成绩,并将其存储在一个数组中。程序允许用户提早结束输入,并在一行上显示所有成绩,然后报告平均成绩。请使用3个数组处理函数来分别进行输入、显示和计算平均成绩。
本题要求编写3个函数,分别用来输入、显示和计算平均成绩,同时规定最多10个成绩,但也可以允许提早结束输入,对于这个功能,我们可以在提示用户输入时提示输入一个特定字符以结束,而函数内部我们定义用户输入的内容为double类型,这样一旦输入char字符型,就会输入失败,接下来用一个if判断来判断输入是否失败就可以完成提早结束输入了。对于显示和计算函数,我们只需要把储存成绩的double数组和数组长度作为参数传给函数,然后在函数内部使用for循环来进行显示和计算就可以了。
代码如下:
// 7.2.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
const int Max = 10;
int input(double ar[], int limit);
void display(const double ar[], int n);
double cal(double ar[], int n);
using namespace std;
int main()
{
double scores[Max];
int size = input(scores, Max);
display(scores, size);
double ave;
ave = cal(scores, size);
cout << "\nThe average score is " << ave << endl;
system("pause");
return 0;
}
int input(double ar[], int limit)
{
int i;
double score;
cout << "Please enter the scores, 'q' to quit.\n";
for (i = 0; i < limit; i++)
{
cout << "Enter the score #" << (i + 1) << ": ";
cin >> score;
if (!cin)
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Input process terminated\nQuit\n";
break;
}
ar[i] = score;
}
return i;
}
void display(const double ar[], int n)
{
cout << "You entered " << n << " scores.\n";
cout << "The scores are:\n";
for (int i = 0; i < n; i++)
{
cout << ar[i] << "\t";
}
}
double cal(double ar[], int n)
{
double ave;
double sum = 0.0;
for (int i = 0; i < n; i++)
{
sum += ar[i];
}
ave = sum / n;
return ave;
}
运行结果如下图所示:
代码中我写的是提示用户输入q来退出输入,下图是用户输入q提早结束的情况:
下图是输入10个数之后自动输出结果的情况:
3. 下面是一个结构声明:
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
a. 编写一个函数,按值传递box结构,并显示每个成员的值。
b. 编写一个函数,传递box结构的地址,并将volume成员设置为其他三维长度的乘积。
c. 编写一个使用这两个函数的简单程序。
本题要求编写两个函数,一个用来按值传递结构,显示数据;一个用来按地址传递结构,并计算数据;然后在main()中来调用这两个函数完成功能。对于按值传递结构,我们就正常使用就可以了,比如以下语句:
box a;
cout << a.maker;
cout << a.height;
cout << a.width;
cout << a.length;
cout << a.volume;
就会正常输出a这个box结构的maker, height, width, length, 和volume这些数据。
而对于按地址传递,声明时应该写成以下形式:
datatype func(box * a);
然后调用语句应是以下形式:
b = func(&a);
然后在函数内部,结构成员的使用要把.改成->,如以下形式:
vol = a->height * a->width * a->length;
以上语句就是用来计算体积的。
代码如下:
// 7.3.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
struct box
{
char maker[40];
float height;
float width;
float length;
float volume;
};
void display(box temp);
float cal(box * temp);
using namespace std;
int main()
{
cout << "The following is the example box.\n";
box temp;
cout << "Please enter the box maker: ";
cin >> temp.maker;
cout << "Please enter the height: ";
cin >> temp.height;
cout << "Please enter the width: ";
cin >> temp.width;
cout << "Please enter the length: ";
cin >> temp.length;
cout << "Please enter the volume: ";
cin >> temp.volume;
display(temp);
float vol;
vol = cal(&temp);
cout << "\nBut after the calculation, the volume of the box is " << vol << endl;
system("pause");
return 0;
}
void display(box temp)
{
cout << "\nThe maker of the box is " << temp.maker << "." << endl;
cout << "The height of the box is " << temp.height << "." << endl;
cout << "The width of the box is " << temp.width << "." << endl;
cout << "The length of the box is " << temp.length << "." << endl;
cout << "The volume of the box is " << temp.volume << "." << endl;
}
float cal(box * temp)
{
float vol;
vol = temp->height * temp->width * temp->length;
return vol;
}
运行结果如下图所示:
4. 许多州的彩票发行结构都使用如程序清单7.4所示的简单彩票玩法的变体。在这些玩法中,玩家从一组被称为域号码(field number)的号码中选择几个。例如,可以从域号码1~47中选择5个号码;还可以从第二个区间(如1~27)选择一个号码(称为特选号码)。要赢得头奖,必须正确猜中所有的号码。中头奖的几率是选中所有域号码的几率与选中号码几率的乘积。例如,在这个例子中,中头奖的几率是从47个号码中正确选取5个号码的几率与从27个号码中正确选择1个号码的几率的乘积。请修改程序清单7.4,以计算中得这种彩票头奖的几率。
本题要计算中头奖的概率,其实就是计算47个数中选5个特定数的概率与27个数中选1个特定数的概率之积,我们只需要把47,5,27,1这四个数按值传递给单独计算的函数,计算出结果之后再返回给main()显示就可以了。
代码如下:
// 7.4.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
double cal(int num1, int num2, int bingo1, int bingo2);
const int Num1 = 47;
const int Num2 = 27;
const int Bingo1 = 5;
const int Bingo2 = 1;
int main()
{
cout << "Your Probability to win the first prize in this game is\t";
double pro;
pro = cal(Num1, Num2, Bingo1, Bingo2);
cout << pro << " !!!" << endl;
system("pause");
return 0;
}
double cal(int num1, int num2, int bingo1, int bingo2)
{
double pro, pro1, pro2;
pro1 = double(bingo1) / double(num1);
pro2 = double(bingo2) / double(num2);
pro = pro1 * pro2;
return pro;
}
运行结果如下图所示:
5. 定义一个递归函数,接受一个整数参数,并返回该参数的阶乘。前面讲过,3的阶乘写作3!,等于3*2!,依此类推;而0!被定义为1。通用的计算公式是,如果n大于零,则n!=n*(n-1)!。在程序中对该函数进行测试,程序使用循环让用户输入不同的值,程序将报告这些值的阶乘。
本题要求编写一个递归函数来计算阶乘,由于阶乘是累乘运算,所以需要循环多次地调用该递归函数,比如func(n)里面就会调用func(n-1),这样依次下去,然后规定好func(0)=1就可以了。在main()函数里,我做了一些处理,首先是提示用户输入,q退出输入,然后识别用户输入的是否是可接受的整数,其次判断是否是非负数,然后都判决通过之后才会去调用递归函数。
代码如下:
// 7.5.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
int fac(int n);
using namespace std;
int main()
{
cout << "This program can calculate the factorial.\t'q' to quit." << endl;
int n;
int result;
while (1)
{
cout << "Please enter the number for factorial: ";
cin >> n;
if (!cin)
{
cout << "Input terminated.\nQuit\n";
break;
}
else if (n < 0)
{
cout << "Bad input, please enter a positive number!" << endl;
continue;
}
else if (n >= 0)
{
result = fac(n);
cout << "The factorial of " << n << " is " << result << endl;
}
}
system("pause");
return 0;
}
int fac(int n)
{
int result;
if (n == 0)
result = 1;
else
{
result = n * fac(n - 1);
}
return result;
}
运行结果如下图所示:
6. 编写一个程序,它使用下列函数:
Fill_array()将一个double数组的名称和长度作为参数。它提示用户输入double值,并将这些值存储到数组中。当数组被填满或用户输入了非数字时,输入将停止,并返回实际输入了多少个数字。
Show_array()将一个double数组的名称和长度作为参数,并显示该数组的内容。
Reverse_array()将一个double数组的名称和长度作为参数,并将存储在数组中的值的顺序反转。
程序将使用这些函数来填充数组,然后显示数组;反转数组,然后显示数组;反转数组中除第一个和最后一个元素之外的所有元素,然后显示数组。
本题要求编写3个函数,第一个函数用来提示用户输入,储存输入的值到数组中,并判断在输入了非数字时停止输入;第二个函数用来显示数组的内容;第三个函数用来将数组中的数值的顺序反转。在main()里面,我们按以下功能来依次调用以上三个函数,首先填充数组并显示,然后反转数组并显示,然后反转数组中除第一个和最后一个元素之外的所有元素再显示。所以前面都是正常调用函数,参数也是正常的参数,但是最后一个功能的时候,我们在调用反转函数Reverse_array()时,使用的参数将有所变化,因为它要反转的是除去第一个元素和最后一个元素之外的元素,所以长度肯定比之前小2,而且起始也比之前往后移了1位,所以我们最后一个调用应该是形如以下这样的语句:
Reverse_array(ar + 1, size - 2);
代码如下:
// 7.6.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
int Fill_array(double ar[], int size);
void Show_array(double ar[], int size);
void Reverse_array(double ar[], int size);
using namespace std;
const int Max = 20;
int main()
{
cout << "Please enter the data of array. 'q' to quit.\n";
double ar[Max];
int size;
size = Fill_array(ar, Max);
Show_array(ar, size);
Reverse_array(ar, size);
cout << "\nAfter the reverse.";
Show_array(ar, size);
Reverse_array(ar, size);
cout << "\nAfter the reverse.";
Reverse_array(ar + 1, size - 2);
Show_array(ar, size);
cout << endl;
system("pause");
return 0;
}
int Fill_array(double ar[], int size)
{
int i;
double j;
int num;
for (i = 0; i < size; i++)
{
cin >> j;
if (!cin)
{
cout << "Input terminated.\nQuit.\n";
break;
}
else
{
ar[i] = j;
}
num = i + 1;
}
return num;
}
void Show_array(double ar[], int size)
{
int i;
cout << "\nThe array is:\n";
for (i = 0; i < size; i++)
{
cout << ar[i] << " ";
}
}
void Reverse_array(double ar[], int size)
{
int i;
double temp;
for (i = 0; i < (size / 2); i++)
{
temp = ar[i];
ar[i] = ar[size - 1 - i];
ar[size - 1 - i] = temp;
}
}
运行结果如下图所示:
7. 修改程序清单7.7中的3个数组处理函数,使之使用两个指针参数来表示区间。fill_array()函数不返回实际读取了多少个数字,而是返回一个指针,该指针指向最后被填充的位置;其他的函数可以将该指针作为第二个参数,以标识数据结尾。
本题要求将正常的数组处理函数,改为使用指针作参数来传递的函数,将按值传递数组改为按地址传递数组,同时把传递数组长度的数改为标识数据结尾的指针。其实就完全只需要把程序清单7.7里面的参数都改为指针式,对应地把对数组数据和长度的操作都改为对指针的操作就可以了。
代码如下:
// 7.7-arrfun3.cpp: 定义控制台应用程序的入口点。
// 7.7-arrfun3.cpp: array functions and const
#include "stdafx.h"
#include <iostream>
const int Max = 5;
double *fill_array(double *ar, double *limit);
void show_array(const double *ar, double *n);
void revalue(double r, double *ar, double *n);
int main()
{
using namespace std;
double properties[Max];
double *size = fill_array(properties, properties + Max);
show_array(properties, size);
cout << "Enter revaluation factor: ";
double factor;
cin >> factor;
revalue(factor, properties, size);
show_array(properties, size);
cout << "Done.\n";
system("pause");
return 0;
}
double *fill_array(double *ar, double *limit)
{
using namespace std;
double temp;
int i = 0;
double *p;
for (p = ar; p < limit; p++, i++)
{
cout << "Enter value#" << (i + 1) << ": ";
cin >> temp;
if (!cin)
{
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Bad input; input process terminated.\n";
break;
}
else if (temp < 0)
break;
*p = temp;
}
return p;
}
void show_array(const double *ar, double *n)
{
using namespace std;
int i = 0;
for (const double *p = ar; p < n; p++, i++)
{
cout << "Property #" << (i + 1) << ": $";
cout << *p << endl;
}
}
void revalue(double r, double *ar, double *n)
{
for (double *p = ar; p < n; p++)
*p *= r;
}
运行结果如下图所示:
8. 在不使用array类的情况下完成程序清单7.15所做的工作。编写两个这样的版本:
a. 使用const char*数组存储表示季度名称的字符串,并使用double数组存储开支。
b. 使用const char*数组存储表示季度名称的字符串,并使用一个结构,该结构只有一个成员——一个用于存储开支的double数组。这种设计与使用array类的基本设计类似。
程序清单7.15使用了array类来存储季度的字符串,对于开支并没有专门存储,而是直接输入就使用了;本题则要求在此基础上进行改良,得到两个版本,第一个版本是使用const char*数组存储字符串,使用double数组存储开支;第二个版本是使用const char*数组存储字符串,使用结构存储开支。
对于第一种情况,使用数组来存储开支,那么我们在调用输入函数和显示函数的时候,也就按值传递数组就可以了;对于第二种情况,使用结构来存储开支,我们在调用输入函数和显示函数的时候,也可以直接按值传递,但为了练习,我使用了结构指针来完成任务。
第一个版本代码如下:
// 7.8.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
const int Seasons = 4;
const char * Snames[Seasons] = { "Spring", "Summer", "Fall", "Winter" };
void fill(double pa[]);
void show(double pa[]);
using namespace std;
int main()
{
double expenses[Seasons];
fill(expenses);
show(expenses);
system("pause");
return 0;
}
void fill(double pa[])
{
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> pa[i];
}
}
void show(double pa[])
{
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << pa[i] << endl;
total += pa[i];
}
cout << "Total Expenses: $" << total << endl;
}
运行结果如下图所示:
第二个版本代码如下:
// 7.8-b.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
const int Seasons = 4;
struct ex
{
double expenses[Seasons];
};
const char * Snames[Seasons] = { "Spring", "Summer", "Fall", "Winter" };
void fill(ex * pa);
void show(ex * pa);
using namespace std;
int main()
{
ex pa;
fill(&pa);
show(&pa);
system("pause");
return 0;
}
void fill(ex * pa)
{
for (int i = 0; i < Seasons; i++)
{
cout << "Enter " << Snames[i] << " expenses: ";
cin >> pa->expenses[i];
}
}
void show(ex * pa)
{
double total = 0.0;
cout << "\nEXPENSES\n";
for (int i = 0; i < Seasons; i++)
{
cout << Snames[i] << ": $" << pa->expenses[i] << endl;
total += pa->expenses[i];
}
cout << "Total Expenses: $" << total << endl;
}
运行结果如下图所示:
9. 这个练习让您编写处理数组和结构的函数。下面是程序的框架,请提供其中描述的函数,以完成该程序。(相信大家书上都有题,这里就不细细敲下来了)
本题需要编写4个函数,其他内容都给你规定好了。
第一个函数getinfo(),一个结构体数组,一个int类型参数,结构体数组参数存储了学生的姓名,爱好,oop等级这三个信息,而int类型的参数则是输入数据的数目的上界,也可以通过直接敲回车来提前结束输入,否则就需要输入到上界数目个信息。
第二个函数display1(),该函数就只接受一个结构体参数,然后把结构体的内容显示出来。
第三个函数display2(),该函数接受一个结构指针,然后显示结构体内容。
第四个函数display3(),该函数接受结构体数组和int类型参数,对应于getinfo()函数的两个参数,然后把结构体的内容显示出来。
代码如下:
// 7.9.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
const int SLEN = 30;
struct student {
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
int getinfo(student pa[], int n);
void display1(student st);
void display2(const student * ps);
void display3(const student pa[], int n);
int main()
{
cout << "Enter class size: ";
int class_size;
cin >> class_size;
while (cin.get() != '\n')
continue;
student * ptr_stu = new student[class_size];
int entered = getinfo(ptr_stu, class_size);
for (int i = 0; i < entered; i++)
{
display1(ptr_stu[i]);
display2(&ptr_stu[i]);
}
display3(ptr_stu, entered);
delete[] ptr_stu;
cout << "Done\n";
system("pause");
return 0;
}
int getinfo(student pa[], int n)
{
int count = 0;
for (int i = 0; i<n; i++)
{
cout << "Please enter the fullname:";
cin.getline(pa[i].fullname, 30);
cout << "Please enter the hobby:";
cin >> pa[i].hobby;
cout << "Please enter the ooplevel:";
cin >> pa[i].ooplevel;
cin.get();
count++;
}
cout << "Enter end!" << endl;;
return count;
}
void display1(student st)
{
cout << "\ndisplay1:\nFullName:" << st.fullname << "\nhobby:" << st.hobby
<< "\nooplevel:" << st.ooplevel << endl;
}
void display2(const student *ps)
{
cout << "\ndispaly2:\nFullName:" << ps->fullname << "\nhobby:" << ps->hobby
<< "\nooplevel:" << ps->ooplevel << endl;
}
void display3(const student pa[], int n)
{
cout << "\ndispaly3:" << endl;
for (int i = 0; i<n; i++)
cout << i << "::\nFullName:" << pa[i].fullname << "\nhobby:" << pa[i].hobby
<< "\nooplevel:" << pa[i].ooplevel << endl;
}
需要注意的是getinfo()函数里面,由于要求输入全名fullname,所以肯定要允许输入多个单词,所以对于char数组要使用cin.getline()函数,而hobby和ooplevel的内容又是使用cin>>的方式输入,所以必须在cin.getline()函数前面一个cin>>的后面加一句cin.get()函数来抵消掉由于二者联合使用,而cin>>在前而导致的缓冲区内多出来的一个回车符,该问题在我写的《C++ Primer Plus 第六版》的第5章练习题答案中有详细描述(点击打开链接)。
运行结果如下图所示:
10. 设计一个名为calculate()的函数,它接受两个double值和一个指向函数的指针,而被指向的函数接受两个double参数,并返回一个double值。calculate()函数的类型也是double,并返回被指向的函数使用calculate()的两个double参数计算得到的值。例如,假设add()函数的定义如下:
double add(double x, double y)
{
return x + y;
}
则下述代码中的函数调用将导致calculate()把2.5和10.4传递给add()函数,并返回add()的返回值(12.9);
double q = calculate(2.5, 10.4, add);
请编写一个程序,它调用上述两个函数和至少另一个与add()类似的函数。该程序使用循环来让用户成对地输入数字。对于每对数字,程序都使用calculate()来调用add()和至少一个其他的函数。如果读者爱冒险,可以尝试创建一个指针数组,其中的指针指向add()样式的函数,并编写一个循环,使用这些指针连续让calculate()调用这些函数。提示:下面是声明这种指针数组的方式,其中包含三个指针:
double (*pf[3])(double, double);
可以采用数组初始化语法,并将函数名作为地址来初始化这样的数组。
本题要求编写一个calculate()函数来做计算,然后还有两个具体计算的函数,一个add()已经给出来了,另一个我们可以就用sub()来做减法就可以了。题目说爱冒险可以用指针数组,那么我就冒险一把,使用这种指针数组的方式来传递,其实只需要在给calculate()函数传递函数的时候使用指针数组就可以了,不需要特别单独去声明这个指针数组。
我编写的程序是首先提示用户输入两个数,判断输入的数是否符合要求,然后将这两个数分别和add()函数及sub()函数组合形成两组参数,分别使用这两组参数调用calculate()函数,得到结果之后显示出来。
代码如下:
// 7.10.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
double add(double x, double y);
double sub(double x, double y);
double calculate(double x, double y, double (*func)(double x, double y));
using namespace std;
int main()
{
while (1)
{
cout << "Please enter two numbers, 'q' to quit: ";
double x, y;
double result;
cin >> x >> y;
if (!cin)
{
cout << "Input terminated.\nQuit.\n";
break;
}
double q = calculate(x, y, add);
double w = calculate(x, y, sub);
cout << x << " add " << y << " equals to " << q << endl;
cout << x << " minus " << y << " equals to " << w << endl;
}
system("pause");
return 0;
}
double add(double x, double y)
{
return x + y;
}
double sub(double x, double y)
{
return x - y;
}
double calculate(double x, double y, double (*func)(double x, double y))
{
double result;
result = (*func)(x, y);
return result;
}
由上述代码可以看出,使用题中所说的冒险的方法,其实也并不怎么复杂,无非就是正常地传递函数变为传递函数指针而已。
运行结果如下图所示:
本章所有编程练习的工程源码可在此处下载(点击打开下载链接),供大家参考交流!