C++-Primer-Plus 习题解答(第十六章-string类和标准模板库)

文章介绍了C++中的字符串操作,包括回文检测函数、处理大小写、空格和标点、使用getline()读取输入、tolower()转换字符以及容器如vector和set的使用。还涉及类模板、迭代器和随机打乱元素等技术。
摘要由CSDN通过智能技术生成

题目:16.1

回文指的是顺读和逆读都一样的字符串。例如,“tot”和“otto”都 是简短的回文。编写一个程序,让用户输入字符串,并将字符串引用传 递给一个bool函数。如果字符串是回文,该函数将返回true,否则返回 false。此时,不要担心诸如大小写、空格和标点符号这些复杂的问题。 即这个简单的版本将拒绝“Otto”和“Madam,I'm Adam”。请查看附录F中 的字符串方法列表,以简化这项任务。

bool Func(string ch)
{
	int size = ch.size();
	string::iterator first = ch.begin();
	string::iterator second = ch.end();//这是在最末尾后面了
	second--;
	for (int i = 0; i < size / 2; i++)
	{
		cout << "first=" << *first << endl;
		cout << "second=" << *second << endl;
		if (*first != *second)
		{
			return false;
		}
		first++;
		second--;
	}
	return true;
}

 问题1:string是类模板吗?

string是C++标准库中的一个类模板。在C++中,string类模板用于表示字符串,提供了一系列操作字符串的方法。通过使用string类模板,可以方便地操作字符串,而不需要手动管理内存或处理字符串的长度等问题。因此,string类模板是C++中非常常用的类之一。

题目:16.2 

题: 与编程练习1中给出的问题相同,但要考虑诸如大小写、空格和 标点符号这样的复杂问题。即“Madam,I'm Adam”将作为回文来测试。 例如,测试函数可能会将字符串缩略为“madamimadam”,然后测试倒过 来是否一样。不要忘了有用的cctype库,您可能从中找到几个有用的 STL函数,尽管不一定非要使用它们。

bool Func1(string ch)
{
    int size = ch.size();
    string::iterator first = ch.begin();
    string::iterator second = ch.end();//这是在最末尾后面了
    second--;
    for (int i = 0; i < size / 2; i++)
    {
        cout << "first=" << *first << endl;
        cout << "second=" << *second << endl;
        if (*first != *second)
        {
            return false;
        }
        first++;
        second--;
    }
    return true;
}
bool Func2(string ch)
{
    //需求:判断有符号的一串数字是否是回文数,且要将其全部转为小写字母
    string::iterator it = ch.begin();
    for (; it != ch.end(); )
    {
        if (!isalpha(*it))
        {
            //如果不是字母则将其擦除
            it=ch.erase(it);//这种擦除,ch中所分配的内存是会减少的
            continue;
        }
        else
        {
            //是字母,则转化为小写字母
            *it = tolower(*it);
            it++;
        }
    }
    //判断是否是回文数
   return Func1(ch);
    
}

问题二:getline()的详细用法

getline(cin, input) 是一个 C++ 的标准库函数,用于从标准输入流 cin 中读取一行输入,并将其存储到字符串变量 input 中。

具体方法如下:

  1. getline() 函数接受两个参数,第一个参数是输入流对象,通常是 cin,第二个参数是一个字符串变量,用于存储读取的输入。

  2. 当程序执行到 getline(cin, input) 时,程序会等待用户输入一行字符并按下回车键。

  3. 一旦用户按下回车键,getline() 函数会将用户输入的整行文本读取并存储到 input 字符串变量中。

  4. 如果用户输入的文本长度超过了 input 字符串变量的最大长度,getline() 函数会截断文本并存储到 input 中。

  5. getline() 函数会自动忽略换行符,并将换行符从输入流中移除,因此 input 中不会包含换行符。

  6. getline() 函数会返回一个 istream 对象,可以用来检查输入流的状态。如果输入流正常操作,返回值为 cin,如果发生错误,返回值为 NULL

