string类(一)

目录

一、 string类对象的常见构造

二、string类对象的容量操作

 2.1 size(返回字符串有效字符长度)

2.2 capacity(返回空间总大小) 

 2.3 reserve扩空间​编辑

2.4 resize初始化不会覆盖本来的空间​编辑

2.5 对于test_string7中每一句代码进行调试运行

三、string类对象的访问及遍历操作

 3.1 operator[]

 3.2 迭代器

四、笔试题

1.关于代码输出正确的结果是( )

 2.关于代码输出正确的结果是( )

3.关于代码输出正确的结果是( )

4. 把字符串转换成整数_牛客题霸_牛客网 (nowcoder.com)

5.917. 仅仅反转字母 - 力扣(Leetcode)

6.541. 反转字符串 II - 力扣(Leetcode)

7.125. 验证回文串 - 力扣(Leetcode)  

一、 string类对象的常见构造

string类(一)_第1张图片

 string初始化:

#define _CRT_SECURE_NO_WARNINGS 1
#include

#include
using namespace std;

//string管理动态增长的字符数组,这个字符串以\0结尾
int main()
{
	std::string s;
	//string初始化
	string s1;//构造空的string类对象s1
	cout << "s1: " << s1 << endl;
	string s2("hello world");
	s2 += "!!!!";
	cout << "s2: " << s2 << endl;
	string s3(s2);
	cout << "s3: " << s3 << endl;
	string s4 = s2;//拷贝构造
	cout << "s4: " << s4 << endl;
	string s5("https://blog.csdn.net/weixin_57604904?spm=1000.2115.3001.5343", 4);
	cout << "s5: " << s5 << endl;
	string s6(6, 'C');
	cout << "s6: " << s6 << endl;
	string s7(s2, 6, 5);//第6个字符往后,不包括第6个,5个字符进行初始化
	cout << "s7: " << s7 << endl;
	string s8(s2, 6, 4);
	cout << "s8: " << s8 << endl;
	string s9(s2, 1, 100);//不会报错,会到\0截止
	cout << "s9: " << s9 << endl;
	string s10(s2, 6);//从s2的第六个字符往后直接到\0
	cout << "s10: " << s10 << endl;
	string s11(s2, 1);
	cout << "s11: " << s11 << endl;
	string s12(s2, 10);
	cout << "s12: " << s12 << endl;
	return 0;
}

string类(一)_第2张图片

 s1可修改:

void test_string()
{
	string s1("hello");
	string s2("xxxx");
	s1 = s2;
	s1 = "xxx";
	s1 = 'y';
	cout << s1 << endl;
	cout << s2 << endl;
}
int main()
{
	test_string();
	return 0;
}

二、string类对象的容量操作

string类(一)_第3张图片

 2.1 size(返回字符串有效字符长度)

 string类(一)_第4张图片

1. size()与length()方法底层实现原理完全相同,
引入size()的原因是为了与其他容器的接口保持一致,
一般情况下基本都是用size()。

2.2 capacity(返回空间总大小) 

void test_string6()
{
	string s("helloworld");
	size_t sz = s.capacity();//空间总大小
	cout << sz << endl;
	//s.reserve(1000);//扩空间
	//s.resize(1000, 'x');//扩空间+初始化
	for (int i = 0; i < 1000; i++)
	{
		s.push_back('c');//尾插
		if (sz != s.capacity())//尾插后,容量如果满了,容量会变
		{
			sz = s.capacity();//变了后就有新的sz
			cout << "capacity changed: " << sz << "\n";
		}
	}
}
int main()
{
	test_string6();
	return 0;
}

初始size与capacity:

字符串有效字符长度与空间总大小:

 string类(一)_第5张图片

 string类(一)_第6张图片

 尾插push_back,空间满了就扩容:string类(一)_第7张图片

 第一次扩容:string类(一)_第8张图片

 运行结果:string类(一)_第9张图片

 2.3 reserve扩空间string类(一)_第10张图片

2.4 resize初始化不会覆盖本来的空间string类(一)_第11张图片

 注意:观察如下代码:

void test_string7()
{
	string s("hello");
	s.reserve(100);
	s.resize(100, 'x');//注意不会改变hello,只是让size=100,后面补x
	s.reserve(10);//说明reserve会扩不会缩
//s[9] = 'y'//会报断言错误
	s.resize(10, 'x');//但是resize使得size= 10//s[9] = 'x'
	s[9] = 'y';//不会报错
}
int main()
{
	test_string7();
	return 0;
}

2.5 对于test_string7中每一句代码进行调试运行

1.capacity变为111

string类(一)_第12张图片

 2.size变为100,补xstring类(一)_第13张图片

 3. capacity没有变(reserve不会缩只会扩)

 4.resize会改变size,从100->10

string类(一)_第14张图片

 5.改变s[9],不会报错

string类(一)_第15张图片

