前言:在前面我们说过,前面的绝大部分内容都是在为了后面真正进入C++这块大门做铺垫,今天我们将正式的步入string类来进一步了解C++的奥妙。
? 博主CSDN主页:卫卫卫的个人主页 ?
? 专栏分类:高质量C++学习 ?
?代码仓库:卫卫周大胖的学习日记?
?关注博主和博主一起学习!一起努力!
目录标题
string类的使用string类对象的常见构造构造函数string类对象的容量操作string类对象的访问及遍历操作迭代器(非常重要)string中operator[ ]重载的使用 string类对象的修改操作C++中的string与C语言字符串的区别string类中的运算符重载
string类的使用
string类对象的常见构造
字符串是表示字符序列的类标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请basic_string)。注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
构造函数
1string()
.默认构造函数,创建一个空字符串。
int main(){string emptyString;// 使用默认构造函数创建空字符串对象string emptyString1 = "";// 使用空字符串字面值构造函数创建空字符串对象string StrOutput("hello");emptyString = StrOutput;emptyString1 = StrOutput;cout << emptyString << endl;cout << emptyString1<<endl;return 0;}
这两种方法都将创建一个空的字符串对象,可以在后续的代码中对其进行赋值或修改。
2.string(const char* str):
使用C风格的字符串来初始化一个string对象
int main(){string StrOutput = "Hello string";//构建一个对象并赋值cout << StrOutput << endl;//打印对象const char* str_cur = "weiweiwei";//printf("%s\n", str_cur);//printf无法直接打印string类对象中的内容,需要转化成char*后才能打印string s(str_cur);cout << s<< endl; //cout可以直接打印return 0;}
string 对象(size_t n, char c)
string类对象中包含n个字符c int main(){string m(10, 'a'); //string类对象中包含10个字符a//myString = "aaaaaaaaaa";cout << m << endl;return 0;}
string 对象(拷贝的对象,size_t,count)
从拷贝对象的第t个数开始,往后拷贝count个数到 string构建的新的对象中。 int main(){string s1("weiweizhoudapang");string s2(s1, 2, 2);//下标就是从1开始的,指代从s1中第二个字符开始一直往后两个字符都拷贝到s3中cout << s2 << endl;string s3(s1, 3);//省略最后一个参数,指从s1中第三个参数开始一直往后的所有参数全部拷贝到s1中cout << s3 << endl;cout << string(s1, 2, 2);//匿名对象直接调用return 0;}
string(const string&s)
是一个构造函数,它的作用是将一个传入的字符串变量s作为参数,创建一个新的字符串对象。该构造函数是通过引用的方式传递参数的,这意味着它不会创建s的拷贝,而是直接使用s的引用。 #include <iostream>#include <string>using namespace std;int main() { // 定义一个字符串变量s并赋值 string s = "Hello World"; // 使用构造函数创建一个新的字符串对象s2,将s作为参数传入 string s2(s); // 输出s和s2的值 cout << "s: " << s << endl; cout << "s2: " << s2 << endl; return 0;}
总结:
cout 可直接输出 string 类的对象的内容;使用 c_str() 方法转换 string 类型到 char* 类型时,需要为char*添加 const 关键字;printf() 函数不能直接打印 string 类的对象的内容,可以通过将 string 转换为 char* 类型,再使用 printf() 函数打印。string类对象的容量操作
1.size()
:返回字符串中字符的数量,也就是字符串的长度。
int main(){string str = "hello string";int len = str.size();cout << len << endl;//返回12return 0;}
length()
:同样返回字符串的长度,与size()方法功能相同。 int main(){string str = "hello string";int len = str.length();//返回12cout << len;return 0;}
capacity()
:返回字符串在内存中分配的总容量,即字符串实际占用的内存大小。 int main(){string str = "hello string";int cap = str.capacity();//返回实际字符串占用的内存cout << cap;return 0;}
注意事项:
在 C++ 的 string 类中,capacity() 函数返回当前字符串的容量,即字符串在不重新分配内存的情况下可以容纳的字符数。容量包括字符串实际存储的字符数以及额外的预留空间。
预留空间是为了避免频繁地进行内存重新分配操作,当字符串的空间不足时,string 类会自动分配一块更大的内存空间,并将原来的字符拷贝到新的内存中。
因此,capacity() 返回的容量可能会比字符串的长度(通过 length() 或 size() 函数获得)大一些。这样设计的目的是提高字符串操作的效率,避免每次添加字符时都需要重新分配内存。
需要注意的是,capacity() 返回的容量不一定和实际分配的内存大小相等。实际分配的内存大小可以通过 sizeof(string) 来获得,这个大小包括了除了存储字符之外的其他开销,比如指针、长度信息等。
另外,可以使用 reserve() 函数来显式地设置字符串的容量,这样可以避免后续的内存重新分配。但是需要注意,reserve() 并不会改变字符串的长度,只是保证了容量足够存储指定长度的字符。
empty()
:用于判断字符串是否为空。当字符串中没有任何字符时,即长度为0时,empty()函数返回true;否则返回false。 int main() { std::string str1 = "Hello"; std::string str2; if (str1.empty()) { std::cout << "str1为空" << std::endl; } else { std::cout << "str1不为空" << std::endl; } if (str2.empty()) { std::cout << "str2为空" << std::endl; } else { std::cout << "str2不为空" << std::endl; } return 0;}
5.clear()
:用于清空字符串的内容,即将字符串的长度设置为0,删除所有字符
int main() { std::string str = "Hello, World!"; std::cout << "清空前的字符串:" << str << std::endl; str.clear(); std::cout << "清空后的字符串:" << str << std::endl; return 0;}
reserve()
:用于预分配字符串的存储空间,以提高字符串的效率和性能 int main() { std::string str; std::cout << "空字符串的容量:" << str.capacity() << std::endl; str.reserve(100); std::cout << "预分配100个字符后的容量:" << str.capacity() << std::endl; return 0;}
注意:
在上述示例中,我们首先创建了一个空字符串str,并使用capacity()函数获取了该空字符串的容量,结果为15(可能会因实现而异)。
接着,我们调用reserve(100)函数,将字符串str的容量预分配为100个字符,以提供更多的存储空间。再次使用capacity()函数获取容量,结果为100。
通过使用reserve()函数,我们可以提前分配足够的内存空间,避免字符串频繁重新分配内存的开销,以提高性能。请注意,reserve()函数只会增加字符串的容量,但不会改变字符串的长度。reserve(size_t res_arg=0):为string预留间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
resize()
用于修改字符串的大小。将有效字符的个数该成n个,多出的空间用字符c填充。 int main() { std::string str = "Hello"; std::cout << "修改前的字符串:" << str << std::endl; str.resize(8,'b');//将有效字符的个数该成8个,多出的空间用字符b填充。 std::cout << "增加字符后的字符串:" << str << std::endl; str.resize(3); std::cout << "减少字符后的字符串:" << str << std::endl; return 0;}
string类对象的访问及遍历操作
访问字符:可以通过下标运算符([ ])和at()函数访问字符串中的单个字符。下标从0开始计数,可以使用str[0]或者str.at(0)访问字符串str的第一个字符。int main() { std::string str = "Hello string"; for (int i = 0; i < str.size(); i++)//下标运算符([])访问字符串 { printf("%c ", str[i]); } printf("\n"); for (int i = 0; i < str.size(); i++)//at()函数访问字符串 { printf("%c ", str.at(i)); } return 0;}
迭代器(非常重要)
概念:在C++中,迭代器是一种通用的抽象概念,用于遍历容器中的元素。使用迭代器可以方便地访问容器中的元素,并进行插入、删除等操作。
获取迭代器:对于容器类对象,可以使用成员函数begin()和end()获取迭代器,begin()返回指向容器第一个元素的迭代器,end()返回指向容器最后一个元素之后的位置的迭代器。(如果你无法理解,你可以把它理解成一个指针,但是它又不是指针等到后面我们会讲)int main(){string s1 = "Hello String";auto it = s1.begin();//指向第一个字符的迭代器//或者像下面这样写string::iterator item;item = s1.begin();int i = 0;for (i = 0; i < s1.size(); i++){cout << *(it + i);}cout << endl;auto its = s1.end();//指向最后一个字符的迭代器cout << *(its- 1) << endl;return 0;}
在C++中,反向迭代器(reverse_iterator)可以用于从容器的末尾向前遍历元素。使用反向迭代器可以方便地逆序访问容器中的元素。
注意:在C++中,rbegin()和rend()是两个成员函数,可用于返回反向迭代器的起始位置和终止位置。
rbegin()函数返回一个指向容器中最后一个元素的反向迭代器(即反向迭代器的起始位置),而rend()函数返回一个指向容器中第一个元素之前位置的反向迭代器(即反向迭代器的终止位置,不包括在遍历范围内)
int main() { string s1 = "Hello reverse_iterator"; // 使用反向迭代器遍历容器中的元素 std::string::reverse_iterator rit;//构建一个反向迭代器rit int i = 0; for (rit = s1.rbegin(); rit != s1.rend(); ++rit)//反向遍历字符 { std::cout << *rit << " "; } return 0;}
在C++中,常量迭代器(const iterator)用于遍历容器并保证容器中的元素不可修改。常量迭代器可以指向容器中的元素,并允许读取元素的值,但不允许修改元素的值。常量迭代器用于在不改变容器元素的情况下遍历容器,特别适用于需要只读访问容器的情况。
int main() { string s1 = "Hello const_iterator"; // 使用 const_iterator 遍历容器 string::iterator it; int i = 0; for (it = s1.begin(); it != s1.end(); it++) cout << *it; return 0;}
C++中的范围for语句是一种方便的循环语句,可以用来遍历一个容器(如数组、向量、列表等)中的元素。使用范围for语句可以简化代码,并且更易于阅读和理解。
基本语法:
for (element_declaration : container) { // 循环体}//其中,element_declaration是一个新的变量,//用于接收容器中的每个元素,container表示被遍历的容器。
示例演示:
int main() { int arr[] = { 1, 2, 3, 4, 5 }; for (int element : arr)//范围for遍历数组 { cout << element << " "; } cout << endl; string s1("weiwei zhou da pang");//范围for遍历string类的对象 for (char element : s1) { cout << element; } return 0;}
string中operator[ ]重载的使用
在C++的std::string类中,operator[]被重载了,可以用于访问字符串中的单个字符。operator[]返回一个引用,可以用于读取或修改该位置处的字符。
int main() { std::string str = "Hello, world!"; // 使用 operator[] 读取字符 char c = str[0]; std::cout << "First character: " << c << std::endl; // 使用 operator[] 修改字符 str[7] = 'W'; std::cout << "Modified string: " << str << std::endl; return 0;}
注意:
string类对象的修改操作
C++中string类对象的修改操作可以使用以下方法:
使用赋值运算符(=)将一个字符串赋给另一个字符串对象。string str1 = "Hello";string str2 = "World";str1 = str2; // str1现在的值为"World"
使用成员函数
assign()
将一个字符串赋给另一个字符串对象。 int main(){string s1 = "weiweizhoudapang";string s2 = " ";cout << s2.assign(s1)<<endl;//把s1中的值分给了s2;cout << s1 << endl;//s1中的值不变return 0;}
使用
+=
操作符将一个字符串附加到另一个字符串对象的末尾。 int main(){string s1 = "weiwei";string s2 = "zhoudapang";s1 += s2;//现在s1的值就是:weiweizhoudapangcout << s1 << endl;return 0;}
使用
append()
成员函数将一个字符串附加到另一个字符串对象的末尾。 string str1 = "Hello";string str2 = "World";str1.append(str2); // str1现在的值为"HelloWorld"
使用成员函数
insert()
在指定的位置插入一个字符串。 string str = "Hello";string insertStr = " World";str.insert(5, insertStr); // str现在的值为"Hello World"
使用成员函数
erase()
删除指定位置的字符。 string str = "Hello World";str.erase(6); // str现在的值为"Hello orld"
使用成员函数
replace()
替换指定位置的字符串。 string str = "Hello World";string replaceStr = "C++";str.replace(6, 5, replaceStr); // str现在的值为"Hello C++"
使用成员函数
push_back
尾插一个字符 int main(){string s1 = "weiwei";s1.push_back('c');//在s1的末尾尾插一个字符ccout << s1 << endl;//此时s1就是weiweicreturn 0;}
在C++中,npos是一个常量,表示一个无效的或不存在的位置。它在string和vector等容器中经常用于表示找不到元素的情况。
find函数用于在字符串或容器中搜索指定的元素。它返回一个迭代器,指向第一个匹配到的元素。如果没有找到匹配的元素,则返回npos。
语法使用:(需注意的是find是从前往后找)
size_t 变量名 = string 对象名.find(查找的元素,pos)//pos指代从pos这个位置前往后找
int main(){ std::string str = "abcdefg"; std::size_t found = str.find("abf"); //如果找到会返回该字符串第一个字符的下标 if (found != std::string::npos)//如果没有找到会返回npos { std::cout << "子字符串找到,位置为:" << found <<"字符是: "<<str[found]<<std::endl; } else { std::cout << "子字符串未找到" << std::endl; } std::size_t found1 = str.find("ef"); if (found1 != std::string::npos) { std::cout << "子字符串找到,位置为:"<<found1 <<"字符是: " << str[found1] << std::endl; } else { std::cout << "子字符串未找到" << std::endl; } std::size_t found2 = str.find("efg", 2); if (found2 != std::string::npos) { std::cout << "子字符串找到,位置为:"<<found2 <<"字符是: " << str[found2] << std::endl; } else { std::cout << "子字符串未找到" << std::endl; } return 0;}
在C++中,rfind()函数用于在字符串或容器中从后往前搜索指定的元素。它返回最后一个匹配元素的位置,如果没有找到匹配的元素,则返回npos。
语法说明:
size_t rfind(const string& str, size_t pos = npos) const;
其中str表示要搜索的子字符串,pos表示从哪个位置开始搜索,默认值为npos,表示从字符串的末尾开始搜索 int main() { std::string str = "hello world hello"; std::string target = "hello"; size_t found = str.rfind(target); if (found != std::string::npos) { std::cout << "子字符串找到,位置为:" << found << std::endl; } else { std::cout << "子字符串未找到" << std::endl; } return 0;}
在C++中,substr()函数用于从字符串中提取子字符串。它接受两个参数:起始位置和子字符串的长度。substr()函数的语法如下:
string substr(size_t pos = 0, size_t len = npos) const;
其中pos表示起始位置,默认为0,len表示子字符串的长度,默认为npos,表示提取从起始位置到字符串末尾的所有字符
int main() { std::string str = "Hello, World!"; std::string sub1 = str.substr(str.find('W')); // 从字母W开始提取到末尾 std::string sub2 = str.substr(str.find('H'), str.find('o')+1); //从字符H一直到字符o std::cout << "sub1: " << sub1 << std::endl; // 输出: World! std::cout << "sub2: " << sub2 << std::endl; // 输出: Hello return 0;}
需要注意的是,substr()函数返回的是一个新的字符串,原字符串并没有被修改。因此,你可以将提取的子字符串赋值给另一个字符串变量,或者直接在输出语句中使用。
在C++中,
c_str
是string
类的一个成员函数,它用于返回一个指向以空字符结尾的字符数组(C风格字符串)的指针。 c_str
函数的语法如下:
const char* c_str() const;
该函数返回一个指向以空字符结尾的字符数组的指针,这个指针指向string
对象中的字符数据。由于返回的指针是一个指向常量字符的指针,因此无法通过该指针修改string
对象中的字符。同时,返回的指针是一个const
指针,表示不能通过该指针修改字符串的内容。
以下是一个示例,演示如何使用c_str
函数将string
对象转换为C风格字符串:
#include <iostream>#include <string>int main() { std::string str = "Hello World!"; const char* cstr = str.c_str(); std::cout << "C风格字符串: " << cstr << std::endl; return 0;}
输出结果为:
C风格字符串: Hello World!
在上面的示例中,我们将string
对象str
通过c_str
函数转换为一个C风格字符串,并将它输出到控制台上。
c_str
函数在需要将string
对象传递给需要C风格字符串作为参数的函数或方法时非常有用。它可以提供一个与C风格字符串兼容的指针,而无需进行显式的类型转换。
以上是C++中string类对象的一些常见的修改操作方法,你可以根据需要选择合适的方法来修改字符串对象。
C++中的string与C语言字符串的区别
C++中的string
类和C语言中的字符串(C风格字符串)有几个主要区别:
类型:string
是C++中的标准库类,而C语言中的字符串是由字符数组表示的。
动态内存管理:string
类负责管理其内部分配的内存,它会根据需要进行内存的分配和释放。而C语言中的字符串需要手动管理内存,使用malloc
和free
来分配和释放内存。
长度:string
类中的字符串长度可以动态增长或缩小,而C语言中的字符串长度是固定的,需要事先分配足够的内存空间。
函数和操作符:string
类提供了一系列成员函数来处理字符串,例如查找、替换、拼接等操作。而C语言中需要使用一些库函数来完成类似操作,如strlen
、strcpy
、strcat
等。
字符串字面量:C++中的string
类可以直接使用双引号包裹的字符串字面量进行初始化,而C语言中的字符串字面量需要手动创建字符数组。
异常处理:string
类在内部处理内存分配和字符串操作时,会自动抛出异常来处理错误情况。而C语言中的字符串操作通常不提供异常处理机制,需要通过返回值或指针来判断是否发生错误。
综上所述,C++中的string
类提供了更加方便和安全的字符串操作方式,封装了许多底层的操作,提高了代码的可读性和可维护性。但在某些情况下,C语言的字符串仍然是必需的,特别是在需要与C语言库函数或其他C语言代码进行交互的情况下。
string类中的运算符重载
在C++中,string类支持使用"+"运算符来进行字符串的拼接操作。这个操作符允许将两个字符串连接起来产生一个新的字符串。下面是一个示例int main() { std::string str1 = "Hello"; std::string str2 = "World"; std::string result = str1 + str2; str1 = str1 + " string"; std::cout << "Concatenated string: " << result << std::endl; std::cout << str1 << std::endl; return 0;}
在 C++ 中,std::string 类没有重载 operator>> 运算符。operator>> 运算符主要用于输入流 (std::istream) 和基本数据类型之间的输入操作。如果你想要从输入流中读取并存储字符串,可以使用 std::getline() 函数。以下是一个示例:
int main() { std::string str; std::cout << "Enter a string: "; std::getline(std::cin, str);//输入一个字符串并存放到str中 std::cout << "You entered: " << str << std::endl; return 0;}
在上面的示例中,我们使用 std::getline() 函数从 std::cin 输入流中读取一行字符串,并将其存储在 str 变量中。然后,我们将字符串输出到控制台。
请注意,std::getline() 函数会读取整行输入,包括空格和换行符。如果你只想读取一个单词或一段不包含空格的字符串,可以使用运算符 >> 进行输入,如下所示:
int main() { std::string str; std::cout << "Enter a word: "; std::cin >> str;//输入一个字符串并存在str中,遇到空格和回车会停止 std::cout << "You entered: " << str << std::endl; return 0;}
在上面的示例中,我们使用 operator>> 运算符从 std::cin 输入流中读取一个单词,并将其存储在 str 变量中。然后,我们将字符串输出到控制台。
在 C++ 的 std::string 类中,提供了一组关系运算符(relational operators),用于比较两个字符串的大小关系。这些运算符包括: ==:判断两个字符串是否相等,如果相等返回 true,否则返回 false。!=:判断两个字符串是否不相等,如果不相等返回 true,否则返回 false。<:判断一个字符串是否小于另一个字符串,如果小于返回 true,否则返回 false。大于号:判断一个字符串是否大于另一个字符串,如果大于返回 true,否则返回 false。<=:判断一个字符串是否小于或等于另一个字符串,如果小于或等于返回 true,否则返回 false。小于等于:判断一个字符串是否大于或等于另一个字符串,如果大于或等于返回 true,否则返回 false。
这些运算符可以直接用于 std::string 对象之间的比较,例如:
int main(){ std::string str1 = "hello"; std::string str2 = "world"; if (str1 == str2)//判断是否相等 { std::cout << "str1 equals str2" << std::endl; } if (str1 != str2)//是否不相等 { std::cout << "str1 does not equal str2" << std::endl; } if (str1 < str2)//比较大小 { std::cout << "str1 is less than str2" << std::endl; } if (str1 > str2)//同理 { std::cout << "str1 is greater than str2" << std::endl; } if (str1 <= str2) { std::cout << "str1 is less than or equal to str2" << std::endl; } if (str1 >= str2) { std::cout << "str1 is greater than or equal to str2" << std::endl; }return 0;}
请注意,在比较字符串时会按照字典序进行比较,即通过逐个比较字符的 ASCII 值来确定大小关系。
好啦,今天的内容就到这里啦,下期内容预告string类的模拟实现,博主最近比较忙可能更新的会比较慢请见谅
结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。
??️ 这里祝各位接下来的每一天好运连连 ??