《C++ Primer Plus》第七章复习题和编程练习

一、复习题

1. 使用函数的三个步骤是什么?

答:

  1. 函数声明
  2. 函数定义
  3. 调用函数

2. 请创建与下面的描述匹配的函数原型。

答:

// 函数声明
a. void igor();
b. float tofu(int i);
c. double mpg(double d1, double d2);
d. long summation(long arr[], int size);
e. double doctor(const char* str);
f. void ofcourse(boss bs);
g. char* plot(map* pm);

函数声明可以省略函数名,数组既可以使用数组表示法,也可以使用指针表示法(推荐数组表示法)。

3. 编写一个接受3个参数的函数,3个参数分别为int数组名、数组长度和一个int值,并将数组的所有元素设置为该int值。

答:

// 函数声明
void set_arr(int arr[], int size, int set);

int main()
{
	// 操作
	...
	return 0;// 函数定义
void set_arr(int arr[], int size, int set)
{
	// 遍历数组,把每个元素的值设置为set
	for (int i = 0; i < size; ++i)
	{
		arr[i] = set;
	}
}

4. 编写一个接受3个参数的函数,3个参数分别为指向数组区间中的第一个元素的指针,指向数组区间中最后一个元素后面的指针已经一个int值,并将数组的每个元素设置为该int值。

答:

// 函数声明
void set_arr(int *begin, int *end, int set);

int main()
{
	// 操作
	...
	return 0;
}

// 函数定义
void set_arr(int *begin, int *end, int set)
{
	// 遍历数组,把每个元素的值设置为set
	while (begin < end)
	{
		*begin = set;
	}
}

5. 编写以double类型的数组名和长度最为参数并返回该数组中最大值的函数。该函数不应该修改数组的内容。

答:

// 函数声明
double find_max(double arr[], int size);

int main()
{
	// 操作
	...
	
	return 0;
}

// 函数定义
double find_max(double arr[], int size)
{
	// 让数组第一个元素和剩余元素比较,找出最大值
	int max = arr[0];
	for (int i = 1; i < size; ++i)
	{
		if (arr[i] > max)
			max = arr[i];
	}
	// 返回数组最大值
	return max;
}

6. 为什么不对类型为基本类型的函数参数使用const限定符?

答:在C++中参数传递是以值传递的方式实现的。int、double等基本类型传参,函数中使用的形参是实参的副本,形参改变不会影响实参。而数组、指针等复合类型传参,传递的是实参的地址,函数中的形参可以通过传入的地址改变实参。所以,基本类型不需要使用const限定符,而数组、指针等复合类型在需要的时候可以通过const限定符保护原数据。(这个东西不好讲,每个人都有自己的理解,理解了大概意思就行,在后面学习的过程中会慢慢理解的)。

7. C++程序可以使用哪三种C风格字符串?

答:
1)以空字符结尾存储在字符数组中的字符串
2)双引号标识的字符串常量
3)指向char类型的指针代表的字符串

8. 编写一个函数,其原型如下。
int replace(char* str, char c1, char c2);
该函数将字符串中所有的c1都替换为c2,并返回替换次数。

答:

// 函数声明
int replace(char *str, char c1, char c2);

int main()
{
	// 操作
	...
	
	return 0;
}

// 函数定义
int replace(char *str, char c1, char c2)
{
	int times = 0;  // 记录交换次数
	// 遍历整个字符串,发现c1就用c2替换,并记录替换次数
	while (*str)
	{
		if (*str == c1)
		{
			// 交换并记录次数
			*str = c2;
			++times;
		}
		// 下一个字符
		++str;
	}
	// 返回替换次数
	return times;
}

9. 表达式*"pizza"的含义是什么?“taco”[2]呢?

答:在C++中,双引号表示的字符串常量实际上代表的是第一个字符的地址,所以*“pizza"代表字符p,而"taco”[2]是字符串的数组表示法,代表字符c。

10. C++允许按值传递结构体,也允许传递结构体的地址。如果glitz是一个结构体变量,如何按值传递它?如何传递它的地址?这两种方法有何利弊?

答:
1)值传递:直接将变量名传递给函数——glitz
优点:使用原数据的副本,保护原数据。
缺点:拷贝过程消耗时间和空间。

2)传地址:&glitz
优点:直接使用原数据,节省时间和空间。
缺点:不能保护原数据,除非使用const限定符。

11. 函数judge()的返回类型为int,它将以一个函数的地址作为参数,以const char指针作为参数,返回一个int值。请编写judge()函数的原型。

答:

