String
一、string类字符串的介绍
在程序设计中, 字符串的使用十分频繁, C语言类型字符串(简称C-串)在使用与字符串的处理上较为复杂, C++为了在程序设计中更加方便的使用字符串特新增了一种string类型的字符串。
string类字符串为STL(Standard Template Library, 标准模板库)中的一种自定义的数据类型, 相对于C-串来说string类型串具有一些明显的优势, 首先, 它在内存使用上是自动的, 需要多少, 开辟多少, 并且能够根据字符串大小的变化自动调整所开辟的内存; 此外, string串还提供了大量的方法以便更好的完成对字符串的各种操作。
二、声明一个string型字符串
同普通变量一样, string类型的字符串在使用前也需进行声明, 并且也可以对其进行相关的初始化操作, 相关的声明以及初始化方法如下:
- string s; //声明一个string型字符串s
- string s(const string &str); //声明string型字符串s并用另一个string型字符串str对其进行初始化
- string s(const string &str, size_type n); //将字符串str中起始位置n后的字符串作为字符串s的初始值
- string s(const string &str, size_type n, size_type m); //将字符串str位置n起, 长为m的部分的字符作为字符串s的初始值
- string s(const char *cs) ; //将C-串cs作为string串s的初始值
- string s(const char *cs, size_type n); //将C-串cs的前n个字符作为string串s的初始值
- string s(const char *cs, size_type n, size_type m); //将C-串cs中位置n起, 长为m的部分的字符作为字符串s的初始值
- string s(size_type num, char c); //初始化字符串值为num个c字符
- string s(iterator begin, iterator end); //将区间[begin, end]内的字符作为字符串s的初始值
用双引号括起来的一串字符称为字符串, 例如 "abc"、"Hello, world!"。C++延续了C语言中的做法, 将字符串使用字符型(char)一维数组来存放, 在存放字符串时, 编译器会在字符串结束的位置自动添加"\0", "\0"是 ASCII 码值为0的转义符, 它是字符串的结束标志, 对于这种存放方式, 称它为字符数组更为合适。
在字符串中, 有效字符的个数称为字符串的长度, 例如字符串"abc"的长度为3, 但它所占的字节数为4字节, 因为编译器会在结束时自动添加一个 "\0", 也就是说, 定义长度为n的字符型一维数组只能存放下n-1个字符, 否则将无法存放结束标识"\0", 在某些情况下将导致字符串无法正常使用, 严重时可导致一些未知的错误。
1>.逐个字符进行初始化.
2>. 使用字符串常量初始化方式, 例如:
char a[6] = {"Hello"} ;
由于编译器会自动在字符串末尾添加'\0'字符, 所以字符数组a的各元素存放的内容依次为:'H', 'e', 'l', 'l', 'o', '\0'。
在上述初始化形式中, 大括号可以省略, 并且在初始化时数组元素的长度声明也可以省略, 编译器会根据初始化值中的字符个数(包括'\0')自动计算数组所需的元素个数, 以下声明都是正确的:
2>. 使用字符串常量初始化方式, 例如:
char a[6] = {"Hello"} ;
由于编译器会自动在字符串末尾添加'\0'字符, 所以字符数组a的各元素存放的内容依次为:'H', 'e', 'l', 'l', 'o', '\0'。
在上述初始化形式中, 大括号可以省略, 并且在初始化时数组元素的长度声明也可以省略, 编译器会根据初始化值中的字符个数(包括'\0')自动计算数组所需的元素个数, 以下声明都是正确的:
char a[6] = "Hello" ; char a[] = "Hello" ;
字符串的输入
使用cin进行输入主要使用在字符串输入过程没有空白符(空格、tab)的情况下, 当存输入过程中按下空格键或tab键时cin就会默认输入结束, 当再按下回车进行时, 也只存空白符前面的内容。
如果输入字符超出范围,则会内存错误
1>. cin.get() 函数
如果想连空格一起输入到字符数组中可以使用 cin.get() 函数
- #include<iostream>
- using namespace std ;
- int main()
- {
- char a[50] ;
- cin.get(a, 50) ; //输入字符串a
- cout<<a ; //输入后进行输出
- return 0 ;
- }
2>. cin.getline() 函数
cin.getling() 函数也可起到输入一行并包含空格的作用
- #include<iostream>
- using namespace std ;
- int main()
- {
- char a[50] ;
- cin.getline(a, 50) ; //输入字符串a
- cout<<a ; //输入后进行输出
- return 0 ;
- }
cin.get() 与 cin.getline() 的不同之处
虽说这两个函数都能够用来输入带有空格的字符串, 但还是有不同之处的, 两个函数都用于读入一行输入, 直至遇到换行符, 但是 getline() 函数会将换行符从输入队列中提取出来并抛弃掉, 而 get() 函数不会将换行符从输入队列中提取并抛弃掉, 这乍一看区别不大, 实际上在有连续几行的输入时这将会对输入结果产生很大的影响。
#include<iostream> using namespace std ; int main() { char a[50], b[50] ; //定义两个字符数组 cout<<"请输入字符串一:" ; cin.get(a, 50) ; //输入字符串a cout<<"请输入字符串二:" ; cin.get(b, 50) ; //输入字符串b cout<<a ; //输入后进行输出 cout<<b ; return 0 ; }
请输入字符串一:hello my name 请输入字符串二:hello my name Process returned 0 (0x0) execution time : 7.031 s Press any key to continue.
如果我们自己编译运行后可以发现, 当我们输入完毕第一行字符串, 还没来得及输入第二行时程序就已经运行结束了, 这就是因为 get() 函数会将换行符留在输入队列所致, 当输入完第一行时我们按下回车, get 函数获取输入的内容, 并把换行符留在了输入队列, 当执行到 cin.get(b, 50) ; 时正好他得到的第一个字符不是用户的输入, 而是遗留在上一次输入的换行符, 这样它就误认为用户输入以及结束了而自动结束输入。
由于 get() 函数不会抛弃输入队列中的换行符, 因此在使用 get() 函数进行输入时可以使用一个较为完善的输入方式:
cin.get(数组名, 允许长度).get() ;
这样当第一个 get() 获取到用户输入并存放到字符数组后, 第二个 get() 会负责把换行符提取出来, 相当于抛弃掉, 这样在下一行使用函数进行输入时就不会再出现还没有输入程序就已经默认为输入已经结束的情况。
三、字符串处理函数
数组不能整体的进行加减乘除比较等操作, 例如以下操作都是错误的:
char a[50] = "Hello" ; char b[50] = "world" ; if(a == b) //错误! a += b ; //错误! a = a + "abc" ; //错误!
可以看出, 在字符串操作上比较的不方便, 为了方便编程的进行, 在C++的标准库里给我们提供好了一些能够对字符串方便操作的函数, 我们只需要调用函数就行了, 要使用这些函数, 需要包含头文件 cstring
#include<cstring>
一些常用的字符串处理函数如下:
操作 | 函数原型 | 说明 |
取得字符串长度 | size_t strlen(数组名) | 不包括结束标志'\0' |
将源字符数组中的字符串复制到目标数组 | char *strcpy(目标数组, 源数组名) | 目标数组的大小应不小于源字符串 |
字符串大小比较 | int strcmp(字符串1, 字符串2) | 相等返回0, 字符串1大于字符串2返回正数, 否则返回一个负数 |
将两个字符串连接起来 | char *strcat(字符串1, 字符串2) | 将字符串2连接到字符串1后面, 字符串1必须有足够的剩余位置容纳字符串2 |
将字符串中的小写字符全部转成大写 | char *strupr(数组名) | |
将字符串中的大写字符全部转成小写 | char *strlwr(数组名) |
需要说明的是关于字符串的大小比较, 字符串的大小比较不是比较其长度, 而是比较从左向右依次比较每个字符的ASCII的值的大小, 如果第一个字符串的第一个字符的ASCII值大于第二个就说明字符串1大于字符串2, 依次类推。
字符串处理函数使用举例: 测量字符串的长度并将该字符串全部转成大写后输出:
- #include<iostream>
- #include<cstring>
- using namespace std ;
- int main()
- {
- char a[50] = "Hello, I am C++ !" ;
- int n ; //用来保存字符串的长度值
- n = strlen(a) ; //测量字符串长度
- cout<<n<<endl ; //输出长度
- strupr(a) ; //将字符串全部转为大写
- cout<<a ; //输出转换后的字符串
- return 0 ;
- }
三、字符串的输入输出
除了已经学习的 ">>"、"cin.get()"和"cin.getline()"对字符串进进行输入外, string头文件中还定义了getline()函数用于输入string字符串。
getline的函数原型如下:
istream& getline ( istream &is , string &str , char delim ); //形式一 istream& getline ( istream& , string& ); //形式二
getline的第一个函数参数为输入流对象; 第二个为待输入的字符串; 第三个是可选参数, 为自定义的终止符, 当输入到该字符时表示输入完成, 程序只保存终止符前的输入内容, 当省略时默认以'\n'为终止符。需要说明的是, 终止符不会保存到输入的字符串中去。
示例:
1 #include<iostream> 2 3 using namespace std ; 4 5 int main() 6 { 7 string s; 8 getline(cin, s) ; //使用默认的'\n'作为终止符 9 cout<<s<<endl ; 10 11 getline(cin, s, '!') ; //以'!'作为终止符 12 cout<<s<<endl; 13 14 return 0 ; 15 }
输出:
hello ↙键盘输入 hello hwllo!world! ↙键盘输入 hwllo Process returned 0 (0x0) execution time : 25.375 s Press any key to continue.
四、string串的基本使用方法
在string类型的字符串中, 字符串的处理得到极大的简化, 例如原本在C-串中的复制操作, 需要借助string.h中的strcpy()函数才能完成, 而在string串中只需一个'='进行赋值就能完成。更具体的如下:
1>. 复制
string s1 = "hello" ; string s2 = s1 ; //复制
2>. 连接
string s1 = "hello" ; string s2 = "world" ; s1 += s2 ; //连接
3>. 比较
string s1 = "hello" ; string s2 = "world" ; if(s1 < s2) cout<<"s1 < s2" ; //比较
4>. 倒置串
string s = "hello" ; reverse(s.begin(), s.end()) ; //需要包含algorithm头文件, #include<algorithm>
5>. 查找串
string s = "hello" ; cout<<s.find("ll") ; //返回子串第一次出现的位置
6>. 替换
string s = "hello" ; s.replace(0, 2, "aaa") ; //将字符串s中下标0-2部分字符串替换为"aaa"
五、string的更多方法
由于string类型的字符串自身提供的方法太多, 这里不能一一详述, 只选择一些常用的来进一步说明。
1>. 获取字符串状态
s.size() //返回字符串大小
s.length() //返回字符串长度
s.max_size() //返回字符串最大长度
s.clear() //清空字符串
s.empty() //判断字符串是否为空
2>. 修改字符串
①. append - 追加 string s = "hello" ; s.append("world") ; //将"world"追加到s中 ②. push_back - 追加字符到字符串 string s = "hello" ; s.push_back('!') ; //将'!'追加字符到字符串s中 ③. insert - 插入 string s = "hello" ; s.insert(2, "www") ; //将字符串"www"插入到字符串s中, 插入位置为2 ④. erase - 从字符串中擦除一些字符 string s = "hello" ; s.erase(1, 2) ; //从下标为1处向后擦去2个字符 ⑤. swap - 与另一字符串交换内容 string s1 = "hello" ; string s2 = "world" ;s1.swap(s2) ; //将s1与s2中的字符串进行交换
find:
size_type find( const basic_string &str, size_type index );//返回str在字符串中第一次出现的位置(从index开始查找)
size_type find( const char *str, size_type index );//返回str在字符串中第一次出现的位置(从index开始查找)
size_type find( const char *str, size_type index, size_type length );//返回str在字符串中第一次出现的位置(从index开始查找,长度为length)
size_type find( char ch, size_type index );//返回字符ch在字符串中第一次出现的位置(从index开始查找)
at函数
reference at( size_type index );//at()函数返回一个引用,指向在index位置的字符. 如果index不在字符串范围内, at() 将报告"out of range"错误,并抛出out_of_range异常
begin函数
iterator begin();//begin()函数返回一个迭代器,指向字符串的第一个元素
end函数
iterator end();//返回一个迭代器,指向字符串的末尾(最后一个字符的下一个位置)
c_str函数
const char *c_str();//返回一个指向正规C字符串的指针, 内容与本字符串相同
capacity函数
size_type capacity();//返回在重新申请更多的空间前字符串可以容纳的字符数. 这个数字至少与 size()一样大
copy函数
size_type copy( char *str, size_type num, size_type index );//拷贝自己的num个字符到str中(从索引index开始)。返回值是拷贝的字符数
data函数
const char *data();//返回指向自己的第一个字符的指针
empty函数
bool empty();//如果字符串为空则empty()返回真(true),否则返回假(false)
get_allocator函数
allocator_type get_allocator();//返回本字符串的配置器
length函数
size_type length();//返回字符串的长度. 这个数字应该和size()返回的数字相同
max_size
size_type max_size();//返回字符串能保存的最大字符数
rbegin函数
rbegin();//返回一个逆向迭代器,指向最后一个字符
rend函数
rend();//返回一个逆向迭代器,指向第一个元素的前一个位置
reserve函数
reserve( size_type num );//保留一定容量以容纳字符串(设置capacity值)
resize函数
void resize( size_type num );//改变本字符串的大小到num, 新空间的内容不确定
void resize( size_type num, char ch );//也可以指定用ch填充
size函数
size();//返回字符串中字符的数量
substr函数
basic_string substr( size_type index, size_type num = npos );//返回本字符串的一个子串,从index开始,长num个字符。如果没有指定,将是默认值 string::npos。这样,substr()函数将简单的返回从index开始的剩余的字符串
swap函数
void swap( basic_string &str );//把str和本字符串交换