C++——string类

embedded/2024/10/9 9:21:40/

目录

前言:

一、C语言中字符串的缺陷

 二、string常见接口极其调用

1.构造及遍历

2.+、+=、[]、<<、>>运算符重载

3.string自身属性接口 

4.增删查改接口

三、模拟实现


前言:

        严格来说,string类并不属于STL中的一部分,出现在STL之前,STL并没有把string归入其中,但是与STL中的容器的很多操作类似,字符串的操作也很常见,所以很值得学习。

        如需自己查找文档:cplusplus.com - The C++ Resources Network

一、C语言中字符串的缺陷

C 语言中,字符串是以 '\0' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP 的思想,而且底层空间需要用自己管理,稍不留神可能还会越界访问。

 二、string常见接口极其调用

这是所有的接口:

看起来很多但是因为历史原因设计较为冗余,下面是对比较重要和常用的接口的操作演示,注意要包含string的头文件<string>,下面是比较常见的:

代码注释写的很详细了,应该可以直接看懂

1.构造及遍历

#include <iostream>
#include <string>
using namespace std;void string_test1()
{string str1;//  默认构造string str2("musssshandsomehaha");// 带参构造string str3(str2);// 拷贝构造cout << "str1: " << str1 << endl;cout << "str2: " << str2 << endl;cout << "str3: " << str3 << endl;string str4(str2, 3, 4);// 从下标为3的位置开始(包括此位置),长度为4的子串cout << "str4: " << str4 << endl;string str5(str2, 3, 100); // 超过最大长度会默认取到最后cout << "str5: " << str5 << endl;string str6("abcdefg", 3);// 取前3个字符cout << "str6: " << str6 << endl;// from sequence (5)	  string(const char* s, size_t n);// 不能这么玩,会越界,库里面没处理//string str7("abcdefg", 100);//cout << "str7: " << str7 << endl;string str8(7, 'm');// 填充7个字符'm',必须要加单引号cout << "str8: " << str8 << endl;// 对string的遍历//  []重载for (int i = 0; i < str2.size(); i++) // size求str长度{//str2[i]++;    //也可以对其修改cout << str2[i];}cout << endl;// at,与[]不同的是,如果越界,at会抛出异常,而[]会直接报错(assert)for (int i = 0; i < str2.size(); i++){str2.at(i)++;    //也可以对其修改cout << str2.at(i);}cout << endl;// 迭代器// 迭代器是一个很类似于指针的东西,可能是原生指针也可能是通过运算符重载封装起来的指针,不管怎么样,都可以进行类似指针的操作// 下面调用的begin、end、rbegin、rend等等都是返回string迭代器的接口string::iterator it = str2.begin();while (it != str2.end()){*it += 1;(*it)++; // 必须加括号!!!!cout << *it;it++;}cout << endl;// 范围for(底层其实就是迭代器)for (auto ch : str2)   // auto就是自动识别类型,改成char也一样{cout << ch;}// *it给了ch,ch只是一份拷贝,并不能通过修改ch来修改str2,如果非要通过这种方式就在auto后面加引用cout << endl;// 反向遍历:反向迭代器//string::reverse_iterator rit = str2.rbegin();// 可以通过auto来简化代码auto rit = str2.rbegin();while (rit != str2.rend()){cout << *rit;rit++;}cout << endl;// const正反向迭代器,只读const string str9("musssshandsomehaha");//      iterator begin();// const_iterator begin() const;// 这些迭代器接口会自动识别类型返回,但其实也可以用cbegin、cend、crbegin、crend指定string::const_iterator cit = str9.begin();while (cit != str9.end()){cout << *cit;cit++;}cout << endl;string::const_reverse_iterator crit = str9.rbegin();while (crit != str9.rend()){cout << *crit;crit++;}cout << endl;// cbegin,cend,crbegin,crend直接就是指定const迭代器,前面的那一组是自动识别string::const_iterator ccit = str9.cbegin();while (ccit != str9.cend()){cout << *ccit;ccit++;}cout << endl;string::const_reverse_iterator ccrit = str9.crbegin();while (ccrit != str9.crend()){cout << *ccrit;ccrit++;}cout << endl;
}
int main()
{string_test1();return 0;
}

2.+、+=、[]、<<、>>运算符重载