// 函数声明
int judge(int (*pf)(const char*));

12. 假设有如下结构体声明。

// application结构声明
struct application{
	char name[30];
	int credit_tatings[3];
}

a. 编写一个函数,它以application结构体作为参数,并显示该结构体的内容。
b. 编写一个函数,它以application结构体的地址作为参数,并显示该结构体的内容。

答:

// a.函数声明
void print1_struct(application app);
// b.函数声明
void print_struct(application *papp);

int main()
{
	// 操作
	...

	return 0;
}

// a.函数定义
void print1_struct(application app)
{
	cout << app.name << endl;
	for (int i = 0; i < 3; ++i)
		cout << app.credit_ratings[i] << endl;
}

// b.函数定义
void print2_struct(application papp)
{
	cout << app.name << endl;
	for (int i = 0; i < 3; ++i)
		cout << app.credit_ratings[i] << endl;
}

13. 假设函数f1()和f2()的原型如下。
void f1(applicant *a);
const char *f2(const applicant *a1, const applicant *a2);
请将p1与p2分别声明为指向f1和f2的指针…。

答:

// 用typedef简化类型声明
typedef void (*ptype1)(applicant *a);
typedef const char* (*ptype2)(const applicant *a1, const applicant *a2);
// 声明
ptype1 p1 = f1;
ptype2 p2 = f2;
ptype1 ap[5];
ptype2 (*pa)[10];

二、编程练习

1. 编写一个程序,不断要求用户输入两个数,直到其中一个为0。对于每两个数,程序将使用一个函数来计算它们的调和平均数,并将结果返回给main(),而后者将报告结果。调和平均数是倒数平均值的倒数,计算公式如下。
               调和平均数 = 2.0xy/(x+y)

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 函数声明
double calculate_harmonic(int n1, int n2); // 计算两个数的调和平均数

int main()
{
	int n1, n2;  // 存储输入的两个数
	// 输入
	cout << "Please enter two number: ";
	cin >> n1 >> n2;
	while (n1 != 0 && n2 != 0)  // 有一个数为0就停止输入
	{
		// 计算
		double harmonic = calculate_harmonic(n1, n2);
		// 显示
		cout << "Harmonic: " << harmonic << endl;
		// 下一组数
		cout << "Please enter the next two number: ";
		cin >> n1 >> n2;
	}

	return 0;
}

// 函数定义
double calculate_harmonic(int n1, int n2) // 计算两个数的调和平均数
{
	return 2.0 * n1 * n2 / (n1 + n2);
}

2. 编写一个程序,要求用户输入最多10个高尔夫成绩,并将其存储在一个数组中。程序允许用户提早结束输入,并在一行上显示所有成绩,然后报告平均成绩。请使用三个数组处理函数,来分别输入、显示和计算平均成绩。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 函数声明
int input(double scores[]);  // 输入高尔夫成绩
double calc_average(const double scores[], const int size);  // 计算平均成绩
void print(const double scores[], const int size);  // 打印成绩

int main()
{
	// 输入成绩并存储成绩数量
	double scores[10];
	int size = input(scores);
	// 计算平均值成绩
	double average = calc_average(scores, size);
	// 按格式输出
	cout << "Scores: ";
	print(scores, size);
	cout << "Average: " << average << endl;

	return 0;
}

// 函数定义
int input(double scores[])  // 输入高尔夫成绩
{
	cout << "Please enter your golf score(-1 to quit):" << endl;
	int num = 0;  // 记录输入成绩数量
	for (int i = 0; i < 10; ++i)
	{
		cout << i + 1 << ": ";
		cin >> scores[i];
		// 输入-1结束输入
		if (scores[i] == -1)
			break;

		// 计数
		++num;
	}

	return num;
}
double calc_average(const double scores[], const int size)  // 计算平均成绩
{
	double sum = 0;  // 存储总成绩
	// 计算总成绩
	for (int i = 0; i < size; ++i)
	{
		sum += scores[i];
	}
	// 计算平均成绩并返回
	double average = sum / size;
	
	return average;
}
void print(const double scores[], const int size)  // 打印成绩
{
	// 遍历数组,打印成绩
	for (int i = 0; i < size; ++i)
	{
		cout << scores[i] << " ";
	}
	cout << endl;
}

3. 下面是一个结构体声明。

// box结构声明
struct box{
	char maker[40];
	float height;
	float width;
	float length;
	float volume;
}

