文章目录
- 一. STL
- 1.概念
- 2.版本
- 二. string类
- 2.1 为什么学习string类
- 2. 标准库中的string类
- 2.2.1 构造(7个)
- 2.2.2 对string类对象进行访问和修改
- (1)operator[]
- (2)迭代器
- 1.迭代器的使用
- 2.迭代器的价值(list)
- (3)为什么有operator[]之后还需要迭代器
- 补充的小知识点:auto
- 补充的小知识点:范围for
一. STL
1.概念
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
2.版本
- 原始版本
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本–所有STL实现版本的始祖。
P. J. 版本
由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。
RW版本
由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般。
SGI版本
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。我们后面学习STL要阅读部分源代码,主要参考的就是这个版本。
二. string类
2.1 为什么学习string类
- C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
2. 标准库中的string类
- 首先,我们要学会看文档
string是在STL之前就设计出来了,所以比较复杂,总共有100多个接口(什么是接口,就是提供给我们,可以去调用的),但是我们只需要记住重要的20多个,剩下的使用时查询即可。
- 使用string类的时候,必须包含头文件
#include<string>
以及using namespace std
(这个可以选择不写) - string实际上是个模板,但是它的参数一定确定了,so我们不太用关注它。
- 先使用默认构造,构造一个空的字符串。
std::string str1;
2.2.1 构造(7个)
我们可以先简单看一看接口,进行猜测(它的参数的名字都是有意义的,所以猜测的还是很接近的)。具体的内容看下面的接口介绍
记住:initialize是初始化
规定:string的结尾一定是‘\0’结尾
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{//1.创建空的字符串string str1; //构造空的string类对象str1//2.填充:string(size_t n, char c);string str2(5, 'r'); //用5个'r'初始化cout << str2 << endl;//3.copy--->string(const string & str);string str3(str2); //用str2初始化str3cout << str3 << endl;//4.from c-string--->string(const char* s);char s1[5] = "abcd";string str4(s1); //用字符串s1初始化str4cout << str4 << endl;//5.将字符串s的地址传过来,复制n个它的字符:string (const char* s, size_t n);char s[4] = { 'a','b','c','d' };string str5(s, 3); //用字符串s的前三个字符初始化str5cout << str5 << endl;//注意:字符串传递过去默认也是首地址string str6("abcd", 3); //常量(const)字符串的类型的地址是const char*cout << str6 << endl;//6.substring--->string(const string & str, size_t pos, size_t len = npos);string str7("abcdefghijklmn",14);string str8(str7, 3, 9);cout << str8 << endl;//如果没有写复制几个字符,则拷贝到str7结束string str9(str7, 3);cout << str9 << endl;return 0;
}
2.2.2 对string类对象进行访问和修改
(1)operator[]
std::string::operator[]
的底层大致意思是:
class string
{
public:char& operator[](size_t pos){assert(pos < _size);//防止越界return _str[pos];}
private:char* _str;size_t _size;size_t _capacity;
};
它是用来返回pos这个位置的字符的别名。
接下来,如何使用operator方括号呢?
- 可以用来修改某个位置的字符(因为是引用返回,so可直接修改)
#include<stdio.h>
#include<iostream>
#include<assert.h>
#include<string>
using namespace std;
int main()
{//char& std::string::operator[](size_t pos)string str1("abcdefg");//str1.operator[](0)='p';str1[0] = 'p';std::cout << str1 << std::endl;return 0;
}
- 可用来遍历string的每个字符
int main()
{string str1("abcdefg");for (size_t i = 0; i < str1.size(); i++){cout << str1[i] << " ";}return 0;
}
循环遍历,将每个字符都加1
int main()
{string str1("abcdefg");for (size_t i = 0; i < str1.size(); i++){//将所有的字符都加1str1[i]++;}
- 可以很好的防止越界
这个返回值不可以被修改
(2)迭代器
1.迭代器的使用
(像指针一样的东西,但并不是指针)
- 迭代器的使用
begin()返回第一个位置的迭代器
end()指的是最后一个有效字符的下一个位置(即\0)的迭代器(\0是标识字符,不是有效字符)
#include <iostream>
#include<stdio.h>
#include<assert.h>
#include<string>
using namespace std;
int main()
{string str1("hello world");//在string这个类里面,有iterator这个类型
// 类域 :: 类型 定义的对象 begin()返回第一个位置的迭代器string::iterator it1 = str1.begin();while (it1 != str1.end()) //end()指的是最后一个字符的下一个位置// 不到最后一个\0{cout << *it1 << " "; //it1是地址it1++; //++就到下一个地址了,在解引用就是下一个字符}//在字符串打印完之后,换行cout << endl;return 0;
}
同样的,在遍历读取的时候,也可以修改数据。
while (it1 != str1.end())
{(*it1)++;cout << *it1 << " "; it1++;
}
如果像倒着遍历,则使用反向迭代器
2.迭代器的价值(list)
(链表的那个list,带头双向循环的链表)
list的遍历和修改只能借助迭代器,push_back等等
#include <iostream>
#include<stdio.h>
#include<assert.h>
#include<string>
#include<list>
using namespace std;
int main()
{list<int> lt1;lt1.push_back(9);lt1.push_back(8);lt1.push_back(7);lt1.push_back(6);//定义list的迭代器list<int>::iterator it1 = lt1.begin();while (it1 != lt1.end()){cout << *it1 << " ";it1++;}return 0;
}
(3)为什么有operator[]之后还需要迭代器
下标[]确实很方便,但并不是通用的。它只适用于string和vector(它们的底层是连续的物理空间)。
像链表等等,它们的结点的地址并没有什么大小关系。
补充的小知识点:auto
auto声明的变量:变量的类型由编译器在编译时期推导而得。(根据右边的值推导左边变量的类型)
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
int main()
{int i = 9;int j = i;//所以j的类型是int//用auto自动推导类型auto m = j; //m的类型是intauto n = 1.2;//n的类型是doublereturn 0;
}