3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,
不同的是当字符个数增多时:
    resize(n)用0来填充多出的元素空间,
    resize(size_t n, char c)用字符c来填充多出的元素空间。
    注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,
   当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。

三、string类对象的访问及遍历操作

string类(一)_第16张图片

 3.1 operator[]

string类(一)_第17张图片返回位于字符串中指定位置的字符:

1. 对于operator[],字符串中的第一个字符用值0(而不是1)表示,
    s1.operator[](i)//返回位于字符串中指定位置i的字符。
    如果字符串对象是const限定的,则该函数返回const char&。否则,它返回char&。
    char& operator[] (size_t pos);const char& operator[] (size_t pos) const;

2. 为什么不能返回char?
    1).返回的是位于字符串指定位置pos的字符,return str[pos]
    其因为是在堆区开辟的,出了作用域还在,所以按常规操作肯定是返回char&别名更合适,减少拷贝;
    2).这样引用返回可以使得返回值可修改,因为如果是char返回,返回是先创建临时变量,返回的是临时变量,而临时变量具有常性,const权限放大,不能赋值和修改,而char&不会,可以修改。

void test_string2()
{
	string s1("hello");//初始化
	s1.at(1) = 'x';
	//s1[6];//会报错assert判断的
	cout << s1.size() << endl;//s1.size()返回有效字符个数,不包含\0
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}
	cout << endl;
}
int main()
{
	test_string2();
	return 0;
}

string类(一)_第18张图片

 3.2 迭代器

string类(一)_第19张图片

reverse_iterator rbegin();

const_reverse_iterator rbegin() const;

string类(一)_第20张图片

void test_string4()
{
	string s = "helloworld";
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
}
void test_string5()
{
	const string s = "helloworld";
	string::const_reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;

}
int main()
{
    test_string4();
    test_string5();
    return 0;
}

四、笔试题

1.关于代码输出正确的结果是( )

关于代码输出正确的结果是( )

