C++ Primer Plus(第六版)编程练习 第7章 函数——C++的编程模块

本章所有编程练习的工程源码可在此处下载(点击打开下载链接),供大家参考交流!


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;
}

由上述代码可以看出,使用题中所说的冒险的方法,其实也并不怎么复杂,无非就是正常地传递函数变为传递函数指针而已。

运行结果如下图所示:



本章所有编程练习的工程源码可在此处下载(点击打开下载链接),供大家参考交流!

猜你喜欢

转载自blog.csdn.net/leowinbow/article/details/80980489