a. 编写一个函数,按值传递box结构体,并显示每个成员的值。
b. 编写一个函数,传递box结构体的地址,并将volume成员设置为其他三位长度的乘积。
c. 编写一个使用这两个函数的简单程序。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// box结构声明
struct box
{
	char maker[40];
	float height;  // 高
	float width;  // 宽
	float length;  // 长
	float volume;  // 体积
};
// 函数声明
void print_box(box b);  // 打印box结构体
void calc_volume(box* pb);  // 计算box的成员volume

int main()
{
	// 创建一个box结构变量并初始化
	box box1 = { "cat", 5, 5, 5 };  // volume未初始化,编译器设置为0
	// 计算volume
	calc_volume(&box1);
	// 打印
	print_box(box1);

	return 0;
}

// 函数定义
void print_box(box b)  // 打印box结构体
{
	cout << "Maker: " << b.maker << endl;
	cout << "Height: " << b.height << endl;
	cout << "Width: " << b.width << endl;
	cout << "Length: " << b.length << endl;
	cout << "Volume: " << b.volume << endl;
}
void calc_volume(box* pb)  // 计算box的成员volume
{
	pb->volume = pb->height * pb->width * pb->length;
}

4. 许多州的彩票发行机构使用如程序清单7.4所示的简单彩票玩法的变体。…。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 函数声明
long double probability(double total, double special, double choice);  // 计算中彩票头奖的概率

int main()
{
	double total, special, choice;  // 存储总个数,特殊个数,选择个数
	// 输入
	cout << "请输入总号码个数(输入-1停止): ";
	cin >> total;
	while (total != -1)
	{
		cout << "请输入特殊号码的区间为1-多少: ";
		cin >> special;
		cout << "请输入选择域号码的个数: ";
		cin >> choice;
		cout << "中彩票头奖的概率为: ";
		long double proba = 1 / probability(total, special, choice);
		cout << proba << endl;
	}
	
	// 结束
	cout << "Done." << endl;

	return 0;
}

// 函数声明
long double probability(double total, double special, double choice)  // 计算中彩票头奖的概率
{
	// 计算概率
	long double proba = 1.0L;
	for (long double i = choice, j = total; i > 0; --i, --j)
	{
		proba *= j / i;
	}

	return proba * special;
}

5. 定义一个递归函数,该函数接受一个整数参数,并返回该参数的阶乘。…。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 函数声明
long long factorial(int n);  // 返回n的阶乘

int main()
{
	// 输入
	int n;
	cout << "Please enter a number(-1 to quit): ";
	cin >> n;
	while (n != -1)
	{
		// 计算并输出
		cout << "It's factorial: " << factorial(n) << endl;
		// 下一个数
		cout << "The next number: ";
		cin >> n;
	}

	return 0;
}

// 函数声明
long long factorial(int n)  // 返回n的阶乘
{
	// 递归
	if (n == 1 || n == 0)  // 0和1的阶乘为1
		return 1;
	return n * factorial(n - 1);
}

6. 编写一个程序,它使用下列函数。
a. Fill_array()以一个double类型数组的名称和长度作为参数。它提示用户输入double值,并将这些值存储到数组中。当数组被填满或者用户输入非数字时,输入将停止,并返回实际输入了多少个数字。
b. Show_array()以一个double型数组的名称和长度作为参数,并显示该数组的内容。
c. Reverse_array()以一个double型数组的名称和长度作为参数,并将存储在数组中的值顺序反转。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 符号常量声明
const int SIZE = 10;

// 函数声明
int Fill_array(double arr[], const int size);  // 填充数组,返回实际填充个数
void Show_array(const double arr[], const int length);  // 显示数组
void Reverse_array(double arr[], const int length);  // 将数组反转

int main()
{
	// 创建数组
	double arr[SIZE] = { 0 };
	// 输入
	int length = Fill_array(arr, SIZE);
	// 显示数组
	Show_array(arr, length);
	// 反转数组
	Reverse_array(arr + 1, length - 2);  // 不反转数组第一位和最后一位
	// 显示数组
	Show_array(arr, length);


	return 0;
}

// 函数定义
int Fill_array(double arr[], const int size)  // 填充数组,返回实际填充个数
{
	double input;  // 存储输入的数
	int length = 0;  // 存储输入个数
	cout << "Enter a number: ";
	while (cin >> input && length < size)  // 输入非数字或者数组满了停止输入
	{
		// 存储并计数
		arr[length] = input;
		++length;
		// 输入下一个数
		cout << "Next number: ";
	}
	// 返回输入个数
	return length;
}
void Show_array(const double arr[], const int length)  // 显示数组
{
	for (int i = 0; i < length; ++i)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}
