不要使用memset初始化string(一定别这么干)

最后更新于:2022-04-01 06:41:51

##实战c++中的string系列--不要使用memset初始化string(一定别这么干) 参考链接:  [http://www.cppblog.com/qinqing1984/archive/2009/08/07/92479.html](http://www.cppblog.com/qinqing1984/archive/2009/08/07/92479.html) 百度百科第一次这么给力:  void *memset(void *s, int ch, size_t n);  函数解释:将s中前n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。  memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。 memset() 函数常用于内存空间初始化:  ~~~  char str[100];  memset(str,0,100); ~~~ 用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ~~~ memset(a, '\0', sizeof(a)); ~~~ memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度:   ~~~ char a[100], b[50]; memcpy(b, a, sizeof(b)); //注意如用sizeof(a),会造成b的内存地址溢出。 ~~~ strcpy就只能拷贝字符串了,它遇到’\0’就结束拷贝:  ~~~ char a[100], b[50]; strcpy(a,b); ~~~ 如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。  下面开始: ~~~ class Material { public: Material(){ setDefaults();} void setDefaults(){ memset(this,0,sizeof(*this));} int mark; char materialName[256]; // material name Vector3 ambient; // ambient Vector3 diffuse; // diffuse Vector3 specular; // specular int shininess; // float alpha; // bool isSpecular; char textureName[256]; // texture name char textureTransName[256]; // transparent texture name }; ~~~ 这段代码完美无瑕。再看看下面的: ~~~ class Material { public: Material(){ setDefaults();} void setDefaults(){ memset(this,0,sizeof(*this));} int mark; std::string materialName; // material name Vector3 ambient; // ambient Vector3 diffuse; // diffuse Vector3 specular; // specular int shininess; // float alpha; // bool isSpecular; std::string textureName; // texture name std::string textureTransName; // transparent texture name }; ~~~ 上面的代码会造成内存泄露:  所以对于C++的std::string来说,要使用C++风格的初始化。 在网上看到这样一条评论,觉得有道理:  **任何类都不能用memset, 一旦暴力,就等于你强奸了她的内部数据,她已经崩溃了**
';

