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

一、复习题

1. 对于下面的情况,应使用哪种存储方案?
a. homer 是函数的形参。
b. secret 变量由两个文件共享。
c. topsecret 变量由一个文件中的所有函数共享,但对于其他文件来说是隐藏的。
d. beencalled 记录包含它的函数被调用的次数

答:
a. 自动存储持续性
b. 静态存储持续性(具有外部链接性)
c. 静态存储持续型(具有内部链接性)
d. 静态存储持续性(没有链接性)

2. using声明和using编译指令之间有何区别?

答:使用using声明只声明名称空间的一个名称,当有局部名称与名称空间的名称冲突时,编译器会报错。而使用using编译指令则会声明名称空间的所有名称,当有局部名称与名称空间的名称冲突时,编译器不会报错,而是隐藏名称空间中的名称。在局部范围(函数中)使用上述两种方法,声明的名称局部可用,在全局范围(文件/所有函数外)声明使用,声明的名称全局可用。

3. 重新编写下面的代码,使其不使用using声明和using编译指令。

#include <iostream>
using namespace std;
int main()
{
	double x;
	cout << "Enter value: ";
	while (! (cin >> x) )
	{
		cout << "Bad input. Please enter a number: ";
		cin.clear();
		while (cin.get() != '\n')
			continue;
	}
	cout << "Value = " << x << endl;
	return 0;
}

答:不使用using声明和using编译指令,那就只能使用名称加上作用域解析运算符。

// 头文件
#include <iostream>

int main()
{
	double x;
	std::cout << "Enter value: ";
	while (! (std::cin >> x) )
	{
		std::cout << "Bad input. Please enter a number: ";
		std::cin.clear();
		while (std::cin.get() != '\n')
			continue;
	}
	std::cout << "Value = " << x << std::endl;
	return 0;
}

4. 重新编写下面的代码,使之使用using声明,而不是using编译指令。

#include <iostream>
using namespace std;
int main()
{
	double x;
	cout << "Enter value: ";
	while (! (cin >> x) )
	{
		cout << "Bad input. Please enter a number: ";
		cin.clear();
		while (cin.get() != '\n')
			continue;
	}
	cout << "Value = " << x << endl;
	return 0;
}

答:使用using编译指令需要把使用的名称一一列出。

// 头文件
#include <iostream>

int main()
{
	// using声明
	using std::cout;
	using std::cin;
	using std::endl;
	
	double x;
	cout << "Enter value: ";
	while (! (cin >> x) )
	{
		cout << "Bad input. Please enter a number: ";
		cin.clear();
		while (cin.get() != '\n')
			continue;
	}
	cout << "Value = " << x << endl;
	return 0;
}

5. 在一个文件中调用average(3, 6)函数时,它返回两个int参数的int平均值,在同一个程序的另一个文件中调用时,它返回两个int参数的double平均值。应该如何实现?

答:首先,两个函数的参数列表的参数数量、类型和顺序均相同,只有返回值不同,所以不能使用函数重载。可以利用本章学习的关键字static修饰函数(函数声明和定义都需要),把函数的外部链接属性变成内部链接属性,函数只能在它所在的函数使用,这样两个函数就不会冲突。还可以创建两个名称空间,把两个函数分别放进去,使用哪一个就表明是哪一个名称空间的函数。

6. 下面的程序由两个文件组成,该程序显示什么内容?

// file1.cpp
#include <iostream>
using namespace std;
void other();
void another();
int x = 10;
int y;

int main()
{
	cout << x << endl;
	{
		int x = 4;
		cout << x << endl;
		cout << y << endl;
	}
	other();
	another();
	return 0;
}

void other()
{
	int y = 1;
	cout << "Ohter: " << x << ", " << y << endl;
}
// file 2.cpp
#include <iostream>
using namespace std;
extern int x;
namespace
{
	int y = -4;
}
void another()
{
	cout << "another(): " << x << ", " << y << endl;
}