总之,getline(cin, input) 方法是一个方便的方式来从标准输入流中读取一行输入,并存储到字符串变量中。

问题三:tolower()用法 

 c++ tolower()函数用于将字符转换为小写字母。它接受一个字符作为参数,并返回相应的小写字母字符。

 示例代码:

#include <iostream>
#include <cctype>

int main() {
    char ch = 'A';
    char lowerCh = tolower(ch);

    std::cout << "原始字符: " << ch << std::endl;
    std::cout << "转换为小写字母: " << lowerCh << std::endl;

    return 0;
}

 题目:16.4

题: 编写一个具有老式风格接口的函数,其原型如下:

int reduce(long arr[], int n);

实参应是数组名和数组中的元素个数。该函数对数组进行排序,删 除重复的值,返回缩减后数组中的元素数目。请使用STL函数编写该函 数(如果决定使用通用的unique( )函数,请注意它将返回结果区间的结 尾)。使用一个小程序测试该函数。
//方法1:
int reduce1(long arr[], int n)
{
	//决定使用使用set容器,原因:它不存放重复的元素
	set<long> ans;
	for (int i = 0; i < n; i++)
	{
		ans.insert(arr[i]);
	}
	cout << "ans.size()=" << ans.size() << endl;
	set<long>::iterator it = ans.begin();
	for (; it!=ans.end(); it++)
	{
		cout << *it;
	}
	return ans.size();
}

//方法2:
int reduce2(long arr[], int n)
{
	//unique():功能是去除相邻的重复元素(注意一定是相邻元素,且只保留一个)
	//所以使用前需要对数组进行排序
	
	//对arr进行排序
	//arr+n 表示最后一个元素后面一个位置
	sort(arr, arr + n);
	vector<long>ans;
	
	for (int i = 0; i < n; i++)
	{
		ans.push_back(arr[i]);
	}
	//auto自动识别数据类型
	auto it=unique(ans.begin(), ans.end());

	//取出末尾重复的数
	ans.erase(it, ans.end());
	vector<long>::iterator ret = ans.begin();
	for (ret; ret != ans.end(); ret++)
	{
		cout << *ret << " ";
	}

	cout << endl;
	return 0;
}

 题目:16.5

题: 问题与编程练习4相同,但要编写一个模板函数:

template <class T>
int reduce(T arr[], int n)
在一个使用long实例和string实例的小程序中测试该函数。

template <class T>
int reduce(T arr[], int n)
{
	//使用unique()方法

	//先排序
	sort(arr, arr + n);
	
	//unique函数返回一个指向数组中去除重复元素后的末尾位置的迭代器
	vector<T>ans;
	for (int i = 0; i < n; i++)
	{
		ans.push_back(arr[i]);
	}
	typename vector<T>::iterator it = unique(ans.begin(), ans.end());

	//去除相同的末尾元素
	typename vector<T>::iterator ret = ans.begin();
	ans.erase(it, ans.end());
	for (ret; ret != ans.end(); ret++)
	{
		cout << *ret << " ";
	}

	
	cout << endl;
	return 0;
}

 问题一:为什么在使用类模板时,无法直接使用vector<T>::iterator it 创建一个迭代器

 在C++中,vector<T>::iteratorstd::vector模板类的一个嵌套类型,表示std::vector中的迭代器类型。当使用类模板时,例如std::vector<int>,迭代器类型std::vector<int>::iterator是由编译器根据std::vector<int>的具体类型推导出来的。

因此,在使用类模板时,无法直接使用vector<T>::iterator来创建迭代器,因为T是一个模板参数,需要具体化为一个实际的类型后才能确定vector<T>::iterator的具体类型。您需要使用typename std::vector<T>::iterator来指定迭代器类型,其中typename表示std::vector<T>::iterator是一个类型,而不是一个静态成员。

题目:16.7  