void Reverse_array(double arr[], const int length)  // 将数组反转
{
	// 记录数组首尾下标
	int left = 0;
	int right = length - 1;
	while (left < right)
	{
		// 交换
		double temp = arr[right];
		arr[right] = arr[left];
		arr[left] = temp;
		// 下一组
		++left;
		--right;
	}
}

7. 修改程序清单7.7中的三个数组处理函数,使之使用两个指针来表示区间。…。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 符号常量声明
const int Max = 5;

// 函数声明
double* fill_array(double* begin, const int limit);  // 填充数组
void show_array(double* begin, double* end);  // 打印数组
void revalue(double* begin, double* end, const double n);  // 数组每个元素乘以n

int main()
{
	// 创建数组
	double arr[Max];

	// 填充并接收数组结尾地址
	double* end = fill_array(arr, Max);
	// 打印数组
	show_array(arr, end);
	// 数组每个元素乘以n
	double n;
	cout << "请输入数组缩放因子: ";
	cin >> n;
	revalue(arr, end, n);
	// 打印
	cout << "缩放后: " << endl;
	show_array(arr, end);

	cout << "Done." << endl;

	return 0;
}

// 函数定义
double* fill_array(double* begin, const int limit)  // 填充数组
{
	double input;  // 存储输入
	int i = 0;  // 记录数组的长度
	for (i = 0; i < limit; ++i)
	{
		// 输入
		cout << "Enter value #" << i + 1 << ": ";
		cin >> input;
		if (!cin)  // 非法输入
		{
			cin.clear();
			while (cin.get() != '\n')
				continue;
			cout << "Bad input; input process terminated." << endl;
		}
		else if (input < 0)
			break;
		// 存储
		*(begin + i) = input;
	}
	return begin + i;
}
void show_array(double* begin, double* end)  // 打印数组
{
	while (begin != end)
	{
		cout << *begin << " ";
		++begin;
	}
	cout << endl;
}
void revalue(double* begin, double* end, const double n)  // 数组每个元素乘以n
{
	while (begin != end)
	{
		*begin *= n;
		++begin;
	}
}

8. 在不使用array类的情况下完成程序清单7.15所做的工作。编写两个这样的版本。
a. 使用const char数组存储表示季度名称的字符串,并使用double型数组存储开支。
b. 使用const char
数组存储表示季度名称的字符串,并使用一个结构体,该结构体有一个成员,即一个用于存储开支的double数组。这种类的设计与使用array类的设计基本类似。

a. 部分

// 头文件
#include <iostream>

// 标准名称空间
using namespace std;

// 符号常量声明
const int Seasons = 4;

const char* pseasons[4] = { "Spring", "Summer", "Fall", "Winter" };

// 函数声明
void fill(double arr[], int size);  // 填充数组
void show(double arr[], int size);  // 显示数组

int main()
{
	double arr[Seasons];
	// 填充数组
	fill(arr, Seasons);
	// 显示数组
	show(arr, Seasons);

	return 0;
}

// 函数定义
void fill(double arr[], int size)  // 填充数组
{
	for (int i = 0; i < size; ++i)
	{
		cout << "Enter " << pseasons[i] << " expenses: ";
		cin >> arr[i];
	}
}
void show(double arr[], int size)  // 显示数组
{
	double total = 0;  // 存储一年的
	for (int i = 0; i < size; ++i)
	{
		// 打印每季度
		cout << pseasons[i] << ": $" << arr[i] << endl;
		// 计算一年
		total += arr[i];
	}
	// 打印一年
	cout << "Total Expenses: $" << total << endl;
}

b. 部分

// 头文件
#include <iostream>

// 标准名称空间
using namespace std;

// 符号常量声明
const int Season = 4;
const char* Sname[Season] = { "Spring", "Summer", "Fall", "Winter" };

// Spend结构声明
struct Spend
{
	double money[Season];
};

// 函数声明
void fill(double arr[], const int size);  // 填充数组
void show(const double arr[], const int size);  // 显示数组

int main()
{
	// 创建Spend结构变量
	Spend expenses;
	// 填充数组
	fill(expenses.money, Season);
	// 显示数组
	show(expenses.money, Season);

	return 0;
}

