一些常用的网站,seo 整站优化,农业技术推广网站,谷雨网页设计作业目录
1、认识string类
2、标准库中的string类
2.1、string类的常见接口
2.1.1、构造与赋值重载
2.1.2、迭代器
2.1.3、容量
2.1.4、访问
2.1.5、修改
2.1.6、字符串操作
2.1.7、成员常量
2.1.8、非成员函数
2.1.9、转换函数
2.2、vs和g下的string
2.2.1、vs下的s…目录
1、认识string类
2、标准库中的string类
2.1、string类的常见接口
2.1.1、构造与赋值重载
2.1.2、迭代器
2.1.3、容量
2.1.4、访问
2.1.5、修改
2.1.6、字符串操作
2.1.7、成员常量
2.1.8、非成员函数
2.1.9、转换函数
2.2、vs和g下的string
2.2.1、vs下的string
2.2.2、g下的string
3、OJ题
3.1、仅仅反转字母
3.2、第一个出现一次的字符
3.3、最后一个单词的长度
3.4、字符串是否回文
3.5、字符串相加
4、模拟实现
5、补充 1、认识string类
C语言中字符串是以\0结尾的一些字符的集合为了操作方便C标准库中提供了一系列字符串的库函数 但是这些库函数与字符串是分离开的不太符合面向对象的思想而且底层空间需要用户自己管理稍不留神可能还会越界访问。
在OJ题中有关字符串的题目基本以string类的形式出现而且在常规工作中为了简单、方便、快捷基本都使用string类很少有人去使用C库中的字符串操作函数。
2、标准库中的string类
string类是basic_string模板类的一个实例它使用char来实例化basic_string模板类。这个类独立于所使用的编码来处理字节string 类可以存储多字节或变长字符序列但在操作时是基于字节而非字符的。
string类的文件介绍
2.1、string类的常见接口
只讲解最常用的接口对其他的接口感兴趣的可以点击string类文件的介绍查看。
2.1.1、构造与赋值重载
string(); // 构造空的string类对象即空字符串
string (const string str); // 用string对象构造string对象
string (const char* s); // 用C式字符串构造string对象
string (size_t n, char c); // 用n个c构造string对象
string operator (const string str); // 赋值重载
string operator (const char* s);
string operator (char c);
2.1.2、迭代器
// 正向迭代器
iterator begin(); // 返回第一个位置
iterator end(); // 返回第一个位置的下一个位置const_iterator begin() const;
const_iterator end() const; // 反向迭代器
reverse_iterator rbegin(); // 返回最后一个位置
reverse_iterator rend(); // 返回最后一个位置的上一个位置const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
注关于迭代器的原理可以看看下面的string的模拟实现。
例如
int main()
{string s1;string::iterator t1 s1.begin();while (t1 ! s1.end()){cout *t1;t1;}cout endl;string s2(hello world);string::iterator t2 s2.begin();while (t2 ! s2.end()){cout *t2;t2;}cout endl;string s3(s2);string::iterator t3 s3.begin();while (t3 ! s3.end()){cout *t3;t3;}cout endl;string s4(10, a); string::iterator t4 s4.begin();while (t4 ! s4.end()){cout *t4;*t4 1;t4;}cout endl;const string s5(s2);string::const_reverse_iterator t5 s5.rbegin();while (t5 ! s5.rend()){cout *t5;t5;}cout endl;string s6;s6 s4;string::const_iterator t6 s6.begin();while (t6 ! s6.end()){cout *t6;t6;}cout endl;return 0;
}
2.1.3、容量
size_t size() const; // 返回有效字符长度
size_t length() const; // 返回有效字符长度
void resize (size_t n); // 将有效字符的个数改为n个
void resize (size_t n, char c); // 将有效字符的个数改成n个多出的空间用字符c填充
size_t capacity() const; // 返回空间的总大小
void reserve (size_t n 0); // 预留空间
void clear(); // 清空字符串
bool empty() const; // 判断是否为空是返回true否返回false
注意
1、size()与length()方法底层实现原理完全相同引入size()的原因是为了与其他容器的接口保持一 致一般情况下基本都是用size()。
2、clear()只是将string中有效字符清空不改变底层空间大小。
3、resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个不同的是当字符个数增多时resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。
注意resize在改变元素个数时如果是将元素个数增多可能会改变底层容量的大小如果是将元素个数减少底层空间总大小不变。
4、reserve(size_t n0)为string预留空间不改变有效元素个数当reserve的参数小于string的底层空间总大小时reserver不会改变容量大小。
例如
int main()
{string s1(hello world);cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;s1.clear();cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;cout s1.empty() endl;s1 i am a student;cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;s1.reserve(100);cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;s1.resize(50, o);cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;string::iterator t1 s1.begin();while (t1 ! s1.end()){cout *t1;t1;}cout endl;return 0;
}
2.1.4、访问
char operator[] (size_t pos); // 返回pos位置的字符
const char operator[] (size_t pos) const;
char back(); // 返回最后一个元素
const char back() const;
char front(); // 第一个元素
const char front() const;
// 范围for
例如
int main()
{string s1(i love you);for (int i 0; i s1.size(); i){cout s1[i];}cout endl;cout s1.front() endl;cout s1.back() endl;string s2(aaaaaaaaaaaa);for (auto e : s2) // 在底层实际上用的还是迭代器{cout e;e 1;}cout endl;for (auto e : s2){cout e;}return 0;
}
2.1.5、修改
string operator (const string str); // 追加字符串
string operator (const char* s); // 重载
string operator (char c); // 重载
string append (const string str); // 追加字符串
string append (const char* s); // 重载
string append (size_t n, char c) // 重载
void push_back (char c); // 尾插字符
string insert (size_t pos, const char* s); // pos位置前插入字符串
注意在string尾部追加字符时s.push_back(c)和s.append(1, c)以及s c三种的实现方式差不多一般情况下string类的操作用的比较多操作不仅可以连接单个字符还可以连接字符串。
例如
int main()
{string s1(i am);s1 student;for (char s : s1){cout s;}cout endl;s1.push_back(!);s1.append(do you like me?);for (auto s : s1){cout s;}cout endl;s1.insert(13, );for (auto s : s1){cout s;}return 0;
}
2.1.6、字符串操作
const char* c_str() const; // 返回C式字符串
size_t find (const char* s, size_t pos 0) const; // 从pos位置向后开始查找字符串
size_t find (char c, size_t pos 0) const;
size_t rfind (const char* s, size_t pos npos) const; // 从pos位置向前查找字符串
size_t rfind (char c, size_t pos npos) const;
string substr (size_t pos 0, size_t len npos) const; // 从pos位置开始截len个长度的字符串构造对象
例如
int main()
{string s1(i am);const char* s2 s1.c_str();s1 student! do you like me?;size_t n s1.find(like me, 0);string s3 s1.substr(n, 7);for (auto e : s3){cout e;}cout endl;return 0;
}
2.1.7、成员常量
static const size_t npos -1; // size_t类型的最大值
2.1.8、非成员函数
string operator (const string lhs, const string rhs); // 运算符重载
istream operator (istream is, string str); // 流提取
ostream operator (ostream os, const string str); // 流插入
istream getline (istream is, string str); // 获取一行字符串默认遇换行结束
istream getline (istream is, string str, char delim); // 可以指定遇到delim结束
bool operator (const string lhs, const string rhs); // 等于
bool operator! (const string lhs, const string rhs); // 不等于
bool operator (const string lhs, const string rhs); // 小于
bool operator (const string lhs, const string rhs); // 小于等于
bool operator (const string lhs, const string rhs); // 大于
bool operator (const string lhs, const string rhs); // 大于等于
例如
int main()
{string s1(100);s1 s1 100;cout s1 endl;string s2;getline(cin, s2);cout s2 endl;cout (s1 s2) endl;string s3;cin s3;cout s3 endl;cout string::npos endl;return 0;
}
2.1.9、转换函数
int stoi (const string str, size_t* idx 0, int base 10); // 转换为整数
string to_string (int val); // 转换为string类型例如
int main()
{string s1(100);int n stoi(s1);n 50;string s2 to_string(n);for (auto e : s2){cout e;}cout endl;return 0;
}
上面的几个接口了解一下下面的OJ题目中会有一些体现他们的使用此外还可以看string的模拟实现来理解string类的使用。string类中还有一些其他的操作这里不一一列举大家在需要用到时不明白了查文档即可。
2.2、vs和g下的string
注意下述结构是在32位平台下进行验证32位平台下指针占4个字节。
2.2.1、vs下的string
string总共占28个字节内部结构稍微复杂一点先是有一个联合体联合体用来定义string中字 符串的存储空间 当字符串长度小于16时使用内部固定的字符数组来存放当字符串长度大于等于16时从堆上开辟空间。
2.2.2、g下的string
G下string是通过写时拷贝实现的string对象总共占4个字节内部只包含了一个指针该指 针将来指向一块堆空间内部包含了如下字段 空间总大小、字符串有效长度、引用计数。
写时拷贝是写时再进行深拷贝是通过“浅拷贝”和引用计数机制以及“延迟复制”策略来实现的。当创建对象或赋值时多个对象可以共享同一份数据不立即复制只有当其中某个对象需要修改这份共享数据时才会为它创建一份独立的拷贝即“写”操作触发复制。
引用计数用来记录资源使用者的个数。在构造时将资源的计数给成1每增加一个对象使用该资源就给计数增加1当某个对象被销毁时先给该计数减1然后再检查是否需要释放资源如果计数为0说明该对象为资源的最后一个使用者将该资源释放否则就不能释放因为还有其他对象在使用该资源。
3、OJ题
3.1、仅仅反转字母
仅仅反转字母 参考 3.2、第一个出现一次的字符
第一个出现一次的字符 参考 3.3、最后一个单词的长度
最后一个单词的长度 参考 注意无论是scanf还是cin都有一个特点就是遇到空格或者换行就会结束。
3.4、字符串是否回文
验证回文串 参考 3.5、字符串相加
字符串相加 参考 上面的这个题时间复杂度比较高我们可以进行优化一下 4、模拟实现
我们只实现string类的主要的功能。
class String
{
public:// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////迭代器 这里的迭代器是用原生指针实现的。typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str _size;}// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////特殊的成员函数/*String():_str(new char(\0)),_size(0),_capacity(0){}String(const char* str):_size(strlen(str)),_capacity(_size){_str new char[_capacity 1];strcpy(_str, str);}*/String(const char* str) //上面的两个构造函数合并这一个构造函数。:_size(strlen(str)), _capacity(_size){_str new char[_capacity 1];strcpy(_str, str);}/*String(const String s)//传统写法的构造函数{_str new char[s.capacity()1];strcpy(_str, s._str);_size s.size();_capacity s.capacity();}*/void swap(String s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);//这个是算法库里面的函数。}String(const String s)//现代写法的构造函数/*:_str(nullptr) //不写这个在vs不报错但是在其他编译器上不写这个可能会出现错误。一般情况下编译器不会对自定义类型处理, _size(0) //但在vs上编译器把_str处理为nullptr,_size和_capacity处理为0。不处理的情况下默认为随机值等到出作用域销毁的, _capacity(0)*/ //时候也就是delete的时候就会出现错误。{String tmp(s._str);swap(tmp);}~String(){delete[] _str;_str nullptr;_size _capacity 0;}//String operator(const String s)//传统写法//{// if (this ! s)// {// char* tmp new char[s.capacity() 1];// strcpy(tmp, s._str);// delete[] _str;// _str tmp;// _size s.size();// _capacity s.capacity();// }// return *this;//}//String operator(const String s)//现代写法//{// if (this ! s)// {// String tmp(s);// swap(tmp);// }// return *this;//}String operator(String s)//极致的现代写法{swap(s);return *this;}// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////普通的成员函数char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const//为const对象提供的重载形式{assert(pos _size);return _str[pos];}const char* c_str() const{return _str;}void reserve(size_t n){if (n_capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}void resize(size_t n, char c \0){if (n _size){_str[n] \0;_size n;}else{reserve(n);while (_size n){_str[_size] c;_size;}_str[_size] \0;}}size_t find(char ch, size_t pos 0){for (size_t i pos; i _size; i){if (ch _str[i]){return i;}}return npos;}String substr(size_t pos, size_t len npos){String s;size_t end pos len;if (len npos || len pos _size){len _size - pos;end _size;}s.reserve(len);for (size_t i pos; i end; i){s _str[i];}return s;}size_t find(const char* sub, size_t pos 0){const char* tmp strstr(_str pos, sub);if (tmp){return tmp - _str;}elsereturn npos;}void push_back(const char ch){if (_capacity _size){reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}void append(const char* str){size_t len strlen(str);if (len _size _capacity){reserve(len _size);}strcpy(_str _size, str);_size len;}String operator(char ch){push_back(ch);return *this;}String operator(const char* str){append(str);return *this;}String operator(const String s){append(s._str);return *this;}void insert(size_t pos,char ch){assert(pos _size);if (_capacity _size){reserve(_capacity 0 ? 4 : _capacity * 2);}size_t end _size1;while (end pos){_str[end] _str[end - 1];--end;}_str[pos] ch;_size;}void insert(size_t pos, const char* str){assert(pos _size);size_t len strlen(str);if (len _size _capacity){reserve(len _size);}size_t end _size1;while (end pos){_str[endlen-1] _str[end-1];--end;}strncpy(_str pos, str, len);_size len;}void erase(size_t pos 0, size_t len npos){assert(pos _size);if (len npos || len pos _size){_str[pos] \0;_size pos;}else{size_t begin pos len;while (begin _size){_str[begin - len] _str[begin];begin;}_size - len;}}void clear(){_str[0] \0;_size 0;}/*size_t size(){return _size;}size_t capacity(){return _capacity;}*/size_t size() const//其实写了下面的两个const修饰的成员函数就没必要写上面的两个成员函数了。{return _size;}size_t capacity() const{return _capacity;}// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool operator(const String s) const{return strcmp(_str, s._str) 0;}bool operator(const String s) const{return strcmp(_str, s._str) 0;}bool operator(const String s) const{return !(*this s);}bool operator(const String s) const{return *this s || *this s;}bool operator(const String s) const{return !(*this s);}bool operator!(const String s) const{return !(*this s);}// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;//为了在类外也能访问所以公开了。};const size_t String::npos -1;// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*istream operator(istream in, String s)
{s.clear();char ch in.get();while (ch ! ch ! \n){s ch;ch in.get();}return in;
}*/istream operator(istream in, String s)//上面的优化版本
{s.clear();char buff[129];size_t i 0;char ch; //流提取默认遇到空格或者换行结束//in ch; //这种写法是不行的因为流提取没法提取空格或者换行。ch in.get();//这里的get函数是库里面的函数这个函数是可以拿到空格和换行的。while (ch ! ch ! \n){buff[i] ch;if (i 128){buff[i] \0;s buff;i 0;}ch in.get();}if (i ! 0){buff[i] \0;s buff;}return in;
}ostream operator(ostream out, const String s)
{/*for (size_t i 0; i s.size(); i){out s[i];}*/for (auto ch : s)//范围for也是可以的。out ch;return out;
}
5、补充
编码表值和符号一一映射的关系。
ASCII表被制作时仅仅考虑到了英文为了让电脑能呈现其他国家的语言所以就制作了Unicode统一码也叫万国码。Unicode又可以分为UTF-8、UTF-16、UTF-32。UTF-8是兼容ASCII表的对于常见的汉字用UTF-8编码占两个字节越是不常用的汉字占的字节数越多但不超过4个字节。
GBK全称《汉字内码扩展规范》之所以会有GBK的存在是因为有些生僻字或者古汉字用Unicode不能很好的兼容因而制作出了更符合中国的GBK编码使用了双字节的编码方案。
Windows上一般使用GBKLinux上一般用UTF-8。
乱码一般是指存储方式和解释方式不同而导致的解析出的一些没有规律的字符或者数字等。