C语言中的字符串 C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP(面向对象编程)的思想,而且底层空间需要用户自己管理,稍不留神可 能还会越界访问。
与C语言的中字符串相比较
string的本质是字符数组 可以扩容 可以增删查改
string表示的是字符串的字符串类
这里可以看到string是一个类模版 string是一个默认管理char的数组 但是它也可以管理其他的
如
是这里的wchar_t是两个字节
string的构造
1.string()
2.string(const char* s)
3.string(const string&s) 比较基础的三个构造
void string1()
{
string s;//默认构造一个空的string类
string s1("hello world");//带参构造
string s2(s1);//拷贝构造
cout << s << endl; //重载流插入
cout << s1 << endl;
cout << s2 << endl;
cin >> s;//重载流提取
cout << s << endl;
}
执行结果
这里中文也是可以正常放入的
4.string (const string& str, size_t pos, size_t len = npos);
void string2()
{
string s1("hello world");//带参构造
string s2(s1, 3, 5);//部分访问构造 从s1中的第三个位置之后取五个字符进行构造
cout << s1 << endl;
cout << s2 << endl;
}
这里的npos的真实内容是指-1的补码 也就是大概42亿
如果第三个参数位置不写 则会自动替换为npos(缺省参数) 也就是要向后访问42亿个字节
这是不可能的 也就是想表达的是之后有多少就拷贝多少
例子:
如果第三个参数给的太大 甚至字符串总长都不够访问 那么就也是有多少访问多少
5.string (const char* s, size_t n);
void string3()
{
string s1("hello world", 5);
cout << s1 << endl;
}
6.string (size_t n, char c);
void string4()
{
string s1(10,'x');
cout << s1 << endl;
}
string的析构是自动调用的 平时不用管析构
string的赋值
支持3种 string赋值给string 字符串赋值给string char赋值给string
void string5()
{
string s1 = "hello world";//隐式类型转换
//中间会产生临时变量 具有常性
const string& s2 = "hello world" ;//引用这种需要用const修饰
}
应用:
通过这种方式可以更方便的去调用函数
string 中表示字符串有效长度的有size()和length()
这两者没有区别 功能是相同的
void string6()
{
string s1("hello world");
cout << s1.size()<<endl;
cout << s1.length() << endl;
}
那么为什么会有两个 相同功能的 这是string比stl先出 当时string用的是length 但后来stl出现后 又统一设立了size 所以size在stl中时通用的 而length则是string中独有的
无论是size还是length他们访问的都是有效长度 在string中的字符串是不包括尾部的斜杠0的
string的遍历:
访问string中的每个成员用[]
传引用返回具有两个意义
一 减少拷贝
二 可以修改返回对象
如果是普通的传值返回 那么就只能去访问单前位置的内容 而不能进行修改 形参不会影响实参
而传引用返回都指向共同一个空间 一经修改 那么实参也会发生改变
其中的assert还可以对越界访问进行及时检查
这里重载了两个版本出来 其中const修饰的版本 对于const和非const的 string是都可以调用的
而第一个非const修饰的版本 则只能修饰非const 的string const string会造成权限的扩大
而在两个版本都重载的时候 系统会自动匹配最适合的版本 即const调用const版本 非const调用非const版本
第一种遍历 :下标+[]遍历 这种可以修改可以访问
void string7()
{
string s1 = "hello world";
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
}
第二种遍历:通过迭代器进行遍历 也可以进行修改
void string7()
{
string s1 = "hello world";
/*for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;*/
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
}
其中begin 和end 都是string的成员函数 begin()返回的string字符串数组中的第一个成员
end()返回的字符串数组的有效字符最后一个成员的下一位
迭代器和方括号比起来明显是方括号好用
但是只有string和vector支持方括号 而迭代器是可以全部支持的
第三种范围for遍历 底层角度就是迭代器
void string7()
{
string s1 = "hello world";
/*for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;*/
/*string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;*/
for (auto e:s1)
{
cout << e << " ";
}
cout << endl;
}
void string7()
{
const string s1 = "hello world";
string::const_iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << (*it1) << " ";
++it1;
}
cout << endl;
}
这里也是有两种版本
iterator 可读可写
const_iterator 只读 保护指向迭代器的内容不能写
const iterator 则是迭代器本身不能写
这里也可以使用auto
rebegin和rend与begin和end的位置是反的 rbegin是在容器有效数据的下一个位置 而rend是在容器有效数据的第一个位置
其中rbegin也分const修饰和非const修饰版本
对字符串数组进行按字典序排序
这里需要用到algorithm库中的sort函数模版 针对所有容器
范围要求是左闭右开
void string8()
{
string s1 = "hello world";
sort(s1.begin(),s1.end());
auto e = s1.begin();
while (e != s1.end())
{
cout << *e << " ";
++e;
}
cout << endl;
}
string的增删
push_back
这里空间不够就会进行扩容
void string9()
{
string s1 = "hello world";
cout << s1 << endl;
s1.push_back('x');
cout << s1 << endl;
}
插入一串数据
void string9()
{
string s1 = "hello world";
cout << s1 << endl;
s1.push_back('x');
cout << s1 << endl;
s1.append("yyyyyyyyy?");
cout << s1 << endl;
}
最好用的是重载的一个运算符加等
void string9()
{
string s1 = "hello world";
cout << s1 << endl;
s1.push_back('x');
cout << s1 << endl;
s1.append("yyyyyyyyy?");
cout << s1 << endl;
string s2 = "8888888";
s1 += 'y';
s1 += "6666666";
s1 += s2;
cout << s1 << endl;
}