int main(int argc, char *argv[])
{
string a="hello world";
string b=a;
if (a.c_str()==b.c_str())
{
    cout<<"true"<
分析:a 和 b的值虽然相同,
但是a.c_str()==b.c_str()比较的是存储字符串位置的地址,
a和b是两个不同的对象,内部数据存储的位置也不相同,因此不相等,
后面c="",a=""与b对象都没有任何的影响,所以都不相等
故答案为:A

 2.关于代码输出正确的结果是( )

下面程序的输出结果正确的是( )
int main()
{
string str("Hello Bit.");
str.reserve(111);
str.resize(5);
str.reserve(50);
cout<
分析:

str.reserve(111); //调整容量为 111

str.resize(5);   //调整元素个数为 5

str.reserve(50);  //调整容量为 50,由于调整的容量小于已有空间容量,故容量不会减小

所以size=5 capacity=111

故答案为: C

3.关于代码输出正确的结果是( )

下面程序的输出结果正确的是( )
int main(int argc, char *argv[])
{
string strText = "How are you?";
string strSeparator = " ";
string strResult;
int size_pos = 0;
int size_prev_pos = 0;
while((size_pos=strText.find_first_of(strSeparator, size_pos)) != string::npos)
{
strResult = strText.substr(size_prev_pos, size_pos-size_prev_pos);
cout<
分析:程序的目的是以字符串strSeparator = " "作为分隔符,
对字符串string strText = "How are you?";进行分割,每分割出一个单词就进行一次打印

故答案为 D

实际的 find_first_of函数的作用是:
        在一个字符串中进行查找,返回值是第一个与指定字符串中任何字符匹配的字符位置;
如果没有找到匹配的内容,就返回 string::npos。
 string类(一)_第21张图片

注意与find的区别:发现find是返回-1,说明找不到。

string类(一)_第22张图片

 find:

string类(一)_第23张图片

substr:

substr(size_type _Off = 0,size_type _Count = npos)
参数:
_Off——所需的子字符串的起始位置。字符串中第一个字符的索引为 0,默认值为0。
_Count——复制的字符数目
返回值——一个子字符串,从其指定的位置开始
假设string s(“student12”);
string x=s.substr()                 //默认时的长度为从开始位置到尾
string y=s.substr(5)               //获得字符串s中 从第5位开始到尾的字符串
string z=s.substr(5,3);         //获得字符串s中 从第5位开始的长度为3的字符串

 具体解析:

int main()
{
	string strText = "How are you?";
	string strSeparator = " ";
	string strResult;
	int size_pos = 0;
	int size_prev_pos = 0;
	//找不到就返回npos
	//在strText中找空格,返回位置为3,因为是从0开始。
	//找不到就返回string::pos
	//只要strText.find_first_of(strSeparator, size_pos)) != string::npos就说明
	//找到了空格,找到了空格就返回所在位置或者说是下标size_pos
	while ((size_pos = strText.find_first_of(strSeparator, size_pos)) != string::npos)
		//在strText的第0开始找strSeparator也就是空格,返回的位置只要不是-1,就进入循环,
		//如果在一个字符串strText中查找另一个字符串strSeparator,
		//如果strText1中含有strSeparator中的任何字符,则就会查找成功
	{
		//从0开始找(3-0)个元素,找到How
		strResult = strText.substr(size_prev_pos, size_pos - size_prev_pos);
		cout << strResult << " ";//再输出一个空格
		size_prev_pos = ++size_pos;//然后同时++,都变成4
		//之后size_pos = 4,从位置4开始找空格,到了位置7,7-4=3
		//size_prev_pos = size_pos = 8
		//之后就找不到空格了,跳出循环,size_pos = -1,size_prev_pos = 8
	}
	if (size_prev_pos != strText.size())//已知size = 12,8!=12进入if
		//只要不和size相等就进入循环
	{
		strResult = strText.substr(size_prev_pos, size_pos - size_prev_pos);
		//从8开始找到-9,就相当于找到底
		cout << strResult << " ";
	}
	cout << endl;
	return 0;
}

4. 把字符串转换成整数_牛客题霸_牛客网 (nowcoder.com)

描述

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为 0 或者字符串不是一个合法的数值则返回 0

class Solution
{
  public:
    int StrToInt(string str)
    {
        if (str == "")//如果没有字符串返回0
            return 0;//输入一个字符串,包括数字字母符号,可以为空
        int ret = 0;
        int flag = 1;
        if (str[0] == '-')
        {
            str[0] = '0';
            flag = -flag;
        }
        if (str[0] == '+') 
        {
            str[0] = '0';
        }
        for (int i = 0; i < str.size(); ++i) 
        {
            if (str[i] < '0' || str[i] > '9') 
            //注意:字符串中可能出现任意符号,出现除 +/- 以外符号时直接输出 0
            {
                return 0;
            }
            if (str[i] >= '0' && str[i] <= '9')
            //比如str是0123,str[1] = 1,ret = 0+1
            //str[2] = 2,ret = 1*10+2=12
            //str[3] = 3,ret = 12*10+3=123
            {
                ret = ret*10 + str[i] - '0';//‘0’ascii码值是48
                //字符'1'的ascii码值是49,49-48 =1,从字符1变成整数1
            }
        }
        if (flag == -1)
        {
            ret *= -1;//如果flag等于-1,那么ret就要乘上-1
        }
        return ret;
    }
};

5.917. 仅仅反转字母 - 力扣(Leetcode)

给你一个字符串 s ,根据下述规则反转字符串:

  • 所有非英文字母保留在原有位置。
  • 所有英文字母(小写或大写)位置反转。

返回反转后的 s 。

class Solution {
public:
    bool isLetter(char ch)
    {
        if(ch >= 'A' && ch <= 'Z')
        {
            return true;
        }
        else if(ch >= 'a' && ch <= 'z')
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    string reverseOnlyLetters(string s) 
    {
        string::iterator left = s.begin();
        string::iterator right = s.end()-1;
        while(left < right)
        {
            while(left

6.541. 反转字符串 II - 力扣(Leetcode)

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

class Solution {
public:
	void reverse(string& s, int left, int right) 
	{
		while (left < right)
		{
			swap(s[left], s[right]);
			left++;
			right--;
		}
	}

	string reverseStr(string s, int k) 
	{
		//从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
		//每次i向前移动2k个字符
		for (int i = 0; i < s.size(); i += 2 * k) 
		{
			//x为走了2k步后的剩余字符,如果k<= x <2k,那么反转前k个数
			//那么s.size()>=(k+2k),就反转前k个数
			if (s.size() >= (i + k))
			{
				reverse(s, i, i + k - 1);
				continue;//反转前k个数后,调到for循环,继续向后走2k步,如果还大于,接着反转前k个数
			}
			//如果x

7.125. 验证回文串 - 力扣(Leetcode)  

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 

class Solution {
public:
	char func(char c)
	{
		if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z'))
			return c;//数字0~9或a~z无需转换
		else if ('A' <= c && c <= 'Z')
			return c + 'a' - 'A';   //所有大写转小写,A~Z转化为对应a~z
		else
		{
			return ' ';    //其他字符转换为空格符' '
		}
	}
	bool isPalindrome(string s)
	{
		if (s.size() == 0 || s.size() == 1) 
			return true;//空字符和一个字符都是回文结构
		string::iterator left = s.begin();
		string::iterator right = s.end() - 1;
		char c1, c2;
		while (left < right)
		{
			c1 = func(*left); //调用转化函数
			c2 = func(*right);  //调用转化函数
			if (c1 == ' ')
			{
				left++;
			}
			if (c2 == ' ')
			{
				right--;
			}
			//c1和c2如果是空格,说明是别的字符且已经转换了
			if (c1 != ' ' && c2 != ' ')
			{
				if (c1 != c2)
				{
					return false;
				}	
				left++; right--;
			}
		}
		return true;
	}	
};

你可能感兴趣的:(研究生日记,c++)