#include <iostream>
#include <string>
using namespace std;void string_test2()
{// =赋值运算符重载// 三种赋值方式:string、C语言字符数组首元素地址、单个字符string s("abcdefghijklmn");string s1 = s;	// 这里是拷贝构造,不是运算符重载!!!string s2 = "hello"; // 这里也是调用了构造函数,不是运算符重载!!!string s3;s3 = 'a'; // 这里才是赋值运算符重载,因为是已经声明并初始化过的,然后才把'a'赋给s3//string s4 = 'a';  // 这里会报错,因为这是调用构造函数,而这里char不能隐式类型强转成stringchar a[] = "wohaoshuai";string s4;// =重载调用s4 = a;string s5;cin >> s5;// 打印和输入其实就是调用的重载后的<<和>>cout << "s1:" << s << endl;cout << "s2:" << s2 << endl;cout << "s3:" << s3 << endl;s3 = s;cout << "s3:" << s3 << endl;s3 = s2;cout << "s3:" << s3 << endl;cout << "s4:" << s4 << endl;cout << "s4:" << s5 << endl;}void string_test3()
{string s("abcdefghijklmn");// +重载:支持string,字符数组和char互相随便+string s1 = s + "hello";string s2 = s + "world";cout << "s1:" << s1 << endl;cout << "s2:" << s2 << endl;// +=重载:支持随便+=string,字符数组和chars1 += "hello";s2 += "world";cout << "s1:" << s1 << endl;cout << "s2:" << s2 << endl;// []重载:重载了const版本和普通版本s1[0] = 'M';s2[0] = 'W';cout << "s1:" << s1 << endl;
}int main()
{string_test2();string_test3();return 0;
}

3.string自身属性接口 

#include <iostream>
#include <string>
using namespace std;void string_test4()
{string s("abcdefghijklmn");cout << s.size() << endl;	// 存储字符的长度,不算尾部的\0*cout << s.length() << endl;// length和size是一样的,length是历史问题,我们一般用size即可cout << s.capacity() << endl;// 容量cout << s.max_size() << endl;// 最大容量,其实就是整型的最大值,基本没用s.reserve(30);// 直接给s>=30的容量,是否大于,大多少,标准没有硬性规定cout << s.capacity() << endl;// 111s.reserve(20);cout << s.capacity() << endl;// 是否缩容取决于编译器,但是一定不会改变原来的string存储的内容,size肯定不变s.resize(10);// size变成10,容量不变,内容截断cout << s.capacity() << endl;cout << s.size() << endl;cout << "s:" << s << endl;//s.resize(40);// 扩容的话,容量会改变,填充\0//cout << s.capacity() << endl;//cout << s.size() << endl;//cout << "s:" << s << endl;s.resize(50, 'm');// 也可以指定扩充后的填充字符cout << s.capacity() << endl;cout << s.size() << endl;cout << "s:" << s << endl;s.clear();// 清空s,容量不变,size为0,全部都为\0cout << s.capacity() << endl;cout << s.size() << endl;cout << "s:" << s << endl;cout << s.empty() << endl;// 是否为空,1或0s = "abcdefghijklmn";cout << s.capacity() << endl;cout << s.size() << endl;cout << "s:" << s << endl;cout << s.empty() << endl;s.shrink_to_fit();// 缩容,就是把容量缩小到刚好装下内容cout << s.capacity() << endl;cout << s.size() << endl;cout << "s:" << s << endl;}int main()
{string_test4();return 0;
}

4.增删查改接口

#include <iostream>
#include <string>
using namespace std;void string_test5()
{string s("abcdefghijklmn");s.back() = 'x';s.front() = 'X';// 分别返回最后一个和第一个字符的引用,引用也就意味着可以修改cout << s << endl;// append  往字符串后面添加string str;string str2 = "Writing ";string str3 = "print 10 and then 5 more";str.append(str2);                       // str后面添加"Writing "cout << str << endl;str.append(str3, 6, 3);                   // 再后面添加"10 ",下标为6开始,3个字符cout << str << endl;str.append("dots are cool", 5);          // 添加"dots ",5个字符cout << str << endl;str.append("here: ");                   // 添加"here: "cout << str << endl;str.append(10, '.');                    // 添加"..........",10个'.',添加一个字符就用1,'字符',也可以写成"字符"str.push_back('a');// push_back只能往后添加字符cout << str << endl;str.append(str3.begin() + 8, str3.end());  // 迭代器,也就是begin后面数八个位置(下标为8)到最后" and then 5 more"cout << str << endl;
}void string_test6()
{// assign 为字符串分配一个新值,替换其当前内容。string str;string base = "The quick brown fox jumps over a lazy dog.";str.assign(base);  // base给给str(覆盖而不是追加)cout << str << '\n';str.assign(base, 10, 9);cout << str << '\n';         // 指定位置给给str"brown fox"str.assign("pangrams are cool", 7);cout << str << '\n';         // "pangram" 前七个位置str.assign("c-string");cout << str << '\n';         // "c-string"str.assign(10, '*');cout << str << '\n';         // "**********",n个charstr.assign(base.begin() + 16, base.end() - 12);cout << str << '\n';         // "fox jumps over"迭代器区间}void string_test7()
{// insert 插入// 除了尾插效率都不太好,因为要挪动数据string str = "to be question";string str2 = "the ";string str3 = "or not to be";string::iterator it;str.insert(6, str2);                 // to be (the )question   下标为6之前插入str.insert(6, str3, 3, 4);             // to be (not )the question  下标为6之前插入str3下标为3开始4个字符cout << str << '\n';str.insert(10, "that is cool", 8);    // to be not (that is )the question   下标为10前插入指定字符串的前8个字符cout << str << '\n';str.insert(10, "to be ");            // to be not (to be )that is the question 下标为10前插入指定字符串cout << str << '\n';str.insert(15, 1, ':');               // to be not to be(:) that is the question  下标为15前插入一个字符cout << str << '\n';it = str.insert(str.begin() + 5, ','); // to be(,) not to be: that is the questioncout << str << '\n';str.insert(str.end(), 3, '.');       // to be, not to be: that is the question(...)cout << str << '\n';str.insert(it + 2, str3.begin(), str3.begin() + 3); // (or )cout << str << '\n';
}void string_test8()
{// replace// 替换字符串的一部分,也就是部分覆盖,这个除非替换前后的两部分长度相等,不然效率不高,因为要挪动数据string base = "this is a test string.";string str2 = "n example";string str3 = "sample phrase";string str4 = "useful.";Using positions:                 0123456789*123456789*12345//string str = base;           // "this is a test string."//str.replace(9, 5, str2);          // "this is an example string." (1)  从下标为9的位置开始,长度为5,替换为str2//str.replace(19, 6, str3, 7, 6);     // "this is an example phrase." (2)  从下标为19的位置开始,长度为6,替换为str3下标为7开始,长度为6//str.replace(8, 10, "just a");     // "this is just a phrase."     (3)  从下标为8的位置开始,长度为10,替换为"just a"//str.replace(8, 6, "a shorty", 7);  // "this is a short phrase."    (4)  从下标为8的位置开始,长度为6,替换为"a shorty"中的前7个字符//str.replace(22, 1, 3, '!');        // "this is a short phrase!!!"  (5)  从下标为22的位置开始,长度为1,替换为3个!//cout << str << '\n';base.replace(0, 6, base, 6, 6);cout << base << endl;}void string_test9()
{//pop_backstring str = "hello world";cout << str << endl;cout << str.capacity() << endl;cout << str.size() << endl;str.pop_back();cout << str << endl;cout << str.capacity() << endl;cout << str.size() << endl;// 尾删,会把size-1,删除的位置上的元素置为\0,容量不变
}void string_test10()
{// erasestring str("This is an example sentence.");cout << str << '\n';// "This is an example sentence."str.erase(10, 8);                        //  10位置后面erase8个cout << str << '\n';// "This is an sentence."str.erase(str.begin() + 9);               //     9位置后面全erasecout << str << '\n';// "This is a sentence."str.erase(str.begin() + 5, str.end() - 9);  //   迭代器区间erasecout << str << '\n';// "This sentence."
}void string_test11()
{string str = "We think in generalities, but we live in details.";// substr   截取string的一部分返回string str2 = str.substr(3, 5);     // "think",3位置5个cout << str2 << endl;size_t pos = str.find("live");      //   找到live的位置string str3 = str.substr(pos);     // live往后所有cout << str3 << endl;cout << str2 << ' ' << str3 << '\n';
}void string_test12()
{// find系列//find  // 搜索字符串或单个字符,字符串必须全部匹配//	返回第一个匹配项的第一个字符的位置。// 如果未找到匹配项,该函数将返回 string::npos。string str("There are two needles in this haystack with needles.");string str2("needle");// different member versions of find in the same order as above:size_t found = str.find(str2);if (found != string::npos)cout << "first 'needle' found at: " << found << '\n';found = str.find("haystack");if (found != string::npos)cout << "'haystack' also found at: " << found << '\n';found = str.find('.');if (found != string::npos)cout << "Period found at: " << found << '\n';// refind,类似find,返回倒着找到的第一个string str3("The sixth sick sheik's sixth sheep's sick.");string key("sixth");size_t found2 = str3.rfind(key);if (found2 != string::npos)cout << found2 << endl;// find_first_of			在字符串中搜索与其参数中指定的任何字符匹配的第一个字符。// find_first_not_of  在字符串中搜索与参数中指定的任何字符都不匹配的第一个字符。// find_last_of          在字符串中倒着搜索与参数中指定的任何字符匹配的最后一个字符。// find_last_not_of   在字符串中倒着搜索与参数中指定的任何字符都不匹配的最后一个字符。
}int main()
{//string_test5();//string_test6();//string_test7();//string_test8();//string_test9();//string_test10();//string_test11();string_test12();return 0;
}

5.其它(比较、输入、交换)

比较compare和交换swap就不演示了,(累了),比较是通过ascll,swap是深度交换,重点说一下getline 

#include <iostream>
#include <string>
using namespace std;void string_test13()
{// 默认情况下,string输入会忽略空格,编译器会把空格当成两个字符串的分割// 利用getline可以很好的解决这个问题// 使用getline可以读入空格,默认以换行结束,也可以指定字符作为输入的结束// 指定字符作为结束标志时,换行也依然是结束标志string str;string str2;getline(cin, str);getline(cin, str2, 'a');cout << str << endl;cout << str2 << endl;
}int main()
{string_test13();return 0;
}

 ok,以上string的基本的功能都列举完毕, 下面进入模拟实现

三、模拟实现

实现过程注释写的很详细了,不多赘述。

string.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;namespace muss
{class string{public:// 这个重命名必须放到public里面否则默认是私有无法访问// string由于其结构原因,迭代器可以用原生指针typedef char* iterator;typedef const char* const_iterator;// 短小且频繁调用的函数写到类里面,默认内联//string()//	:_str(new char[1] {'\0'})//	, _size(0)//	, _capacity(0)//{}// 加了缺省值就不用写上面那个了string(const char* str = ""){_size = strlen(str);_capacity = _size;// 要给\0留一个位置// 一定是容量+1,不是size + 1_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& str){// 传引用涉及到深拷贝size_t len = str.size();_size = len;_capacity = len;_str = new char[len + 1];strcpy(_str, str.c_str());}~string(){_size = _capacity = 0;delete[] _str;_str = nullptr;}char* c_str() const{return _str;}size_t size() const{return strlen(_str);}void clear(){_size = 0;_str[0] = '\0';}size_t capacity() const{return _capacity;}char& operator[](size_t pos){assert(pos >= 0 && pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos >= 0 && pos < _size);return _str[pos];}string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}iterator begin(){return _str;}// 一定注意end是最后一个位置的下一个位置,也就是\0iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);string& erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}

string.cpp

#include "string.h"namespace muss
{// 保留n的容量,结果容量大于等于n就行// 如果n小于原来的容量,看编译器,这里就不缩小容量了void string::reserve(size_t n){if (n <= _capacity)return;char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}// 尾插void string::push_back(char ch){// 插入前必须判断容量是否足够if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size++] = ch;// 不能忘记字符串尾置为\0_str[_size] = '\0';}// 末尾追加字符串void string::append(const char* str){size_t len = strlen(str);// 插入前必须判断容量是否足够if (_capacity < _size + len){// 能二倍扩就二倍扩,不能就_size + lenreserve(_capacity * 2 > _size + len ? _capacity * 2 : _size + len);}// 追加strcpy(_str + _size, str);// 最后不能忘记修改size_size += len;}string& string::operator+=(char ch){// 尾插字符再返回//this->push_back(ch);push_back(ch);return *this;}string& string::operator+=(const char* str){// 追加字符串再返回append(str);return *this;}// 插入数据必须要以斜杠0结尾,一定注意这个void string::insert(size_t pos, char ch){assert(pos >= 0 && pos <= _size);// 插入前必须判断容量是否足够if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size + 1] = '\0';// 挪for (size_t i = _size; i > pos; --i){// 左边的往右边挪// 终止条件是pos位置挪走_str[i] = _str[i - 1];}// 填_str[pos] = ch; // 插入数据之后一定要改变_size_size++;}void string::insert(size_t pos, const char* str){size_t len = strlen(str);assert(pos <= _size && pos >= 0);// 插入前必须判断容量是否足够if (_capacity < _size + len){// 能二倍扩就二倍扩,不能就_size + lenreserve(_capacity * 2 > _size + len ? _capacity * 2 : _size + len);}_str[_size + len] = '\0';// 挪for (size_t i = _size + len - 1; i > pos + len - 1; --i){// 左边的往右边挪// 这里len - 1就可以看成上面只插入一个字符的len是1,类比着写_str[i] = _str[i - len];}// 填// 这里不能用strcpy,strcpy会把插入三个字符之后的字符串全部清空,坑死人了//strcpy(_str + pos, str);for (size_t i = 0; i < len; ++i){_str[i + pos] = str[i];}// 插入数据之后一定要改变_size_size += len;}// 擦除字符串的一部分,减少其长度,返回该string// 缺省参数只需要头文件给就可以了,这里再给会重定义string& string::erase(size_t pos, size_t len){assert(pos >= 0 && pos < _size);if (len >= _size - pos){_str[pos] = '\0';// 一定记得改一下_size_size = pos;return *this;}for (size_t i = pos; i < _size - len; ++i){_str[i] = _str[i + len];}_size -= len;// 最后一定给上\0封上字符串_str[_size] = '\0';return *this;}size_t string::find(char ch, size_t pos){assert(pos < _size && pos >= 0);for (size_t i = pos; i < _size; ++i){if (_str[i] == ch)return i;}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size && pos >= 0);char* tmp = strstr(_str, str);if (tmp != nullptr)return tmp - str;return npos;}// 截取该string一段并返回string string::substr(size_t pos, size_t len){assert(pos < _size && pos >= 0);// 如果len给大了就更新一下lenif (len > _size - pos)len = _size - pos;string tmp;tmp.reserve(len);for (size_t i = pos; i < pos + len; ++i){tmp += _str[i];}return tmp;}// string内字符串的比较,为什么不写类里面?// 因为这样会更灵活,可以把一个常量字符串放到前面bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}	bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}	bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}	bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}// 流插入提取重载ostream& operator<<(ostream& out, const string& s){for (auto ch : s){cout << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();// 流插入的话,由于输入字符串长短不确定,并且如果不处理,在前期输入会多次扩容导致效率问题// 所以最好整出来一个buff数组来暂存输入的字符串,如果够用,不用多次扩容,不够用,后面的扩容也相对而言扩的容量多一点,不会太频繁const int N = 256;char buff[N];int i = 0;char ch;//in >> ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;}
}

test.cpp

#include "string.h"
using namespace std;namespace muss
{// 遍历void string_test1(){string s("abc");string s2(s);string s3;cout << s.c_str() << endl;cout << s2.c_str() << endl;cout << s3.c_str() << endl;for (int i = 0; i < s.size(); ++i){cout << s[i] << " ";}cout << endl;string::iterator it = s.begin();while (it < s.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;}void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 2;}cout << s2.c_str() << endl;for (auto e : s2){cout << e << " ";}cout << endl;string::iterator it = s2.begin();while (it != s2.end()){//*it += 2;cout << *it << " ";++it;}cout << endl;}void test_string2(){string s1("hello world");s1 += 'x';s1 += '#';cout << s1.c_str() << endl;s1 += "hello bit";cout << s1.c_str() << endl;s1.insert(5, '$');cout << s1.c_str() << endl;s1.insert(0, '$');cout << s1.c_str() << endl;string s2("hello world");cout << s2.c_str() << endl;s2.insert(5, "$$$");cout << s2.c_str() << endl;s2.insert(0, "$$$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");cout << s2.c_str() << endl;}void test_string3(){string s1("abcdefghijklmn");cout << s1.c_str() << endl;s1.erase(6, 100);cout << s1.c_str() << endl;string s2("abcdefghijklmn");s2.erase(6);cout << s2.c_str() << endl;string s3("abcdefghijklmn");s3.erase(6, 3);cout << s3.c_str() << endl;}void test_string4(){string s("test.cpp.zip");size_t pos = s.find('.');string suffix = s.substr(pos);cout << suffix.c_str() << endl;string copy(s);cout << copy.c_str() << endl;s = suffix;cout << suffix.c_str() << endl;cout << s.c_str() << endl;s = s;cout << s.c_str() << endl;}void test_string5(){string s1("hello world");string s2("hello world");cout << (s1 < s2) << endl;cout << (s1 == s2) << endl;cout << ("hello world" < s2) << endl;cout << (s1 == "hello world") << endl;//cout << ("hello world" == "hello world") << endl;cout << s1 << s2 << endl;string s0;cin >> s0;cout << s0 << endl;}
}int main()
{//muss::string_test1();muss::test_string5();//char c1[] = "abcdefg";//char c2[] = "aaa";//strcpy(c1 + 1, c2);//cout << c1 << endl;return 0;
}

完结撒花~~~╰(✿´⌣`✿)╯♡

下一篇大概率是vector...........


http://www.ppmy.cn/embedded/124997.html

相关文章

Linux 线程

目录 一.线程的概念 1.什么是线程&#xff1f; 2.Linux 系统对线程的实现 线程比进程要更轻量化体现在什么方面&#xff1f;&#xff1f; 线程切换较进程切换效率高的原因&#xff1f;&#xff1f; ①cache缓存&#xff08;主要原因&#xff09; ②寄存器的刷新&#xff…

Git管理远程仓库

添加远程仓库 要新增远程&#xff0c;请在终端上存储存储库的目录中使用 git remote add 命令。 git remote add 命令采用两个参数&#xff1a; 远程名称&#xff08;例如 origin&#xff09;远程 URL&#xff08;例如 https://github.com/OWNER/REPOSITORY.git&#xff09;…

微知-一个不错的rpm大全网站,临时找rpm包的好地方(rpmfind.net)

背景 经常要安装某个rpm包&#xff0c;在默认的镜像源找不到。这个网站可以直接下载安装&#xff0c;能够部分解决问题。 有些场景下载后还有依赖包&#xff0c;不影响大环境的情况&#xff0c;可以以 -nodeps安装&#xff0c;然后尝试使用。 另外rpmfind.net网站能够work的本…

C++笔记之标准库和boost库中bind占位符_1的写法差异

C++笔记之标准库和boost库中bind占位符_1的写法差异 code review! 参考博文: C++新特性探究(十五):bind 在C++中,_1 和 std::placeholders::_1 都用于表示占位符,但它们有不同的上下文:

顺序表和链表的区别

顺序表和链表的区别 不同点顺序表链表&#xff08;带头双向循环&#xff09;存储空间物理上一定连续逻辑上连续物理上不一定连续随机访问&#xff08;用下标随机访问&#xff09;支持&#xff1a;O(1)不支持&#xff1a;O(N)任意位置插入或者删除元素可能需要搬移元素&#xf…

php对接中通SDK问题

记一次对接中通接口遇到的问题。 中通SDK是4年前的了&#xff0c;就这他们技术人员说能拉取的都是最新的&#xff0c;囧。 1.修改ZopHttpUtil.php中的请求方式 public function post($url, $headers, $querystring)//$timeout{$ch curl_init();curl_setopt($ch, CURLOPT_UR…

etcd 集群搭建【docker-compose】

文章目录 环境准备部署创建文件夹进入文件夹生成密钥启动查看集群成员查看节点状态结果 检查配置解说 环境准备 IPROLEETCD_NAME192.168.142.157masteretcd0192.168.142.156slaveetcd1192.168.142.155slave02etcd2192.168.142.158slave03etcd3 部署 创建文件夹 mkdir -p /d…

VNC轻松连接远程Linux桌面

Linux配置VNC&#xff08;以RedHat、CentOS为例&#xff09; 说明&#xff1a; Linux平台安装VNCServer Windows平台使用VNC-Viewer 1.在Linux平台安装VNCServer服务端软件包。 yum -y install vnc *vnc-server*2.修改VNCServer主配置文件 vi /etc/sysconfig/vncservers复制…