C++之字符串

C中的字符串

C语言中不提供字符串类型,因此所谓的字符串不过是一组以’\0’结尾的字符序列。
C语言中通常以char型的数组来存储字符串,如下例:

#include <stdio.h>
#include <string.h>
int main()
{
	char s[] = "Hello World!";
	printf("%s\nLength of s : %d\n  Size of s : %d", s, strlen(s),sizeof(s));
	return 0;
}
Hello World!
Length of s : 12
  Size of s : 13

上例中,strlen()函数用于求字符数组长度,而sizeof关键字用于求字符数组占用的字节数。可以看出,字符串占用的字节数比数组长度大1,这也印证了上面说到的C语言中的字符串实际上是以’\0’结尾的字符数组。

C语言提供了<string.h>来方便程序员处理字符串,<string.h>中主要包含以下用于字符串处理的函数:

函数 函数 函数
strcpy() stricmp () strtec()
strncpy() strerror() strspn()
strcat() strcmpi() strstr()
strchr() strncmp() strtod()
strcmp() strncpy() strtok()
strnicmp() strtol() strlen()
strnset() strupr() strcspn()
strpbrk() swab() strdup()
strrchr()

上述函数的具体用法不在此进行描述。

当然,C++仍旧保留了这种C语言的字符串操作方式,而<string.h>中的相关内容以C++的表现形式被包含于<cstring>中。为了方便描述,本文后面的内容把C语言下的字符串用cstring来表示。

C++中的字符串

C++中除了支持C中的字符数组外,还提供了一个更加强大的string类。但由于string类涉及太多面向对象的内容,这里只作一些简单的讨论。

字符串创建

C++对string的构造函数实现了多个重载,因此有很多不同的方法来定义并初始化一个字符串。下面是几个常用的方式:

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s1;//创建空串
	string s2("Hello World!");          //以cstring作为初值
	string s3(s2);                      //以string作为初值,相当于拷贝
	string s4(s2, 5);                   //取string第5个字符之后的所有字符
	string s5("Hello World!", 5);       //取cstring的前5个字符
	string s6(s2, 6, 5);                //取string第6个字符之后的5个字符
	string s7("Hello World", 6, 5);     //取cstring第6个字符之后的5个字符
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
	cout << "s5 = " << s5 << endl;
	cout << "s6 = " << s6 << endl;
	cout << "s7 = " << s7 << endl;
	return 0;
}
s1 =
s2 = Hello World!
s3 = Hello World!
s4 =  World!
s5 = Hello
s6 = World
s7 = World

这里需要注意的是s4和s5的不同,当分别以string和cstring作为源创建string时,两种重载的第二个参数意义是不同的,前者为起始位置,后者为字符数。

字符元素存取

C++提供了三种方式对string中的字符进行索引,分别为:
1. 下标索引 [ i ]
2. at( i )访问
3. back()/front()访问首字符和末字符。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s("Hello World!");//以cstring作为初值
	cout << s[0] << endl;
	cout << s.at(0) << endl;
	cout << s.front() << endl;
	cout << s.back() << endl;
	return 0;
}
H
H
H
!

字符串赋值

string类重载了“=”操作符,因此可以直接用"="进行赋值,此外,C++还提供了更加灵活的assign()成员函数来对字符串进行赋值。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s1, s2, s3, s4, s5, s6;
	s1 = "Hello World !";//=cstring
	s2 = s1;			 //=string
	s3.assign(s1);		 //assign(string)
	s3.assign("Hello World !");//assign(cstring)
	s4.assign("Hello World !", 5);//assign(cstring, n)	
	s5.assign(s1, 5);		//assign(string, pos)
	s6.assign(12, '-');		//assign(n, char)
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;
	return 0;
}
Hello World !
Hello World !
Hello World !
Hello
 World !
------------

同使用构造函数创建字符串时相同,这里的s4和s5也得到了不同的结果,因此对于ctring和string,assign实现了不同的重载,意义同构造函数。

字符串操作

C++提供了许多对字符串进行操作的方法,包括增、删、查找、替换、交换、属性获取等许多方便的功能。下面就几个常用的方法进行简要的总结。

1.增删操作

string重载了”+=操作符",因此可以利用“+=”来增长字符串。此外,C++还提供了append()和push_back()来对字符串进行增操作,erase()来对字符串进行减操作,clear()来对字符串进行清空等操作。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	cout << "s = " << s << endl;
	s += " I'm";//后面增加字符串" I'm"
	s.append(" C++");//后面增加字符串" C++"
	s.push_back('!');//后面增加'!'字符
	cout << "s = " << s << endl;
	s.erase(5);//删除第5个字符后的所有字符
	cout << "s = " << s << endl;
	s.erase(1,3);//删除第1到3个字符
	cout << "s = " << s << endl;
	s.clear();//清空字符串
	cout << "s = " << s << endl;
	return 0;
}
s = Hello World !
s = Hello World ! I'm C++!
s = Hello
s = Ho
s =

