1. 程式人生 > >C++ string和stringstream用法

C++ string和stringstream用法

轉自https://blog.csdn.net/sunshineacm/article/details/78068987

一、string

string 是 C++ 提供的字串型別,和 C 的字串相比,除了有不限長度的優點外,還有其他許多方便的功能。要使用 string, 必須先加入這一行:

#include <string>

接下來要定義一個字串變數,可以寫成:

string s;

我們也可以在定義的同時初始化字串:

string s = "you";

而要取得其中某一個字元,和傳統C 的字串一樣是用 s[i]

 的方式取得。比較不一樣的是如果 s 有三個字元,傳統 C 的字串的 s[3] 是'\0' 字元,但是 C++ 的 string 則是隻到 s[2] 這個字元而已。


做一個對照:

操作 string 字元陣列
定義字串
string s; char s[100];
取得第i個字元 s[i] s[i]
字串長度 s.length()
或 s.size()
strlen(s)
讀入一行
getline(cin, s); gets(s);
賦值 s = "you"; strcpy(s, "you");
字串連線 s = s + "you";
s += "you";
strcat(s, "you");
字串比較 s == "you" strcmp(s, "you");


兩個string常用的方法是find和substr。在下面的程式碼當中:find函式從str的第3個位置查起,找到ssdf這個子串後,返回子串的位置。而substr函式從pos位置開始,擷取5個字元,賦值給str2。也就是說,str2之後的內容將是ssdfs。


  
  1. string str = "aaaaddddssdfsasdf";
  2. size_t pos = str.find( "ssdf", 3);
  3. //可以用if(pos == string::npos) 用來判斷是否找到子串。
  4. //傳送門: http://blog.csdn.net/sunshineacm/article/details/78075135
  5. string str2 = str.substr(pos, 5);


二、stringstream

stringstream是 C++ 提供的另一個字串型的串流(stream)物件,和之前學過的iostreamfstream有類似的操作方式。要使用stringstream, 必須先加入這一行:

#include <sstream>

stringstream主要是用在將一個字串分割,可以先用.clear( )以及.str( )將指定字串設定成一開始的內容,再用>>把個別的資料輸出。


舉個例子:

題目:輸入的第一行有一個數字 N 代表接下來有 N 行資料,每一行資料裡有不固定個數的整數(最多20個,每行最大200個字元),程式設計將每行的總和打印出來。

輸入:

3
1 2 3
20 17 23 54 77 60
111 222 333 444 555 666 777 888 999

輸出:

6
251
4995


程式碼:


  
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.      string s;
  8.      stringstream ss;
  9.      int n;
  10.      cin >> n;
  11.     getline( cin, s);  //讀取換行
  12.      for ( int i = 0; i < n; i++)
  13.     {
  14.         getline( cin, s);
  15.         ss.clear();
  16.         ss.str(s);
  17.          int sum = 0;
  18.          while ( 1)
  19.         {
  20.              int a;
  21.             ss >> a;
  22.              if(ss.fail())
  23.                  break;
  24.             sum += a;
  25.         }
  26.          cout << sum << endl;
  27.     }
  28.      return 0;
  29. }

三、使用stringstream簡化型別轉換

C++標準庫中的<sstream>提供了比ANSI C的<stdio.h>更高階的一些功能,即單純性、型別安全和可擴充套件性。接下來,我將舉例說明怎樣使用這些庫來實現安全和自動的型別轉換。

一個例子:


  
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int n = 10000;
  5. char s[ 10];
  6. sprintf(s, "%d", n);
  7. //s中的內容為“10000”
  8. //到目前為止看起來還不錯。但是,對上面程式碼的一個微小的改變就會使程式發生錯誤
  9. printf( "%s\n", s);
  10. sprintf(s, "%f", n);
  11. //錯誤的格式化符
  12. printf( "%s\n", s);
  13. return 0;
  14. }
輸出:


在這種情況下,由於錯誤地使用了 %f 格式化符來替代了%d。因此,s在呼叫完sprintf()後包含了一個不確定的字串。要是能自動推匯出正確的型別,那不是更好嗎?

進入stringstream:

由於ns的型別在編譯期就確定了,所以編譯器擁有足夠的資訊來判斷需要哪些轉換。<sstream>庫中宣告的標準類就利用了這一點,自動選擇所必需的轉換。而且,轉換結果儲存在stringstream物件的內部緩衝中。你不必擔心緩衝區溢位,因為這些物件會根據需要自動分配儲存空間。

<sstream>庫定義了三種類:istringstream、ostringstream和stringstream,分別用來進行流的輸入、輸出和輸入輸出操作。另外,每個類都有一個對應的寬字符集版本。簡單起見,我主要以stringstream為中心,因為每個轉換都要涉及到輸入和輸出操作。

注意,<sstream>使用string物件來代替字元陣列。這樣可以避免緩衝區溢位的危險。而且,傳入引數和目標物件的型別被自動推匯出來,即使使用了不正確的格式化符也沒有危險。

1、string到int的轉換


  
  1. string result = "10000";
  2. int n = 0;
  3. stream << result;
  4. stream >> n; //n等於10000


2.重複利用stringstream物件

如果你打算在多次轉換中使用同一個stringstream物件,記住在每次轉換前要使用clear()方法。