答:在file1.cpp文件中,在main()函数中先输出全局变量x,然后代码块中局部变量x隐藏了全局变量x,全局变量y没有初始化,编译器自动设置为0,所以输出的x和y为4和0。而other函数中的局部变量y隐藏了全局变量y,输出的x和y为10和1。最后的another()函数的定义在file2.cpp文件中,该文件声明了全局变量x来自其他文件(也就是file1.cppz中),而y使用的是为命名的名称空间中定义的变量y(相当于static int y = -4,静态存储持续型,内部链接性),所以输出的x和y为10和-4。

程序运行结果如下:
在这里插入图片描述

7. 下面的代码将显示什么内容?

#include <iostream>
using namespace std;
void other();
namespace n1
{
	int x = 1;
}

namespace n2
{
	int x = 2;
}

int main()
{
	using namespace n1;
	cout << x << endl;
	{
		int x = 4;
		cout << x << ", " << n1::x << ", " << n2::x << endl;
	}
	using n2::x;
	cout << x << endl;
	other();
	return 0;
}

void other()
{
	using namespace n2;
	cout << x << endl;
	{
		int x = 4;
		cout << x << ", " << n1::x << ", " << n2::x << endl;
	}
	using n2::x;
	cout << x << endl;
}

答:在main()函数中,using编译指令声明了n2名称空间的所有内容,先输出x的值为1,然后代码块中的局部变量隐藏了n2空间中的x,显示x的值为4,然后显示指出x的来源名称空间,显示两个x的值为1和2,出代码块之后,using声明了n2名称空间中的x,隐藏了n1名称空间中的x,显示x的值为2。最后进入other()函数,和main()函数中的情况类似,这里就不再赘述。

程序运行结果如下:
在这里插入图片描述

二、编程练习

1. 下面是一个头文件:

// golf.h-forgr9-1.cpp

const int Len = 40;
struct golf
{
	char fullname[Len];
	int handicap;
};
// 使用非交互版本:
// 使用传递给函数的参数值,函数为提供的名称和handicap设置golf结构体
void setgolf(golf& g, const char* name, int hc);

// 交互式版本
// 函数申请用户的名称和handicap
// 设置输入的g的个数
// 如果输入名称,返回1;如果名称是空字符串,返回0
int setgolf(golf& g);

// 函数重置handicap为新的值
void handicap(golf& g, int hc);

// 函数显示golf结构体的信息
void showgolf(const golf& g);

注意,setgolf()被重载,可以这样使用其第一个版本:
golf ann;
setgolf(andy);

答:
test.cpp



// 头文件
#include "golf.h"

// using声明
using std::cout;
using std::endl;
using std::cin;

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

int main()
{
	// 非交互版本测试
	golf g1;
	setgolf(g1, "原神", 888);
	showgolf(g1);
	cout << endl;
	// 交互版本测试
	golf golfs[size];
	int i = 0;
	do
	{
		// 正确输入则显示
		if (setgolf(golfs[i]))
		{
			cin.get();  // 丢弃输入handicap遗留的换行符,也可以直接在setgolf()函数中丢弃
			showgolf(golfs[i]);
		}
		else
		{
			break;
		}

	} while (1);  // 输入姓名不为空行

	return 0;
}

golf.cpp

#define _CRT_SECURE_NO_WARNINGS

// 头文件
#include "golf.h"

// using声明
using std::cin;
using std::cout;
using std::endl;

// 函数定义

// 使用非交互版本:
// 使用传递给函数的参数值,函数为提供的名称和handicap设置golf结构体
void setgolf(golf& g, const char* name, int hc)
{
	strcpy(g.fullname, name);
	g.handicap = hc;
}

// 交互式版本
// 函数申请用户的名称和handicap
// 设置输入的g的个数
// 如果输入名称,返回1;如果名称是空字符串,返回0
int setgolf(golf& g)
{
	// 输入名称
	char name[Len];
	cout << "Please enter the name: ";
	cin.getline(name, Len);
	// 如果输入为空行
	if (name[0] == '\0')
	{
		cout << "Enter blank line." << endl;
		// 重置输入且清空无效输入
		cin.clear();
		while (cin.get() != '\n')
			continue;

		return 0;
	}
	// 正确输入名称
	strcpy(g.fullname, name);
	static int num_golf = 0;  // 输入g的个数
	++num_golf;
	// 输入handicap
	cout << "Please enter the handicap: ";
	while (!(cin >> g.handicap))
	{
		// 重置输入
		cin.clear();
		// 清除错误输入
		while (cin.get() != '\n') continue;
		// 重新输入
		cout << "Please enter the handicap: ";
	}
	return 1;
}