2.查找操作

string类提供了一些用于字符查找和字符串查找的方法,主要有:
find()
rfind()
find_first_of()
find_last_of()
find_first_not_of()
find_last_not_of()

string类对上述6个方法进行了多个重载,可以满足大多数情况下的要求。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World ! Hello World !";
	int pos0 = s.find('l');//查找字符‘l’的位置
	cout << pos0 << endl;
	int pos1 = s.find('l', 10);//从下标10开始查找字符‘l'的位置
	cout << pos1 << endl;
	int pos2 = s.find("World");//查找字符串"World"的位置
	cout << pos2 << endl;
	int pos3 = s.find("World", 10);//从下标10开始查找字符串"World"的位置
	cout << pos3 << endl;
	int pos4 = s.find("World????", 10, 5);//从下标10开始查找字符串"Wordl????"的前五个字符"World"的位置
	cout << pos4 << endl;
	return 0;
}
2
16
6
20
20

这里仅给出了find的用法,其余五个方法的用法类似。
此外,STL中还提供了许多功能强大的查找功能,同样可以对字符串进行操作,这里不展开讨论。

3.子串操作

string类提供了提取字串的方法substr(),用法如下:

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	string s1 = s.substr();    //全部
	string s2 = s.substr(6);   //从下标6开始的所有字符
	string s3 = s.substr(2, 7);//从下标2开始7个字符,不是2到7!
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}
Hello World !
World !
llo Wor

4.属性操作

string类提供了一些关于属性操作的方法,较常用的如下:
size() 返回字符串大小
length() 返回字符串长度,和size()几乎没区别
max_size() 可能的最大大小
empty() 判断字符串是否为空

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s = "Hello World !";
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.max_size() << endl;
	cout << s.empty() << endl;
	return 0;
}

13
13
2147483647
0

字符串流

sstream库中定义了三个类:istringstream、ostringstream和stringstream,分别用来进行字符串流的输入、输出和输入输出操作。

字符串流常用于数据转换字符串的处理,下面分别简单的介绍一下两个功能的实现:

1.数据转换

在C语言中,将float型数据与字符数组之间的相互转换可以这样做:

#include <stdio.h>
int main() {
	char s[12];
	float ft0 = 32.23,ft1;
	sprintf(s, "%f", ft0);//float转字符数组
	sscanf(s, "%f", &ft1);//字符数组转float
	for (int i = 0; s[i] != '\0'; ++i) printf("%c ", s[i]);
	printf("\n%f\n", ft1);
	return 0;
}

当然,在C++中也可以这样做,但C++中提供的字符串流可以提供更强大的功能。下面是一个例子:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
	float data, sum=0;
	string line = "12.34 23.45 34.56 45.67";
    stringstream ss(line);//以string创建字符串流
	//stringstream ss; ss << line;
	while (ss >> data) sum += data;//逐个输出求和
	cout << "sum = " << sum << endl;
	return 1;
}

上例中以字符串"12.34 23.45 34.56 45.67"创建一个字符串流ss,然后依次从字符串流ss中读取数据进行求和,最后输出求和的结果。

下面再举一个数据转换的简单例子:

void float_to_string(string &s, float ft) {
	stringstream ss;
	ss << ft;
	s=ss.str();
	//ss >> s;
}

这个例子通过字符串流将float型数据转换为string,因为不用担心string的长度问题,所以也就不用担心是否会溢出。将其他类型转换为string的做法也是一样的,通过泛型编程可以实现任意数据类型之间的转换。

2.输入和输出

字符串流还可以用于输入与输出。上面提到,istringstream、ostringstream和stringstream,分别用来进行字符串流的输入、输出和输入输出操作。我们利用stringstream可以很方便的对从标准输入读取的数据进行处理。将上面求和的例子稍作修改如下:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
	float data, sum = 0;
	string line;
	stringstream ss;
	while (getline(cin, line)) {
		ss << line; sum = 0;//流入
		while (ss >> data) sum += data;//流出求和
		cout << "sum = " << sum << endl;//打印
		ss.clear();//清空
	}
	return 1;
}

上例中,使用string类提供的getline可以从某个输入流(cin)中读取一行数据赋值给字符串。利用字符串流来临时保存数据并且进行数据转换,然后逐个读出求和。

总结

(1) C++仍然保留了C语言中字符数组的机制。
(2) C++还提供更加灵活且强大的string类。
(3) string类提供了非常灵活的创建、操作方法。
(4) 字符串流可以很方便的用于数据转换和数据处理。

猜你喜欢

转载自blog.csdn.net/weixin_43374723/article/details/83957543