C++知识点 -- string类

C++知识点 – string类


在这里插入图片描述

一、成员函数

在这里插入图片描述

1.构造函数

在这里插入图片描述
(1)是无参的构造函数,
(2)是拷贝构造,
(3)是部份拷贝构造 ,
(4)是带参数的构造函数,
(5)是用s的前几个字符构造,
(6)是用n个指定字符c去构造;
代码如下:

void test__string1()
{
	string s1;//无参
	string s2("hello");//有参

	string s3(s2);//拷贝构造

	string s4(s2, 1, 3);//部分拷贝,pos是开始拷贝的位置,len是拷贝的字符长度

	string s5("hello world", 5);

	string s6(100, 'x');

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;

	//string类中重载了 << 和 >> 运算符
}

结果为:
在这里插入图片描述

2.赋值重载

在这里插入图片描述
(1)可以重载其他string对象,
(2)可以重载字符串,
(3)可以重载字符;
代码如下:

void test__string2()
{
	string s1;
	string s2("hello world");

	s1 = s2;
	cout << s1 << endl;
	s1 = "stay";
	cout << s1 << endl;
	s1 = 'c';
	cout << s1 << endl;
}

运行结果:
在这里插入图片描述

二、元素访问

在这里插入图片描述

1.[]重载

能够允许我们以数组的形式访问string类的字符串;
在这里插入图片描述
普通字符串调用普通的[]重载,cosnt字符串调用const的[]重载;
这里重载[]是传引用返回,不光可以读,还可以进行修改;

代码如下:

void test__string3()
{
	string s1("hello world");
	cout << s1[0] << endl;

	s1[0] = 'a';
	cout << s1 << endl;

	for (int i = 0; i < s1.size(); i++)
	{
		s1[i]++;
	}
	cout << s1 << endl;

	const string s2("hello world");
	cout << s2[1] << endl;
	//s2[1] = 'a';
	//const string对象是不能修改的
}

运行结果:
在这里插入图片描述

三、迭代器

用法类似指针;
在这里插入图片描述

1.迭代器iterator

在这里插入图片描述
begin:返回一个指向字符开始位置的迭代器;
在这里插入图片描述
end:返回一个指向字符结束位置后一个位置(‘\0’)的迭代器;
在这里插入图片描述

所以迭代区间都是左闭右开的[);
迭代器中不能用>,只能用!= ,因为list等对象空间就不是连续的了

代码如下:

void test__string4()
{
	string s("hello");
	string::iterator it = s.begin();
	while (it != s.end())//迭代器中不能用>,只能用!=。因为list等对象空间就不是连续的了
	{
		cout << *it << ' ';
		it++;
	}
	cout << endl;
}

在这里插入图片描述

2.范围for

范围for – 自动迭代,自动判断结束;
代码如下:

void test__string4()
{
	string s("hello");
	for (auto ch : s)
	{
		cout << ch << ' ';
	}
	cout << endl;
}

依次取s中的每一个字符,赋值给ch;
范围for的底层就是迭代器;

void test__string4()
{
	string s("hello");
	for (auto& ch : s)
	{
		ch++;
		cout << ch << ' ';
	}
	cout << endl;
}

范围for要修改一定要改成引用,引用ch就成了*it的别名,

3.反向迭代器

在这里插入图片描述

代码如下:

void test__string4()
{
	string s("hello");
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << ' ';
		rit++;

	}
	cout << endl;
}

在这里插入图片描述

4.const迭代器

针对于const string对象的迭代器;
代码如下:

void test__string4()
{
	const string s1("hello");
	string::const_iterator cit = s1.begin();
	while (cit != s1.end())
	{
		cout << *cit << ' ';
		cit++;
	}
	cout << endl;
}

5.反向const迭代器

代码如下:

void test__string4()
{
	const string s1("hello");
	//string::const_reverse_iterator crit = s1.rbegin();
	auto crit = s1.rbegin();
	while (crit != s1.rend())
	{
		cout << *cit << ' ';
		crit++;
	}
	cout << endl;
}

在这里插入图片描述

四、修改

在这里插入图片描述

1.push_back、append、+=

push_back:在字符串后追加一个字符;
在这里插入图片描述
append:在字符串后追加一个字符串;
在这里插入图片描述
+=:在字符串后追加一个字符串;
在这里插入图片描述

代码如下:

void test__string5()
{
	string s("hello");
	s.push_back('-');
	s.push_back('-');
	s.append("world");
	cout << s << endl;

	string s1("hello");
	s1 += '-';
	s1 += '!';
	s1 += "world";
	cout << s1 << endl;
}

在这里插入图片描述

2.insert、erase

在这里插入图片描述
在指定地址插入字符串;
在这里插入图片描述
删除指定长度的字符串;

例:在字符的空格处插入20%
代码如下:

void test__string7()
{
	string s("ni shi shei");
	for (size_t i = 0; i < s.size(); i++)
	{
		if (s[i] == ' ')
		{
			s.insert(i, "20%");
			i += 3;
		}
	}

	for (size_t i = 0; i < s.size(); i++)
	{
		if (s[i] == ' ')
		{
			s.erase(i, 1);
		}
	}
	cout << s << endl;
}

使用insert效率较低,因为insert的底层是挪动数组;
用空间换时间的解决方案:

void test__string7()
{
	string s("ni shi shei");
	string newstr;
	for (size_t i = 0; i < s.size(); i++)
	{
		if (s[i] != ' ')
		{
			newstr += s[i];
		}
		else
		{
			i++;
		}
	}
	cout << newstr << endl;
}

五、容量

在这里插入图片描述

1.max _size 和 capacity

代码如下:

void test__string6()
{
	string s1;
	string s2("1111111111");
	cout << s1.max_size() << endl;
	cout << s2.max_size() << endl;

	cout << s1.capacity() << endl;
	cout << s2.capacity() << endl;

}

在这里插入图片描述

六、字符串应用

在这里插入图片描述

1.c_str

在这里插入图片描述
返回c形式的字符串;
代码如下:

void test__string8()
{
	//用c形式读文件
	string filename("test.cpp");
	FILE* fp = fopen(filename.c_str(), "r");
	assert(fp);
	char ch = fgetc(fp);
	while (ch != EOF)
	{
		cout << ch;
		ch = fgetc(fp);
	}
	fclose(fp);
	fp == nullptr;
}
void test__string8()
{
	string filename("test.cpp");
	cout << filename << endl;
	cout << filename.c_str() << endl;

	filename += '\0';
	filename += "test.cpp";

	cout << filename << endl;//以size为准
	cout << filename.c_str() << endl;//以\0为准
}

string的字符串长度是以size为准的,而c_str的字符串长度是以\0为准的;
在这里插入图片描述

2.find、rfind、substr

在这里插入图片描述
返回要寻找的字符串的下标, 若没有找到,返回npos

在这里插入图片描述
返回一部分字符串构成子串;
在这里插入图片描述
从字符串尾部向前寻找;
例:取文件后缀名,代码如下:

void test__string9()
{
	string filename("test.cpp");
	size_t pos = filename.find('.');
	if (pos != string::npos)
	{
		string suff = filename.substr(pos, filename.size() - pos);
		cout << suff << endl;
	}
}

在这里插入图片描述
倒着找:

void test__string9()
{
	string filename("test.cpp.tar.zip");
	size_t pos = filename.rfind('.');
	if (pos != string::npos)
	{
		string suff = filename.substr(pos, filename.size() - pos);
		cout << suff << endl;
	}
}

在这里插入图片描述
分割url:

void DealUrl(const string& url)
{
	//取协议
	size_t pos1 = url.find("://");
	if (pos1 == string::npos)
	{
		cout << "非法url" << endl;
		return;
	}
	string protocol  = url.substr(0, pos1);
	cout << protocol << endl;

	//取域名
	size_t pos2 = url.find("/", pos1 + 3);
	if (pos2 == string::npos)
	{
		cout << "非法url" << endl;
		return;
	}
	string domain = url.substr(pos1+3, pos2 - pos1 -3);
	cout << domain << endl;

	//取uri
	string uri = url.substr(pos2 + 1);
	cout << uri << endl;
}

在这里插入图片描述

七、类型转换

在这里插入图片描述
字符串转换为其他类型;
在这里插入图片描述
其他类型转换为字符串;

八、非成员函数重载

1.getline

在这里插入图片描述
从流中提取一行作为字符串;
代码如下:

void test__string10()
{
	string str;
	getline(cin, str);
	cout << str << endl;
}

在这里插入图片描述
普通流提取,碰到空格或者换行都会停止,换到提取下一个对象;
getline中间遇到空格不会被打断;

九、练习例题

1.仅反转字母

https://leetcode.cn/problems/reverse-only-letters/
代码如下:

