一. 历史遗留问题
- C语言不支持真正意义上的字符串
- C语言字符串数组和一组函数实现字符串操作
- C语言不支持自定义类型,因此无法获得字符串类型
解决方案:
- 从C到C++的进化过程引入了自定义类型
- 在C++中可以通过类完成字符串类型的定义
问题:
C++中的原生类型系统是否包含字符串类型?
二. 标准库中的字符串类
- C++语言直接支持C语言的所有概念
- C++语言中没有原生的字符串类型
- C++标准库提供了string类型
(1)string直接支持字符串连接
(2)string直接支持字符串的大小比较
(3)string直接支持子串查找和提取
(4)string直接支持字符串的插入和替换
字符串类的使用示例:
#include <iostream>
#include <string>
using namespace std;
//字符串排序,基于字典顺序
void string_sort(string a[], int len)
{
for(int i = 0; i<len; i++)
{
for(int j = i; j<len; j++)
{
if(a[i] > a[j])
{
swap(a[i], a[j]);
}
}
}
}
//字符串连接
string string_add(string a[], int len)
{
string ret = "";
for(int i = 0; i<len; i++)
{
ret += a[i] + ";" ; //字符串类中进行了操作符重载
}
return ret;
}
int main()
{
string sa[7] =
{
"Hello World",
"Super man",
"C#",
"Java",
"C++",
"Python",
"TypeScript"
};
string_sort(sa, 7);
for(int i = 0; i<7; i++)
{
cout << sa[i] << endl;
}
cout << endl;
cout << string_add(sa, 7) << endl;
return 0;
}
编译结果:
C#
C++
Hello World
Java
Python
Super man
TypeScript
C#;C++;Hello World;Java;Python;Super man;TypeScript;
三. 标准库中的字符串类
字符串与数字的转换:
1.标准库中提供了相关的类对字符串和数字进行转换
2.字符串流类(sstream)用于string的转换
1) < sstream > – 相关头文件
2)istringstream – 字符串输入流
3)ostringstream – 字符串输出流
使用方法:
1.string --> 数字
istringstream iss(“123.45”);
double num;
iss >> num;
2. 数字 --> string
ostringstream oss;
oss << 543.21;
string s = oss.str();
字符串和数字的转换示例:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
//字符串转数字
#define TO_NUMBER(s, n) (istringstream(s) >> n)
/*
bool to_number(const string& s, int& n) //考虑模板
{
istringstream iss(s);
return iss >> n;
}
*/
//数字转字符串
#define TO_STRING(n) (((ostringstream&)(ostringstream() << n)).str())
//强制类型转换成字符串输出流
/*
string to_string(int n) //考虑模板
{
ostringstream oss;
oss << n;
return oss.str();
}
*/
int main()
{
double n = 0;
if( TO_NUMBER("125.7896", n))
{
cout << n << endl;
}
string s = TO_STRING(123456);
cout << s << endl;
return 0;
}
/*
原始版本:
int main()
{
istringstream iss("123.45");
double num;
iss >> num; // if (iss >> num)
cout << num << endl; //123.45
ostringstream oss;
oss << 543.21; // oss << 543 << "." << 21;
string s = oss.str();
cout << s << endl; //543.21
return 0;
}
*/
四. 面试题解析
1.字符串循环右移
问题 :abcdefg循环右移3位后得到efgabcd
代码示例:
#include <iostream>
#include <string>
using namespace std;
string right_func(const string& s, unsigned int n) //字符串引用,右移n位
{
string ret = "";
unsigned int pos = 0; //找到位置
//abcdefg==>3 efg abcd 右移三位的字符串子类提取出来
//abc==> 1 cab
//abc==> 3 abc ==> 1 cab 右移一位和右移四位效果相同
n = n % s.length(); // 取余,取多少位都是合法的
pos = s.length() - n; //查位置
ret = s.substr(pos); //查子串,将后面的部分提取出来
ret += s.substr(0, pos); //提取子串,从0开始,到pos结束
//abcdefg ==> 8
//abcdefg ==> 1
//8 % 7 ==> 1
// 7-1==> 6
//abcdef g
// ret ==> g
//ret = g+ abcdef
//ret = gabcdefg
return ret;
}
/*
如果转换函数替换成操作符重载
string operator >> (const string& s, unsigned int n)
*/
int main()
{
string r = right_func("abcdefg", 8);
/*
操作符重载的方式
string r = "abcdefg";
string r = (s>>3);
*/
cout << r << endl;
return 0;
}
运行结果
gabcdef
小结:
应用开发中大多数的情况都在进行字符串处理
C++中没有直接支持原生的字符串类型
标准库中通过string类支持字符串的概念
string类支持字符串和数字的相互转换
string类的应用使得问题的求解变得简单
五 . string类型使用注意事项
- 应用示例1:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "12345";
const char* p = s.c_str();
cout << p << endl; //预计输出 12345
s.append("abced"); // p 成为了野指针
cout << p << endl; //预计输出 12345abcde
return 0;
}
输出结果:
12345
12345
结果不是12345abcde,插入失败。
string s ,s是字符串类。
const char* p = s.c_str();
s.c_str()将返回一个C语言方式的字符串。
说明这段代码混合了C语言和C++的编程方式。
将 cout << p << endl;
改成:
cout << s<< endl;
j结果就是12345abcde
问题分析:
在string类的内部有一个字符指针m_cstr,当s="12345"时(赋值或初始化),字符指针将指向一个堆空间,并且这个堆空间存储了这个字符串。
p=s.c_str();通过一个指针指向这个堆空间,p这个字符指针所代表的字符串就是12345
s.append(“abced”);字符指针所指向的堆空间变成了新的内容。但是新的字符指针并没有指向原来的地址。
也就是说string对象内部维护的char指针,在运行时改变了,原来的指针会被释放,释放后char p就是一个野指针了。
避免方法:不要混合C语言和C++编程思想。
- 应用示例2:
#include <iostream>
#include <string>
using namespace std;
int main()
{
const char* p = "12345";
string s = "";
s.reserve(10); //将字符串对象内部的数据指针的大小变成10个字节
// 不要使用 C 语言中的方式操作 C++ 中的字符串
for(int i=0; i<5; i++)
{
s[i] = p[i];
}
if(!s.empty())
{
cout << s << endl;
}
return 0;
}
无输出
如果
for(int i=0; i<5; i++)
{
cout << s[i] << endl;
}
将输出1 2 3 4 5
for前后m_length始终为0,字符串本身长度没有变化,仍然为空串
解决方法,不需要for循环,避免指针的使用
const string p = "12345";
string s = "";
s = p
cout << s << endl;
小结:
string类通过一个数据空间保存字符数据
string类通过一个成员变量保存当前字符串的长度
C++开发是进来避开C语言中惯用的编程思想