题: 彩票卡是一个常见的游戏。卡片上是带编号的圆点,其中一些 圆点被随机选中。编写一个lotto( )函数,它接受两个参数。第一个参数 是彩票卡上圆点的个数,第二个参数是随机选择的圆点个数。该函数返 回一个vector对象,其中包含(按排列后的顺序)随机选择的号 码。例如,可以这样使用该函数:

vector<int> winners;
winners = Lotto(51, 6);

这样将把一个矢量赋给winner,该矢量包含1~51中随机选定的6个 数字。注意,仅仅使用rand( )无法完成这项任务,因它会生成重复的 值。提示:让函数创建一个包含所有可能值的矢量,使用 random_shuffle( ),然后通过打乱后的矢量的第一个值来获取值。编写 一个小程序来测试这个函数。

vector<int> lotto(int size,int size_rand)
{
	//设置随机数种子
	//srand(time(0));与rand()搭配使用的
	vector<int>ans;
	for (int i = 1; i < size+1; i++)
	{
		ans.push_back(i);
	}
	vector<int>ret;
	//每次随机打乱,抽取第一个
	for (int i = 0; i < size_rand; i++)
	{
		random_shuffle(ans.begin(), ans.end());
		ret.push_back(ans[0]);
	}
	for (int i = 0; i < size_rand; i++)
	{
		cout << ret[i] << " ";
	}
	cout << endl;
	return ret;
}

问题1:randdom_shuffle()用法

 在C++中,random_shuffle()函数用于随机打乱指定范围内的元素顺序。该函数需要包含<algorithm>头文件,并且其用法如下:

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 随机打乱vector中的元素顺序
    std::random_shuffle(vec.begin(), vec.end());

    // 输出打乱后的元素
    for (int num : vec) {
        std::cout << num << " ";
    }

    return 0;
}

题目:16.8 

 

题: Mat和Pat希望邀请他们的朋友来参加派对。他们要编写一个程 序完成下面的任务。

  • 让Mat输入他朋友的姓名列表。姓名存储在一个容器中,然后按排 列后的顺序显示出来。
  • 让Pat输入她朋友的姓名列表。姓名存储在另一个容器中,然后按 排列后的顺序显示出来。
  • 创建第三个容器,将两个列表合并,删除重复的部分,并显示这个 容器的内容。
//输出容器内的数据,使用类模板
template <typename T>
class Container {
private:
	T container;

public:
	Container(T c) : container(c) {}

	void print() {
		for (auto it = container.begin(); it != container.end(); ++it) {
			std::cout << *it << " ";
		}
		std::cout << std::endl;
	}
};

//第三个容器显然使用set,set可以去除重复的数
//前两个使用vector

void Show_Name()
{
	vector<string>Mat;
	int count = 1;
	while (count)
	{
		string name;
		cout << "Mat请输入朋友姓名:";
		
		cin >> name;
		cout << endl;
		Mat.push_back(name);
		cout << "是否继续:1继续,0结束:";
		cin >> count;
	}
	//输出容器内容,用类模板,我另一篇博客有有专门总结过
	Container<vector<string>> con(Mat);
	con.print();

	//
	vector<string>Pat;
	count=1;
	while (count)
	{
		string name;
		cout << "Pat请输入朋友姓名:";

		cin >> name;
		cout << endl;
		Pat.push_back(name);
		cout << "是否继续:1继续,0结束:";
		cin >> count;
	}
	//输出容器内容,用类模板
	Container<vector<string>> con2(Pat);
	con2.print();

	//合并两个人的内容
	set<string>ans;
	
	//传入Mat的数据
	vector<string>::iterator it = Mat.begin();
	for (it; it != Mat.end(); it++)
	{
		ans.insert(*it);
	}

	//传入Pat的数据
	vector<string>::iterator itp = Pat.begin();
	for (itp; itp != Pat.end(); itp++)
	{
		ans.insert(*itp);
	}

	Container<set<string>> con3(ans);
	con3.print();

}

 

  • 20
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值