class Solution {
public:
    bool isLetter(const char c)//判断是否为字母
    {
        if(c >= 'a' && c <= 'z'
        || c >= 'A' && c <= 'Z')
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    string reverseOnlyLetters(string s) {
        size_t begin = 0, end = s.size() - 1;//两个下标,分别指向头和尾
        while(begin < end)
        {
            while(begin < end && !isLetter(s[begin]))//判断下标指向的字符是否为字母
            {
                begin++;
            }
            while(begin < end && !isLetter(s[end]))
            {
                end--;
            }
            swap(s[begin], s[end]);//交换
            ++begin;
            --end;
        }  
        return s;             
    }
};

2.字符串中的第一个唯一字符

https://leetcode.cn/problems/first-unique-character-in-a-string/
代码如下:

class Solution {
public:
    int firstUniqChar(string s) {
        //计数排序的思想
        int CharCount[26] = {0};//创建一个记录所有字母出现次数的数组
        for(auto ch : s)
        {
            CharCount[ch - 'a']++;//每个字母出现一次就在对应数组位置加一
        }

        for(size_t i = 0; i < s.size(); i++)//遍历字符串,找到第一个只出现一次的字符,并返回下标
        {
            if(CharCount[s[i] - 'a'] == 1)
            {
                return i;
            }
        }
        return -1;
    }
};

3.字符串最后一个单词的长度

https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking
代码如下:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str;
    getline(cin, str);
    int pos = str.rfind(' ');
    int len = str.size() - pos - 1;
    cout << len << endl;

    return 0;
}

4.验证回文串

https://leetcode.cn/problems/valid-palindrome/
代码如下:

class Solution {
public:
    bool isLetterOrNum(const char c)//判断是否为字母或数字
    {
        return (c >= 'a' && c <= 'z'
            || c >= '0' && c <= '9');
    }

    bool isPalindrome(string s) {
        for(size_t i = 0; i < s.size(); i++)//先将大写字母转为小写
        {
            if(s[i] >= 'A' && s[i] <= 'Z')
            {
                s[i] += 32;
            }
        }

        int begin = 0, end = s.size() - 1;//创建头尾两个下标
        while(begin < end)
        {
            while(begin < end && !isLetterOrNum(s[begin]))//只判断字母和数字
            {
                begin++;
            }
            while(begin < end && !isLetterOrNum(s[end]))
            {
                end--;
            }
            if(s[begin] != s[end])//不是回文返回false
            {
                return false;
            }
            begin++;
            end--;
        }

        return true;
    }
};

5.字符串相加

https://leetcode.cn/problems/add-strings/
代码如下:

//头插法
class Solution {
public:
    string addStrings(string num1, string num2) 
    {
        //取两个数的尾部,从后往前加
        int end1 = num1.size() - 1;
        int end2 = num2.size() - 1;
        int next = 0;//进位标志
        string strRet;//结果
        while(end1 >= 0 || end2 >= 0)
        {
            int val1 = end1 >= 0 ? num1[end1] - '0' : 0;//取两数的最后一个数字
            int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
            int ret = val1 + val2 + next;//计算这两位的结果
            next = ret > 9 ? 1 : 0;//判断是否进位

            //头插
            strRet.insert(strRet.begin(), (ret % 10) + '0');//将计算结果插入到结果字符串最前面

            --end1;
            --end2;
        }

        if(next)//如果两个数字都加完,但是进位还有,需要考虑进位
        {
            strRet.insert(strRet.begin(), next + '0');
        }

        return strRet;
    }
};
//尾插法,最后逆置
class Solution {
public:
    string addStrings(string num1, string num2) 
    {
        //取两个数的尾部,从后往前加
        int end1 = num1.size() - 1;
        int end2 = num2.size() - 1;
        int next = 0;//进位标志
        string strRet;//结果
        while(end1 >= 0 || end2 >= 0)
        {
            int val1 = end1 >= 0 ? num1[end1] - '0' : 0;//取两数的最后一个数字
            int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
            int ret = val1 + val2 + next;//计算这两位的结果
            next = ret > 9 ? 1 : 0;//判断是否进位
            
            //尾插,后逆置
            strRet += (ret % 10 + '0');

            --end1;
            --end2;
        }

        if(next)//如果两个数字都加完,但是进位还有,需要考虑进位
        {
            strRet += '1';
        }

        reverse(strRet.begin(), strRet.end());//逆置

        return strRet;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值