将string用于switch语句(c++做C#的事儿, switch中break还是return厉害)

最后更新于:2022-04-01 06:41:49

##实战c++中的string系列--将string用于switch语句(c++做C#的事儿, switch中break还是return厉害) 作为一个C++程序员,或是出于习惯,或是出于无奈,你多少次这么写: ~~~ if (!strcmp(pszValue, "Value X")) DoThis(); else if (!strcmp(pszValue, "Value Y")) DoThat(); else if (!strcmp(pszValue, "Value Z")) DoSomethingElse(); else DontKnowWhatToDo(); ~~~ 你千百次的问,如果这个时候可以使用switch多好呢? ~~~ switch(strValue) { case "Value X": DoThis(); break; case "Value Y": DoThat(); break; case "Value Z"; DoSomethingElse(); break; default: DontKnowWhatToDo(); break; ~~~ 上面这段代码在C Sharp中是合法的,但是作为一个C++程序员,你只能无奈和无奈。 下面就是用enum和std::map完成这个愿望! ~~~ #include <map> #include <string> #include <iostream.h> // Value-Defintions of the different String values static enum StringValue { evNotDefined, evStringValue1, evStringValue2, evStringValue3, evEnd }; // Map to associate the strings with the enum values static std::map<std::string, StringValue> s_mapStringValues; // User input static char szInput[_MAX_PATH]; // Intialization static void Initialize(); int main(int argc, char* argv[]) { // Init the string map Initialize(); // Loop until the user stops the program while(1) { // Get the user's input cout << "Please enter a string (end to terminate): "; cout.flush(); cin.getline(szInput, _MAX_PATH); // Switch on the value switch(s_mapStringValues[szInput]) { case evStringValue1: cout << "Detected the first valid string." << endl; break; case evStringValue2: cout << "Detected the second valid string." << endl; break; case evStringValue3: cout << "Detected the third valid string." << endl; break; case evEnd: cout << "Detected program end command. " << "Programm will be stopped." << endl; return(0); default: cout << "'" << szInput << "' is an invalid string. s_mapStringValues now contains " << s_mapStringValues.size() << " entries." << endl; break; } } return 0; } void Initialize() { s_mapStringValues["First Value"] = evStringValue1; s_mapStringValues["Second Value"] = evStringValue2; s_mapStringValues["Third Value"] = evStringValue3; s_mapStringValues["end"] = evEnd; cout << "s_mapStringValues contains " << s_mapStringValues.size() << " entries." << endl; } ~~~ 这里有个特别重要的技巧,那就是为什么把enumeration的第一个设为evNotDefined ? 首先我们要明确std::map::operator[] 的作用:  1 设置一个key的value  2 取值。这个时候需要注意,若不存在,才会被插入。 即程序中对于s_mapStringValues,如果szInput 是新的,将会被插入。  并且 the value默认为0 。  如果enumeration第一项为evStringValue1,任何一个未知的string value 都会导致一个有效的switch case。所以我们才这么干。 ==============================================================  这里还有个小问题 讨论一下,就是switch语句中return厉害还是break厉害:  代码: ~~~ switch(s_mapStringValues[szInput]) { case evStringValue1: cout << "Detected the first valid string." << endl; return 0;//还会执行break吗? break; case evStringValue2: cout << "Detected the second valid string." << endl; break; case evStringValue3: cout << "Detected the third valid string." << endl; break; case evEnd: cout << "Detected program end command. " << "Programm will be stopped." << endl; return(0); default: cout << "'" << szInput << "' is an invalid string. s_mapStringValues now contains " << s_mapStringValues.size() << " entries." << endl; break; } ~~~ 测试,表面,return了 就不会break了。
';

函数返回局部变量string(引用局部string,局部string的.c_str()函数)

最后更新于:2022-04-01 06:41:47

##实战c++中的string系列--函数返回局部变量string(引用局部string,局部string的.c_str()函数) 当函数返回字符串的时候,我们可以定义返回string和string&。 1写一个返回string引用的函数 ~~~ std::string & TestStringReference() { std::string loal_str = "holy shit"; return loal_str; } ~~~ 这个函数当然是错误的,编译器会提示我们: 返回局部变量或临时变量的地址: loal_str 即不能返回局部变量的引用。 2写一个返回string的函数(函数返回局部变量string的时候能不能被引用?) ~~~ std::string TestStringReference() { std::string strTest = "This is a test."; return strTest; } ~~~ 那么对于上述函数的返回值可以被引用吗? 代码说话: ~~~ #include<iostream> #include<string> std::string TestStringReference() { std::string strTest = "This is a test."; return strTest; } int main() { std::string& strRefer = TestStringReference(); std::cout << "strRefer:" << strRefer << std::endl; return 0; } ~~~ 代码 完美运行。 实际上返回的不是局部变量,而是编译器新构造的临时对象。 3返回string的函数直接调用.c_str() 上面说了,返回的“局部”string可以被引用的,那么返回的“局部”string直接调用.c_str()会有什么效果恩? ~~~ #include<iostream> #include<string> std::string TestStringC_STR() { std::string strTest = "This is a test."; return strTest; } int main() { const char *pc = TestStringC_STR().c_str(); std::cout << pc << std::endl; return 0; } ~~~ 上面代码编译器不会报错! 但是等等,别高兴太早,看看输出结果,为空,不是我们期望的。 关键是,我们没有将TestStringC_STR()的结果赋给一个string对象就直接获取其指针了,这时,系统并不会为string调用拷贝构造函数或是赋值函数,返回的string仍然只是一个临时对象的状态,它会在完成对pc的赋值后被销毁,这时其内部的数据也不会存在了。 解决方法:先用一个string接收函数的返回值,然后再调用c_str()方法: ~~~ #include<iostream> #include<string> std::string TestStringC_STR() { std::string strTest = "This is a test."; return strTest; } int main() { std::string str1 = TestStringC_STR(); const char *pc = str1.c_str(); std::cout << pc << std::endl; return 0; } ~~~
';

string的连接(+= or append or push_back)

最后更新于:2022-04-01 06:41:44

##实战c++中的string系列--string的连接(+= or append or push_back) string的连接也是经常用到的,string重载了一些运算符:  首先看一看重载+运算符,用于串联两个字符串对象:  源码: ~~~ template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator> operator+( const basic_string<CharType, Traits, Allocator>& _Left, const basic_string<CharType, Traits, Allocator>& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator> operator+( const basic_string<CharType, Traits, Allocator>& _Left, const CharType* _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator> operator+( const basic_string<CharType, Traits, Allocator>& _Left, const CharType _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator> operator+( const CharType* _Left, const basic_string<CharType, Traits, Allocator>& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator> operator+( const CharType _Left, const basic_string<CharType, Traits, Allocator>& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const basic_string<CharType, Traits, Allocator>& _Left, const basic_string<CharType, Traits, Allocator>&& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const basic_string<CharType, Traits, Allocator>&& _Left, const basic_string<CharType, Traits, Allocator>& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const basic_string<CharType, Traits, Allocator>&& _Left, const basic_string<CharType, Traits, Allocator>&& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const basic_string<CharType, Traits, Allocator>&& _Left, const CharType *_Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const basic_string<CharType, Traits, Allocator>&& _Left, CharType _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( const CharType *_Left, const basic_string<CharType, Traits, Allocator>&& _Right ); template<class CharType, class Traits, class Allocator> basic_string<CharType, Traits, Allocator>&& operator+( CharType _Left, const basic_string<CharType, Traits, Allocator>&& _Rig ~~~ 所以使用时,注意事项: ~~~ #include<iostream> #include<string> int main() { std::string my_str = "holiday"; std::string my_str_add = "error" + "error";//错误 std::string my_str_add2 = my_str + "right"; std::string my_str_add3 = my_str + "right" + "right"; std::string my_str_add4 = "right" + my_str; std::string my_str_add5 = "error" + "error" + my_str;//错误 return 0; } ~~~ 下面开始正题!  **+=**  ****将字符追加到字符串**** ~~~ basic_string<CharType, Traits, Allocator>& operator+=( value_type _Ch ); basic_string<CharType, Traits, Allocator>& operator+=( const value_type* _Ptr ); basic_string<CharType, Traits, Allocator>& operator+=( const basic_string<CharType, Traits, Allocator>& _Right ); ~~~ **append**  ****添加字符为字符串的末尾**** ~~~ basic_string<CharType, Traits, Allocator>& append( const value_type* _Ptr ); basic_string<CharType, Traits, Allocator>& append( const value_type* _Ptr, size_type _Count ); basic_string<CharType, Traits, Allocator>& append( const basic_string<CharType, Traits, Allocator>& _Str, size_type _Off, size_type _Count ); basic_string<CharType, Traits, Allocator>& append( const basic_string<CharType, Traits, Allocator>& _Str ); basic_string<CharType, Traits, Allocator>& append( size_type _Count, value_type _Ch ); template<class InputIterator> basic_string<CharType, Traits, Allocator>& append( InputIterator _First, InputIterator _Last ); basic_string<CharType, Traits, Allocator>& append( const_pointer _First, const_pointer _Last ); basic_string<CharType, Traits, Allocator>& append( const_iterator _First, const_iterator _Last ); ~~~ 有多个重载函数,因此多种使用方法: ~~~ string str1a ( "Hello " ); const char *cstr1a = "Out There "; str1a.append ( cstr1a ); string str1b ( "Hello " ); const char *cstr1b = "Out There "; str1b.append ( cstr1b , 3 ); string str1c ( "Hello " ), str2c ( "Wide World " ); str1c.append ( str2c , 5 , 5 ); string str1d ( "Hello " ), str2d ( "Wide " ), str3d ( "World " ); str1d.append ( str2d ); str1d += str3d; string str1e ( "Hello " ); str1e.append ( 4 , '!' ); string str1f ( "Hello " ), str2f ( "Wide World " ); str1f.append ( str2f.begin ( ) + 5 , str2f.end ( ) - 1 ); ~~~ **push_back**  ****将元素添加到该字符串的末尾**** ~~~ void push_back( value_type _Ch ); ~~~ 这里需要注意的是,以下代码是错误的: ~~~ my_str.push_back("123");//错误 my_str.push_back('1');//ok ~~~
';

CDuiString和string的转换(duilib中的cduistring)

最后更新于:2022-04-01 06:41:42

##实战c++中的string系列--CDuiString和string的转换(duilib中的cduistring) 使用所duilib的人定会知道cduistring类型,先看看这个类是怎么定义的: ~~~ class UILIB_API CDuiString { public: enum { MAX_LOCAL_STRING_LEN = 127/*63*/ }; CDuiString(); CDuiString(const TCHAR ch); CDuiString(const CDuiString& src); CDuiString(LPCTSTR lpsz, int nLen = -1); ~CDuiString(); void Empty(); int GetLength() const; bool IsEmpty() const; TCHAR GetAt(int nIndex) const; void Append(LPCTSTR pstr); void Assign(LPCTSTR pstr, int nLength = -1); LPCTSTR GetData() const; void SetAt(int nIndex, TCHAR ch); operator LPCTSTR() const; TCHAR operator[] (int nIndex) const; const CDuiString& operator=(const CDuiString& src); const CDuiString& operator=(const TCHAR ch); const CDuiString& operator=(LPCTSTR pstr); #ifdef _UNICODE const CDuiString& CDuiString::operator=(LPCSTR lpStr); const CDuiString& CDuiString::operator+=(LPCSTR lpStr); #else const CDuiString& CDuiString::operator=(LPCWSTR lpwStr); const CDuiString& CDuiString::operator+=(LPCWSTR lpwStr); #endif CDuiString operator+(const CDuiString& src) const; CDuiString operator+(LPCTSTR pstr) const; const CDuiString& operator+=(const CDuiString& src); const CDuiString& operator+=(LPCTSTR pstr); const CDuiString& operator+=(const TCHAR ch); bool operator == (LPCTSTR str) const; bool operator != (LPCTSTR str) const; bool operator <= (LPCTSTR str) const; bool operator < (LPCTSTR str) const; bool operator >= (LPCTSTR str) const; bool operator > (LPCTSTR str) const; int Compare(LPCTSTR pstr) const; int CompareNoCase(LPCTSTR pstr) const; void MakeUpper(); void MakeLower(); CDuiString Left(int nLength) const; CDuiString Mid(int iPos, int nLength = -1) const; CDuiString Right(int nLength) const; int Find(TCHAR ch, int iPos = 0) const; int Find(LPCTSTR pstr, int iPos = 0) const; int ReverseFind(TCHAR ch) const; int Replace(LPCTSTR pstrFrom, LPCTSTR pstrTo); int __cdecl Format(LPCTSTR pstrFormat, ...); int __cdecl SmallFormat(LPCTSTR pstrFormat, ...); protected: LPTSTR m_pstr; TCHAR m_szBuffer[MAX_LOCAL_STRING_LEN + 1]; }; ~~~ 下面使用方法: ~~~ 1 Append(LPCTSTR str) 在原字符串基础上追加一个字符串; CDuiString dui_str; dui_str.Append(_T("我是中国人!")); dui_str.Append(_T("我爱中国!")); 2 Assign(LPCSTR pstr ,int nLength ) 在pstr字符串的nLength位置后的东西全部剪切掉不要; config.Assign(config, config.GetLength()-1); 3 Format(LPCSTR pstrformat, ...); 按照pstrformat字符串的格式,导入其他类型变量 CDuiString folde_path; folde_path.Format(_T("%ls"), std_string); 4 GetLength()采集一个变量的宽度(大小); config.GetLength(); ~~~ 很多时候 难免用到CDuiString和string的转换。 我们应该注意到,CDuiString类有个方法: ~~~ LPCTSTR GetData() const; ~~~ 可以通过这个方法,把CDuiString变为LPCTSTR ;  所以下一步只是如何把LPCTSTR 转为string了。 首先写一个StringFromLPCTSTR函数,完成转换: ~~~ std::string StringFromLPCTSTR(LPCTSTR str) { #ifdef _UNICODE int size_str = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, NULL, NULL); char* point_new_array = new char[size_str]; WideCharToMultiByte(CP_UTF8, 0, str, -1, point_new_array, size_str, NULL, NULL); std::string return_string(point_new_array); delete[] point_new_array; point_new_array = NULL; return return_string; #else return std::string(str); #endif } ~~~ 下面就可以完成duicstring到string的转换了: ~~~ CDuiString download_link = msg.pSender->GetUserData(); std::string download_link_str = StringFromLPCTSTR(download_link.GetData()); ~~~
';

std:vector<char> 和std:string相互转换(vector to stringstream)

最后更新于:2022-04-01 06:41:40

##实战c++中的string系列--std:vector<char> 和std:string相互转换(vector to stringstream) 有时候也会遇到std:vector与转std:string 相互转换的情况。 首先看一下`vector<char>`如何转string: ~~~ std::vector<char> *data = response->getResponseData(); std::string res; //方法一 for (int i = 0;i<data->size();++i) { res+=(*data)[i]; } res+='\0'; std:cout << res; //方法二 std::vector<char> *data = response->getResponseData(); std::string res; res.insert(res.begin(), data->begin(), data->end()); std::cout << res; //方法三 std::vector<char> *data = response->getResponseData(); std::string res; const char* s = &(*data->begin()); res = std::string(s, data->size()); std::cout << res; //方法四 string ch = "what a fucking day!"; vector <char> ta; ta.resize(ch.size()); ta.assign(ch.begin(),ch.end()); ~~~ string 转vector就会更容易: ~~~ vector <char> ta = {‘a’, 'b', 'c'}; ch.clear(); ch.assign(ta.begin(),ta.end()); ~~~ ================================================================  **vector to stringstream** ~~~ #include <iostream> #include <sstream> #include <vector> #include <string> #include <iterator> // Dummy std::vector of strings std::vector<std::string> sentence; sentence.push_back("aa"); sentence.push_back("ab"); // Required std::stringstream object std::stringstream ss; // Populate std::copy(sentence.begin(), sentence.end(),std::ostream_iterator<std::string>(ss,"\n")); // Display std::cout<<ss.str()<<std::endl; ~~~
';

string到LPCWSTR的转换

最后更新于:2022-04-01 06:41:38

##实战c++中的string系列--string到LPCWSTR的转换 今天再来介绍一下如何从string到LPCWSTR的转换。 LPCWSTR是什么类型呢?  看看如何定义的: ~~~ typedef const wchar_t* LPCWSTR; ~~~ 顾名思义就是:  LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符串是wchar型,而不是char型。 比如说MessageBoxW的第二、第三个参数就是LPCWSTR类型。 ~~~ `MessageBoxW(__in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType)` ~~~ 所以问题来了,有一个string类型的字符串,如何通过MessageBoxW进行显示呢?这就需要string到LPCWSTR类型的转换了!! ~~~ string image_path = "c:\\avi.png"; size_t size = image_path.length(); wchar_t *buffer = new wchar_t[size + 1]; MultiByteToWideChar(CP_ACP, 0, response->image_path.c_str(), size, buffer, size * sizeof(wchar_t)); buffer[size] = 0; //确保以 '\0' 结尾 ::MessageBox(NULL, buffer, NULL, NULL); delete buffer; buffer = null; ~~~ 看到了吧 又一次用了MultiByteToWideChar函数。所以牢记这个函数的用法。  [http://blog.csdn.net/wangshubo1989/article/details/49210385](http://blog.csdn.net/wangshubo1989/article/details/49210385)
';

std::string与MFC中CString的转换

最后更新于:2022-04-01 06:41:35

##实战c++中的string系列--std::string与MFC中CString的转换 搞过MFC的人都知道cstring,给我们提供了很多便利的方法。 CString 是一种很有用的数据类型。它们很大程度上简化了MFC中的许多操作,使得MFC在做字符串操作的时候方便了很多。不管怎样,使用CString有很多特殊的技巧,特别是对于纯C背景下走出来的程序员来说有点难以学习。 但是很多情况下,我们还是需要cstring和string的转换。  分两步:  1把cstring转为char数组  2根据char数组,构造自己的string(记得释放内存) ~~~ std::string CStringToSTDStr(const CString& theCStr) { const int theCStrLen = theCStr.GetLength(); char *buffer = (char*)malloc(sizeof(char)*(theCStrLen+1)); memset((void*)buffer, 0, sizeof(buffer)); WideCharToMultiByte(CP_UTF8, 0, static_cast<cstring>(theCStr).GetBuffer(), theCStrLen, buffer, sizeof(char)*(theCStrLen+1), NULL, NULL); std::string STDStr(buffer); free((void*)buffer); return STDStr; } ~~~ 而string转cstring那就很轻松了: ~~~ string str="abcde"; CString cstr(str.c_str()); ~~~ [](http://blog.csdn.net/wangshubo1989/article/details/50274079#)[](http://blog.csdn.net/wangshubo1989/article/details/50274079# "分享到QQ空间")[](http://blog.csdn.net/wangshubo1989/article/details/50274079# "分享到新浪微博")[](http://blog.csdn.net/wangshubo1989/article/details/50274079# "分享到腾讯微博")[](http://blog.csdn.net/wangshubo1989/article/details/50274079# "分享到人人网")[](http://blog.csdn.net/wangshubo1989/article/details/50274079# "分享到微信")
';

string的遍历(使用下标还是iterator)

最后更新于:2022-04-01 06:41:33

##实战c++中的string系列--string的遍历(使用下标还是iterator) 迭代器提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符地方法的类对象. 我们都知道可以用下标运算来访问string对象和vector对象。而另外还有一种更通用的方法也可以实现这样的方法。名曰:迭代器(iterator)。 类似于指针,迭代器也提供了对对象的间接访问。就迭代器而言,其对象是容器中的元素或者string中的字符。使用迭代器可以访问某个元素,迭代器也能从一个元素移动到另外一个元素。迭代器有有效和无效之分,有效的迭代器指向某个元素或者容器中尾元素的下一个位置。其他情况均为无效。 和指针不一样的是,迭代器不是使用取址符,而是使用begin和end成员。  结合解引用和成员访问操作 解引用迭代器可以获得迭代器所指的对象,如果该对象的类型恰好是类,那么就可以访问这个类的成员。例如: (*it).empty(); 这里要注意*it一定要加圆括号,否则会出错。如果不加,那么这句话的意思就变成了访问it的empty成员,但是it是个迭代器,没有empty成员。C++11中提供了箭头运算符->,箭头运算符把解引用和成员访问两个操作结合在了一起。故iter->mem 等价于(*iter).mem。 强烈注意:一旦使用了迭代器的循环体,那就不要向迭代器所属的容器添加元素。 迭代器的算术运算: iter + n 迭代器加上一个整数后仍是一个迭代器,在这里迭代器和指针很像,可以理解成地址上的加减。 iter1 - iter2 两个迭代器相减的结果是它们之间的距离。即所指向位置的距离。 ,>= 迭代器关系运算符,如果某迭代器指向的容器位置在另一个迭代器所指位置之前,则说前者小于后者。 ==============================================================  为何string vector可以使用下标访问,还设计了迭代器模式呢? 个人觉得:  **1、STL设置的初衷是,算法 容器分离**  **2、迭代器更通用些,有的容器对象不支持下标**  **3、一些方法,比如erase只能传递iterator** 就vector来说差别不大,迭代器其实就是原生指针,但是就C++整体容器来说还是迭代器好,像list这些容器等等,迭代器给你提供一个中间层,抽象掉各容器间的差异,让你能以相同的方式访问容器
';

string的初始化、删除、转大小写(construct erase upper-lower)

最后更新于:2022-04-01 06:41:31

##实战c++中的string系列--string的初始化、删除、转大小写(construct erase upper-lower) string是有迭代器设计模式的,我还没有体会到迭代器带给我的好处,很多时候使用类似数组索引的方法就可以完成任务。 **场景1:删除string所有的大写字母**  这里用到erase方法: ~~~ #include<iostream> #include<cctype> #include<string> using namespace std; int main() { string str = "This IS A trick"; for(string::iterator iter = str.begin(); iter != str.end();++iter){ if(isupper(*iter)){ str.erase(iter); --iter; } } for(string::iterator iter = str.begin(); iter != str.end();++iter) cout<<*iter<<" "; return 0; } ~~~ 上面的代码会错误,原因之前博客《[没有躲过的坑–vector使用erase后迭代器变成野指针](http://blog.csdn.net/wangshubo1989/article/details/50121059 "erase陷阱")》说过,即erase后,迭代器指向的位置。 **场景2:初始化string**  之前博客讨论过string的初始化问题,朝花夕拾: ~~~ #include<iostream> #include<string> using namespace std; int main() { string s = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" + 'A'; int t = 'A'; string s1 = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" + t; cout << t << endl; cout << s << endl; cout << s1 << endl; return 0; } ~~~ 输出结果出乎意料:  65  tuvwxyz  tuvwxyz 这里需要提醒的是弄清楚字符和字符串的区别,千万别把双引号写成了单引号。  原因:  char 类型转成整形  对const char *进行指针偏移后的指针传给string的构造函数 **场景3:string中的字母转大小写**  常规的for循环就不写了,直接写一个很少用到的: ~~~ #include <iostream> #include <algorithm> using namespace std; int main() { string str = "heLLo"; //可以不包含<string> transform(str.begin(), str.end(), str.begin(), toupper); cout<<str<<endl;//错误,因为没包含<string> cout<<str.c_str()<<endl; transform(str.begin(), str.end(), str.begin(), tolower); cout<<str.c_str()<<endl; } ~~~ 这里需要注意的是,cout不能直接输出string。  这就引出个重要的话题,不包含string头文件,string可以用;包含string头文件,string也可以用?  我猜想是标准库不断更新的原因,也为了兼容之前的老版本
';

string的分割、替换(类似string.split或是explode())

最后更新于:2022-04-01 06:41:29

##实战c++中的string系列--string的分割、替换(类似string.split或是explode()) 对一个字符串根据某个字符进行分割也是在实战中经常遇到的问题,也是面试中经常会被人提及的。 如果你是个C Sharp程序员,你会知晓string.split函数,有下面这些重载: 1) public string[] Split(params char[] separator) 2) public string[] Split(char[] separator, int count) 3) public string[] Split(char[] separator, StringSplitOptions options) 4) public string[] Split(string[] separator, StringSplitOptions options) 5) public string[] Split(char[] separator, int count, StringSplitOptions options) 6) public string[] Split(string[] separator, int count, StringSplitOptions options) 如果你是个PHP程序员,你也会使用explode方法。 但是如果你是C++程序员,或是进行C++开发,那么这里的string就没有现成的分割方法。我们需要自行实现。 ~~~ const vector<string> explode(const string& s, const char& c) { string buff{""}; vector<string> v; for(auto n:s) { if(n != c) buff+=n; elseif(n == c && buff != "") { v.push_back(buff); buff = ""; } } if(buff != "") v.push_back(buff); return v; } //使用自定义的字符串分割函数 int main() { string str{"the quick brown fox jumps over the lazy dog"}; vector<string> v{explode(str, ' ')}; for(auto n:v) cout << n << endl; return 0; } //输出如下: the quick brown fox ... ~~~ 下面是另一种形式: ~~~ int split(const string& str, vector<string>& ret_, string sep = ",") { if (str.empty()) { return 0; } string tmp; string::size_type pos_begin = str.find_first_not_of(sep); string::size_type comma_pos = 0; while (pos_begin != string::npos) { comma_pos = str.find(sep, pos_begin); if (comma_pos != string::npos) { tmp = str.substr(pos_begin, comma_pos - pos_begin); pos_begin = comma_pos + sep.length(); } else { tmp = str.substr(pos_begin); pos_begin = comma_pos; } if (!tmp.empty()) { ret_.push_back(tmp); tmp.clear(); } } return 0; } ~~~ ============================================================= 其他语言的string也有replace的方法,那么再c++中我们也可以自己实现这个方法: ~~~ string replace(const string& str, const string& src, const string& dest) { string ret; string::size_type pos_begin = 0; string::size_type pos = str.find(src); while (pos != string::npos) { cout <<"replacexxx:" << pos_begin <<" " << pos <<"\n"; ret.append(str.data() + pos_begin, pos - pos_begin); ret += dest; pos_begin = pos + 1; pos = str.find(src, pos_begin); } if (pos_begin < str.length()) { ret.append(str.begin() + pos_begin, str.end()); } return ret; } ~~~ ================================================================ 最后介绍一个C中的函数,用于截取字符串: 原型:extern char *strtok(char *s, char *delim); ~~~ #include <stdio.h> #include <string.h> int main () { char str[] ="- This, a sample string."; char * pch; printf ("Splitting string \"%s\" into tokens:\n",str); pch = strtok (str," ,.-"); while (pch != NULL) { printf ("%s\n",pch); pch = strtok (NULL, " ,.-"); } return 0; } ~~~ 输出: Splitting string “- This, a sample string.” into tokens: This a sample string
';

string的替换、查找(一些与路径相关的操作)

最后更新于:2022-04-01 06:41:26

##实战c++中的string系列--string的替换、查找(一些与路径相关的操作) 今天继续写一些string操作。  string给我们提供了很多的方法,但是每在使用的时候,就要费些周折。 场景1:  得到一个std::string full_path = “D:\program files\csdn”,但是我想得到”D:\program files\vagaa”这个路径。  这就需要字符串的替换 ~~~ std::string full_path = "D:\\program files\\csdn" const size_t last_slash_idx1 = full_path .find_last_of("\\/"); if (std::string::npos != last_slash_idx1) { full_path.erase(last_slash_idx1, std::string::npos); } std::string my_path = full_path + "\\vagaa"; ~~~ 这里用到了string的** find_last_of**方法,并使用了**erase**方法进行删除。 场景2:  得到一个std::string full_image_path = “D:\program files\csdn\vagaa.png”,但是我想根据这个路径得到文件的扩展名。  我们可以使用find_last_of+erase方法进行,还可以这么做: ~~~ std::string full_image_path = "D:\\program files\\csdn\\vagaa.png" std::string file_extension_name; size_t i = full_image_path .rfind('.', file_path.length()); if (i != string::npos) { file_extension_name = full_image_path .substr(i + 1, full_image_path .length() - i); } ~~~ 此时用到了string的**rfind**方法和**substr**方法 场景3 ===============================================================  基本知识:  出自博客[http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html](http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html) **string类的构造函数:**  string(const char *s); //用c字符串s初始化  string(int n,char c); //用n个字符c初始化  此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2=”hello”;都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常 ; **string类的字符操作:**  const char &operator[](int n)const;  const char &at(int n)const;  char &operator[](int n);  char &at(int n);  operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。  const char *data()const;//返回一个非null终止的c字符数组  const char *c_str()const;//返回一个以null终止的c字符串  int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目 **string的特性描述:**  int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)  int max_size()const; //返回string对象中可存放的最大字符串的长度  int size()const; //返回当前字符串的大小  int length()const; //返回当前字符串的长度  bool empty()const; //当前字符串是否为空  void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分 **string类的输入输出操作:**  string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。  函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符’\n’分开。 **string的赋值:**  string &operator=(const string &s);//把字符串s赋给当前字符串  string &assign(const char *s);//用c类型字符串s赋值  string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值  string &assign(const string &s);//把字符串s赋给当前字符串  string &assign(int n,char c);//用n个字符c赋值给当前字符串  string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串  string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串 **string的连接:**  string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾  string &append(const char *s); //把c类型字符串s连接到当前字符串结尾  string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾  string &append(const string &s); //同operator+=()  string &append(const string &s,int pos,int n);//字符串中从pos开始的n个字符连接到当前字符串的结尾  string &append(int n,char c); //在当前字符串结尾添加n个字符c  string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾 **string的比较:**  bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等  运算符”>”,”=”,”<=”,”!=”均被重载用于字符串的比较;  int compare(const string &s) const;//比较当前字符串和s的大小  int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小  int compare(int pos, int n,const string &s,int pos2,int n2)const;  int compare(const char *s) const;  int compare(int pos, int n,const char *s) const;  int compare(int pos, int n,const char *s, int pos2) const;  compare函数在>时返回1,<时返回-1,==时返回0 **string的子串:**  string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串 **string的交换:**  void swap(string &s2); //交换当前字符串与s2的值 **string类的查找函数:**  int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置  int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置  int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置  int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置  //查找成功时返回所在位置,失败返回string::npos的值  int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置  int rfind(const char *s, int pos = npos) const;  int rfind(const char *s, int pos, int n = npos) const;  int rfind(const string &s,int pos = npos) const;  //从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值  int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置  int find_first_of(const char *s, int pos = 0) const;  int find_first_of(const char *s, int pos, int n) const;  int find_first_of(const string &s,int pos = 0) const;  //从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos  int find_first_not_of(char c, int pos = 0) const;  int find_first_not_of(const char *s, int pos = 0) const;  int find_first_not_of(const char *s, int pos,int n) const;  int find_first_not_of(const string &s,int pos = 0) const;  //从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos  int find_last_of(char c, int pos = npos) const;  int find_last_of(const char *s, int pos = npos) const;  int find_last_of(const char *s, int pos, int n = npos) const;  int find_last_of(const string &s,int pos = npos) const;  int find_last_not_of(char c, int pos = npos) const;  int find_last_not_of(const char *s, int pos = npos) const;  int find_last_not_of(const char *s, int pos, int n) const;  int find_last_not_of(const string &s,int pos = npos) const;  //find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找 **string类的替换函数:**  string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s  string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符  string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s  string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符  string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c  string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间部分替换为字符串s  string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符  string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s  string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间部分替换为n个字符c  string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串 **string类的插入函数:**  string &insert(int p0, const char *s);  string &insert(int p0, const char *s, int n);  string &insert(int p0,const string &s);  string &insert(int p0,const string &s, int pos, int n);  //前4个函数在p0位置插入字符串s中pos开始的前n个字符  string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c  iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置  void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符  void insert(iterator it, int n, char c);//在it处插入n个字符c **string类的删除函数**  iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置  iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置  string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串 **string类的迭代器处理:**  string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。  用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:  const_iterator begin()const;  iterator begin(); //返回string的起始位置  const_iterator end()const;  iterator end(); //返回string的最后一个字符后面的位置  const_iterator rbegin()const;  iterator rbegin(); //返回string的最后一个字符的位置  const_iterator rend()const;  iterator rend(); //返回string第一个字符位置的前面  rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现
';

指定浮点数有效数字并转为string

最后更新于:2022-04-01 06:41:24

##实战c++中的string系列--指定浮点数有效数字并转为string 上一篇博客讲了好几种方法进行number到string的转换,这里再单独说一下float或是double到string的转换。 还是处于控件显示的原因,比如说要显示文件的大小,我们从服务器可以获得这个文件的总bytes。这样就需要我们根据实际情况是显示bytes、kb、mb等单位。 常用的做法就是把num_bytes/1024,这个时候往往会得到浮点型,浮点型转string也没问题,但是如果你需要保留这个浮点型的一位或是几位小数,怎么操作会方便快捷呢? 你进行了相关搜索,但是很多人给你的回答都是要么使用cout, 要么使用printf进行格式化输出。 **我们使用的是stringstream** Stringstreams allow manipulators and locales to customize the result of these operations so you can easily change the format of the resulting string ~~~ #include <iomanip> #include <locale> #include <sstream> #include <string> // this should be already included in <sstream> // Defining own numeric facet: class WithComma: public numpunct<char> // class for decimal numbers using comma instead of point { protected: char do_decimal_point() const { return ','; } // change the decimal separator }; // Conversion code: double Number = 0.12; // Number to convert to string ostringstream Convert; locale MyLocale( locale(), new WithComma);// Crate customized locale Convert.imbue(MyLocale); // Imbue the custom locale to the stringstream Convert << fixed << setprecision(3) << Number; // Use some manipulators string Result = Convert.str(); // Give the result to the string // Result is now equal to "0,120" ~~~ **setprecision**  控制输出流显示浮点数的有效数字个数 ,如果和fixed合用的话,可以控制小数点右面的位数  但是这里需要注意的是头文件: ~~~ #include <iomanip> ~~~
';

string与整型或浮点型互转

最后更新于:2022-04-01 06:41:22

##实战c++中的string系列--string与整型或浮点型互转 教科书中很少会提到string与int或是float的相互转换,但是在实际工程中会经常遇到,尤其在做UI控件显示的时候。比如说你要在edit控件中显示一个数值,那你就需要把这个数值首先转为string,然后再将这个string付给edit控件。 网上你会找到很多的转换方法,个人觉得效率差不多的情况下,简洁最好。 这里主要用到的是**stringstreams**: stringstream 是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的 iostream、fstream 有类似的操作方式。要使用 stringstream, 必須先加入這一行: ~~~ #include <sstream> ~~~ stringstream 主要是用在將一個字串分割,可以先用 clear( )以及 str( ) 將指定字串設定成一开始的內容,再用 >> 把个別的资料输出,例如: ~~~ string s; stringstream ss; int a, b, c; getline(cin, s); ss.clear(); ss.str(s); ss >> a >> b >> c; ~~~ 下面就言归正传。  **1、stringstreams中number to string**  主要是两步走:  把number输出到stream  从stream中得到string ~~~ int Number = 123; string Result; ostringstream convert; convert << Number; Result = convert.str(); ~~~ 可以将上述代码缩略成一句话: ~~~ int Number = 123; string String = static_cast<ostringstream*>( &(ostringstream() << Number) )->str(); ~~~ 这里需要说明的是,number不限于int,float一样可以工作 **2、stringstreams中string to number**  同样需要两步走:  根据string构造一个stream  将value 读到变量中 ~~~ string Text = "456"; int Result; istringstream convert(Text); if ( !(convert >> Result) ) { Result = 0; //if that fails set 'Result' to 0 } ~~~ 同样,也可以对上面的代码进行简化: ~~~ string Text = "456"; int Number; if ( ! (istringstream(Text) >> Number) ) Number = 0; ~~~ **3、C++11中number string互转**  C++11为我们提供了更为便利的方法: 整型、浮点型转string  **std::to_string**  重载如下:  string to_string (int val);  string to_string (long val);  string to_string (long long val);  string to_string (unsigned val);  string to_string (unsigned long val);  string to_string (unsigned long long val);  string to_string (float val);  string to_string (double val);  string to_string (long double val); **字符串转整型:**  **stoi, stol, stoll** **字符串转浮点型:**  **stof, stod, stold** ~~~ int number = 123; string text = to_string(number); text = "456" number = stoi(number); ~~~ **4、C - stdio中的string与number转换**  Number to String ~~~ int Number = 123; char Result[16]; sprintf ( Result, "%d", Number ); ~~~ String to Number ~~~ char Text[] = "456"; int Result; sscanf ( Text, "%d", &Result ); ~~~ **5、C - stdlib中的string与number转换**  itoa  atoi  atol  atof  strtol  strtoul  strtod  但需要注意的是,上面的几个函数并非标准,尽量少用。
';

前言

最后更新于:2022-04-01 06:41:19

> 原文出处:[实战c++中的string系列专栏文章](http://blog.csdn.net/column/details/wangshubostring.html) > 作者:[王书博](http://blog.csdn.net/wangshubo1989) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 实战c++中的string系列 > 本专栏主要记录和讲诉实际工作中,关于string的一些操作,一些tips和一些tricks.
';