// 函数重置handicap为新的值
void handicap(golf& g, int hc)
{
	g.handicap = hc;
}

// 函数显示golf结构体的信息
void showgolf(const golf& g)
{
	cout << "Name: " << g.fullname << endl;
	cout << "Handicap: " << g.handicap << endl;
}

2. 修改程序清单9.9,要求用string对象代替字符数组。这样,该程序将不再需要判断输入的字符串是否过长,同时可以将输入字符串同字符串""进行比较,以判断输入内容是否为空行。

程序清单9.9如下:

// static.cpp —— 使用静态的局部变量
#include <iostream>
// 常量
const int ArSize = 10;

// 函数原型
void strcount(const char* str);

int main()
{
	using namespace std;
	char input[ArSize];
	char next;

	cout << "Enter a line:\n";
	cin.get(input, ArSize);
	while (cin)
	{
		cin.get(next);
		while (next != '\n')
			cin.get(next);
		strcount(input);
		cout << "Enter next line (empty line to quit):\n";
		cin.get(input, ArSize);
	}
	cout << "Bye\n";
	return 0;
}

void strcount(const char* str)
{
	using namespace std;
	static int total = 0;
	int count = 0;
	cout << "\"" << str << "\" contains ";
	while (*str++)
		++count;
	total += count;
	cout << count << "characters\n";
	cout << total << "characters total\n";
}	

答:



// 头文件
#include <iostream>
#include <string>

// using声明
using std::cout;
using std::cin;
using std::endl;
using std::string;

// 函数声明
void strcount(const string& str);

int main()
{
	// 输入
	string str;
	cout << "Enter a line:\n";
	getline(cin, str);

	while (str != "")
	{
		strcount(str);
		cout << "Enter next line (empty line to quit):\n";
		getline(cin, str);
	}

	cout << "Bye.\n";


	return 0;
}

// 函数定义
void strcount(const string& str)
{
	static int total = 0;  // 记录输入字符串的总字符数
	int count = (int)str.size();  // 当前字符串的字符数

	cout << "\"" << str << "\" contains ";
	total += count;
	cout << count << "characters\n";
	cout << total << "characters total\n";
}

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

// chaff结构声明
struct chaff
{
	char dross[20];
	int slag;
};

编写一个程序,使用定位运算符new将一个包含两个这种结构体的数组放在一个缓冲区中。然后为结构体成员赋值(对于char数组使用strcpy()),并使用一个循环来显示内容。一种方法是像程序清单9.10那样以一个静态数组作为缓冲区;另一种方法是使用常规new运算符来分配空间。

答:



// 头文件
#include <iostream>
#include <new>  // 定位运算符new

// using声明
using std::cin;
using std::cout;
using std::endl;


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

// staff结构声明
struct staff
{
	char dross[20];
	int slag;
};

// 函数声明
void set_staff(staff& s);  // 设置staff
void show_staff(const staff& s);  // 显示staff

int main()
{
	// 申请空间
	char* buff = new char[SIZE];
	// 定位空间
	staff* ps = new(buff) staff[2];  // 定位到buff这块空间的首地址
	// 输出检验是否定位成功
	cout << "buff: " << (int*)buff << endl;  // 不强制类型转换会被当作字符串输出
	cout << "ps  : " << ps << endl;
	// 为结构成员赋值
	for (int i = 0; i < 2; ++i)
	{
		set_staff(ps[i]);
	}
	// 显示
	for (int i = 0; i < 2; ++i)
	{
		show_staff(ps[i]);
	}


	// 释放申请空间
	free(buff);
	
	return 0;
}