在多次轉換中重複使用同一個stringstream(而不是每次都建立一個新的物件)物件最大的好處在於效率。stringstream物件的構造和解構函式通常是非常耗費CPU時間的。


3.在型別轉換中使用模板

你可以輕鬆地定義函式模板來將一個任意的型別轉換到特定的目標型別。例如,需要將各種數字值,如int、long、double等等轉換成字串,要使用以一個string型別和一個任意值t為引數的to_string()函式。to_string()函式將t轉換為字串並寫入result中。使用str()成員函式來獲取流內部緩衝的一份拷貝。


  
  1. template<class T>
  2. void to_string(string &result, const T &t)
  3. {
  4. ostringstream oss; //建立一個流
  5. oss << t; //把值傳遞入流中
  6. result = oss.str(); //獲取轉換後的字元並將其寫入result
  7. }
  8. //這樣,你就可以輕鬆地將多種數值轉換成字串了
  9. to_string(s1, 10.5); //double到string
  10. to_string(s2, 123); //int到string
  11. to_string(s3, true); //bool到string
  12. //可以更進一步定義一個通用的轉換模板,用於任意型別之間的轉換。函式模板convert()含有兩個模板引數out_type和in_value,功能是將in_value值轉換成out_type型別:
  13. template< class out_type, class in_value>
  14. out_type convert(const in_value & t)
  15. {
  16. stringstream stream;
  17. stream << t; //向流中傳值
  18. out_type result; //這裡儲存轉換結果
  19. stream >> result; //向result中寫入值
  20. return result;
  21. }
測試程式碼:


  
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. using namespace std;
  5. template< class T>
  6. void to_string(string &result, const T &t)
  7. {
  8. ostringstream oss;
  9. oss << t;
  10. result = oss.str();
  11. }
  12. template< class out_type, class in_value>
  13. out_type convert(const in_value & t)
  14. {
  15. stringstream stream;
  16. stream << t;
  17. out_type result;
  18. stream >> result;
  19. return result;
  20. }
  21. int main()
  22. {
  23. //to_string例項
  24. string s1, s2, s3;
  25. to_string(s1, 10.5); //double到string
  26. to_string(s2, 123); //int到string
  27. to_string(s3, true); //bool到string
  28. cout << s1 << endl << s2 << endl << s3 << endl << endl;
  29. //convert()例子
  30. double d;
  31. string salary;
  32. string s = "12.56";
  33. d = convert < double> (s); //d等於12.56
  34. salary = convert < string> ( 9000.0); //salary等於"9000"
  35. cout << d << endl << salary << endl;
  36. return 0;
  37. }
輸出:



4.結論

在過去留下來的程式程式碼和純粹的C程式中,傳統的<stdio.h>形式的轉換伴隨了我們很長的一段時間。但是,如文中所述,基於stringstream的轉換擁有型別安全和不會溢位這樣的特性,使我們有充足得理由去使用<sstream>。<sstream>庫還提供了另外一個特性—可擴充套件性。你可以通過過載來支援自定義型別間的轉換。


5.一些例項

stringstream通常是用來做資料轉換的。相比c庫的轉換,它更加安全,自動和直接。

例子一: 基本資料型別轉換例子 int 轉 string


  
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. using namespace std;
  5. int main()
  6. {
  7. stringstream ss;
  8. string s;
  9. int i = 1000;
  10. ss << i;
  11. ss >> s;
  12. cout << s << endl;
  13. return 0;
  14. }

執行結果:



例子二: 除了基本型別的轉換,也支援char *的轉換


  
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. using namespace std;
  5. int main()
  6. {
  7. stringstream ss;
  8. char s[ 10];
  9. ss << 8888;
  10. ss >> s;
  11. cout << s << endl;
  12. return 0;
  13. }

執行結果:



例子三: 再進行多次轉換的時候,必須呼叫stringstream的成員函式.clear()


  
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. using namespace std;
  5. int main()
  6. {
  7. stringstream ss;
  8. int first = 0, second = 0;
  9. ss << "456"; // 插入字串
  10. ss >> first; //轉換成int
  11. cout << first << endl;
  12. ss.clear(); //在進行多次轉換前, 必須清除ss
  13. ss << true;
  14. ss >> second;
  15. cout << second << endl;
  16. return 0;
  17. }

執行結果:

執行.clear()結果


沒有執行.clear()結果



6.使用誤區

如果stringstream使用不當,當心記憶體出問題。試試下面的程式碼,執行程式前開啟工作管理員,看看記憶體變化。

複製程式碼,把 stream.str("");  那一行的註釋去掉,再執行程式,記憶體就正常了。


看來stringstream似乎不打算主動釋放記憶體( 或許是為了提高效率 ),但如果你要在程式中用同一個流,反覆讀寫大量的資料,將會造成大量的記憶體消耗,因此這時候,需要適時地清除一下緩衝 ( 用 stream.str("")  )。

另外不要企圖用  stream.str().resize(0) 或  stream.str().clear()  來清除緩衝,使用它們似乎可以讓stringstream的記憶體消耗不要增長得那麼快,但仍然不能達到清除stringstream緩衝的效果(做個實驗就知道了,記憶體的消耗