// 函数声明
void fill(double arr[], const int size)  // 填充数组
{
	for (int i = 0; i < size; ++i)
	{
		cout << "Enter " << Sname[i] << " expenses: ";
		cin >> arr[i];
	}
}
void show(const double arr[], const int size)  // 显示数组
{
	cout << endl;
	cout << "Expenses:";
	cout << endl;
	double total = 0;  // 存储一年总花费
	for (int i = 0; i < size; ++i)
	{
		// 显示每个季度
		cout << Sname[i] << ":$ " << arr[i] << endl;
		// 计算一年总花费
		total += arr[i];
	}
	// 显示一年
	cout << "Total Expenses:$ " << total << endl;
}

9. 请编写处理数组和结构体的函数。下面是程序的框架,请提供其中描述的函数,以完成该程序。

// 头文件
#include <iostream>

// 标准名称空间std
using namespace std;

// 符号常量声明
const int SLEN = 30;

// student结构声明
struct student
{
	char fullname[SLEN];  // 全名
	char hobby[SLEN];  // 爱好
	int ooplevel;
};

// 函数声明
int getinfo(student pa[], int n);  // 填充student数组
void display1(student st);  // 值传递打印
void display2(const student* ps);  // 地址传递打印
void display3(const student pa[], int n);  // 数组传递打印

int main()
{
	// 输入学生人数
	cout << "Enter the 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);
	cout << endl;
	// 以两种传参方式打印每个学生的信息
	for (int i = 0; i < entered; ++i)
	{
		display1(ptr_stu[i]);  // 值传递
		cout << endl;
		display2(&ptr_stu[i]);  // 传递地址
		cout << endl;
	}
	// 打印整个数组
	display3(ptr_stu, entered);
	// 释放申请空间
	delete[]ptr_stu;
	
	cout << "Done." << endl;

	return 0;
}

// 函数定义
int getinfo(student pa[], int n)  // 填充student数组
{
	int i;  // 记录输入个数
	cout << "请输入学生的信息(输入空行结束):" << endl;
	for (i = 0; i < n; ++i)
	{
		cout << "第" << i + 1 << "位:" << endl;
		cout << "姓名: ";
		cin.getline(pa[i].fullname, SLEN);
		// 输入空行
		if (!cin)
		{
			// 重置输入
			cin.clear();
			// 清除无效输入
			while (cin.get() != '\n')
				continue;
			// 结束输入
			cout << "输入结束" << endl;
			break;
		}
		cout << "爱好: ";
		cin.getline(pa[i].hobby, SLEN);
		cout << "ooplevel: ";
		cin >> pa[i].ooplevel;
		cin.get();  // 读取换行符
	}
	// 返回输入个数
	return i;
}
void display1(student st)  // 值传递打印
{
	cout << "姓名: " << st.fullname << endl;
	cout << "爱好: " << st.hobby << endl;
	cout << "ooplevel: " << st.ooplevel << endl;
}
void display2(const student* ps)  // 地址传递打印
{
	cout << "姓名: " << ps->fullname << endl;
	cout << "爱好: " << ps->hobby << endl;
	cout << "ooplevel: " << ps->ooplevel << endl;
}
void display3(const student pa[], int n)  // 数组传递打印
{
	for (int i = 0; i < n; ++i)
	{
		cout << "第" << i + 1 << "位同学" << endl;
		cout << "姓名: " << pa[i].fullname << endl;
		cout << "爱好: " << pa[i].hobby << endl;
		cout << "ooplevel: " << pa[i].ooplevel << endl;
		cout << endl;
	}
}

10. 设计一个名为calculate()的函数,它接受两个double值和一个指向函数的指针,而被指向的函数接受两个double参数,并返回一个double值。…。

// 头文件
#include <iostream>

// 标准名称空间
using namespace std;

// 函数声明
double calculate(double d1, double d2, double (*pf)(double, double));  // 通过函数指针调用函数计算
double add(double d1, double d2);  // 加法
double mul(double d1, double d2);  // 乘法

int main()
{
	int n1, n2;  // 存储输入的两个数
	// 输入
	cout << "请输入两个数(输入q停止): ";
	while (cin >> n1 >> n2)
	{
		// 通过函数指针调用两个函数计算并输出
		cout << "相加: " << calculate(n1, n2, add) << endl;
		cout << "相乘: " << calculate(n1, n2, mul) << endl;
		// 下一组
		cout << "请输入两个数(输入q停止): ";
	}

	return 0;
}

// 函数定义
double calculate(double d1, double d2, double (*pf)(double, double))  // 通过函数指针调用函数计算
{
	return pf(d1, d2);
}
double add(double d1, double d2)  // 加法
{
	return d1 + d2;
}
double mul(double d1, double d2)  // 乘法
{
	return d1 * d2;
}
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值