// 函数定义
void set_staff(staff& s)  // 设置staff
{
	cout << "Enter the dross: ";
	cin.getline(s.dross, 20);
	// 下面这个while循环有小瑕疵,但是运行没问题,只供参考
	while (!strcmp(s.dross, ""))
	{
		cin.clear();
		while (cin.get() != '\n') continue;
		cout << "Error input! Enter the dross: ";
		cin.getline(s.dross, 20);
	}
	cout << "Enter the slag: ";
	while (!(cin >> s.slag))
	{
		cin.clear();
		while (cin.get() != '\n') continue;
		cout << "Error intput! Enter the slag: ";
	}
	cin.get();  // 丢弃换行符
}
void show_staff(const staff& s)  // 显示staff
{
	cout << endl;
	cout << "Dross: " << s.dross << endl;
	cout << "Slag: " << s.slag << endl;
}

4. 请基于下面这个名称空间编写一个由3个文件组成的程序。

// 头文件
#include <iostream>

// 名称空间
namespace SALES
{
	const int QUARTERS = 4;
	struct Sales
	{
		double sales[QUARTERS];
		double average;
		double max;
		double min;
	};

	// 把数组ar中的项(最多4项)复制到s
	// 的sales成员中,计算s,存储转入的项
	// 的平均值,最大值和最小值
	// 如果sales有其他元素,把它们设置为0
	void setSales(Sales& s, const double ar[], int n);

	// 收集4个季度的销量,在s的sales成员中存储它们,并计算均值、最大值和最小值
	void setSales(Sales& s);

	// 显示结构体的所有信息
	void showSales(const Sales& s);

}

答:
main()函数文件:



// 头文件
#include "SALES.h"

// using 编译指令
using namespace SALES;
using std::cout;
using std::endl;

int main()
{
	// 交互式版本
	Sales s1;
	setSales(s1);
	showSales(s1);
	cout << endl;
	// 非交互版本
	Sales s2;
	double sales[3] = { 10, 20, 30 };
	setSales(s2, sales, 3);
	showSales(s2);


	return 0;
}

SALES文件:

// 头文件
#include "SALES.h"

// using 编译指令
using namespace SALES;

// using 声明
using std::cout;
using std::cin;
using std::endl;

// 把数组ar中的项(最多4项)复制到s
	// 的sales成员中,计算s,存储转入的项
	// 的平均值,最大值和最小值
	// 如果sales有其他元素,把它们设置为0
void SALES::setSales(Sales& s, const double ar[], int n)
{
	double sum = 0;
	double max = ar[0];
	double min = ar[0];
	// 设置sales值,找出最大值、最小值、计算总值
	for (int i = 0; i < 4; ++i)
	{
		if (i < n)
			s.sales[i] = ar[i];
		else
			s.sales[i] = 0;
		
		if (s.sales[i] > max)
			max = s.sales[i];
		if (s.sales[i] < min)
			min = s.sales[i];
		sum += s.sales[i];
	}
	s.max = max;
	s.min = min;
	s.average = sum / 4;
}

// 收集4个季度的销量,在s的sales成员中存储它们,并计算均值、最大值和最小值
void SALES::setSales(Sales& s)
{
	cout << "Please enter 4 sales: ";
	for (int i = 0; i < 4; ++i)
	{
		while (!(cin >> s.sales[i]))
		{
			cin.clear();
			while (cin.get() != '\n') continue;
			cout << "Error input! Please re-enter:";
		}
	}
	double max = s.sales[0];
	double min = s.sales[0];
	double sum = s.sales[0];
	for (int i = 1; i < 4; ++i)
	{
		if (s.sales[i] > max)
			max = s.sales[i];
		if (s.sales[i] < min)
			min = s.sales[i];

		sum += s.sales[i];
	}
	s.max = max;
	s.min = min;
	s.average = sum / 4;
}

// 显示结构体的所有信息
void SALES::showSales(const Sales& s)
{
	cout << "sales:\n";
	for (int i = 0; i < 4; ++i)
	{
		cout << "No." << i +1 << ": " << s.sales[i] << endl;
	}
	cout << "max: " << s.max << endl;
	cout << "min: " << s.min << endl;
	cout << "average: " << s.average << endl;
}
  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值