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) 字符串流可以很方便的用于数据转换和数据处理。