【C++標準IO庫】字符串流

目錄

一、字符串流概述

1.1 流的概念回顧

1.2 字符串流的定義和作用

二、istringstream?的使用

2.1 基本用法

2.2 常見應用場景

三、ostringstream?的使用

3.1 基本用法

3.2 常見應用場景

四、stringstream?的使用

4.1 基本用法

4.2 常見應用場景

五、字符串流的錯誤處理和性能考慮

5.1 錯誤處理

5.2 性能考慮

5.3 性能對比與分析

六、總結

七、參考資料


在C++編程中,標準IO庫是我們處理輸入輸出操作的核心工具。除了傳統的cin/cout和文件流,字符串流(String Stream)作為一組強大的內存流工具,在字符串處理、數據轉換和格式化操作等場景中展現出獨特的優勢。

一、字符串流概述

1.1 流的概念回顧

在 C++ 中,流是一種抽象的概念,它代表了數據的來源或目的地。流可以是文件、控制臺、內存中的字符串等。通過流,我們可以進行數據的輸入(讀取)和輸出(寫入)操作。標準 IO 庫提供了一系列的流類,如?iostreamfstream?等,用于處理不同類型的流。

1.2 字符串流的定義和作用

字符串流是一種特殊的流,它以字符串作為數據的來源或目的地。C++ 標準 IO 庫提供了三個主要的字符串流類:

  • istringstream:用于從字符串中讀取數據,類似于從文件或控制臺讀取數據。
  • ostringstream:用于將數據寫入字符串,類似于將數據寫入文件或控制臺。
  • stringstream:既可以從字符串中讀取數據,也可以將數據寫入字符串,兼具?istringstream?和?ostringstream?的功能。

這些類繼承自iostream基類,因此支持所有標準流操作。它們的核心優勢在于:

  • 內存操作:直接在內存中處理字符串,無需物理文件
  • 類型安全:通過模板參數明確數據類型
  • 格式控制:支持完整的流格式控制符
  • 性能高效:相比文件操作,內存讀寫速度更快

字符串流的主要作用包括:

  • 數據類型轉換:方便地實現字符串與其他數據類型(如整數、浮點數等)之間的轉換。
  • 字符串處理:對字符串進行分割、拼接、格式化等操作。
  • 內存數據的讀寫:在內存中模擬文件或控制臺的輸入輸出操作,提高程序的靈活性和效率。

二、istringstream?的使用

2.1 基本用法

istringstream?類用于從字符串中讀取數據。使用?istringstream?時,需要包含?<sstream>?頭文件,并創建一個?istringstream?對象,將待讀取的字符串作為參數傳遞給構造函數。然后,可以使用提取運算符?>>?從字符串中讀取數據。

以下是一個簡單的示例代碼:

#include <iostream>
#include <sstream>
#include <string>int main() {std::string input = "123 45.6 hello";std::istringstream iss(input);int num;double d;std::string str;iss >> num >> d >> str;std::cout << "整數: " << num << std::endl;std::cout << "浮點數: " << d << std::endl;std::cout << "字符串: " << str << std::endl;return 0;
}

?

創建了一個?istringstream?對象?iss,并將字符串?"123 45.6 hello"?作為參數傳遞給它。然后,使用提取運算符?>>?依次從字符串中讀取一個整數、一個浮點數和一個字符串,并將它們分別存儲在變量?numd?和?str?中。最后,將讀取的數據輸出到控制臺。

2.2 常見應用場景

字符串分割istringstream?可以方便地實現字符串的分割。通過將字符串按空格或其他分隔符進行分割,可以將字符串拆分成多個子字符串。

以下是一個字符串分割的示例代碼:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>std::vector<std::string> split(const std::string& input, char delimiter) {std::vector<std::string> tokens;std::istringstream iss(input);std::string token;while (std::getline(iss, token, delimiter)) {tokens.push_back(token);}return tokens;
}int main() {std::string input = "apple,banana,orange";std::vector<std::string> tokens = split(input, ',');for (const auto& token : tokens) {std::cout << token << std::endl;}return 0;
}

?

定義了一個?split?函數,用于將字符串按指定的分隔符進行分割。在函數內部,使用?istringstream?和?std::getline?函數將字符串拆分成多個子字符串,并將它們存儲在一個?vector?中。

數據解析:在處理一些格式化的數據時,istringstream?可以幫助我們解析數據。例如,從一個包含多個數據項的字符串中提取出所需的數據。

以下是一個數據解析的示例代碼:

#include <iostream>
#include <sstream>
#include <string>struct Person {std::string name;int age;double height;
};Person parsePerson(const std::string& input) {std::istringstream iss(input);Person p;iss >> p.name >> p.age >> p.height;return p;
}int main() {std::string input = "John 25 1.75";Person p = parsePerson(input);std::cout << "姓名: " << p.name << std::endl;std::cout << "年齡: " << p.age << std::endl;std::cout << "身高: " << p.height << std::endl;return 0;
}

?

定義了一個?Person?結構體,用于存儲個人信息。然后,定義了一個?parsePerson?函數,用于從一個包含姓名、年齡和身高的字符串中解析出個人信息。在函數內部,使用?istringstream?和提取運算符?>>?從字符串中讀取數據,并將它們存儲在?Person?結構體中。

三、ostringstream?的使用

3.1 基本用法

ostringstream?類用于將數據寫入字符串。使用?ostringstream?時,需要包含?<sstream>?頭文件,并創建一個?ostringstream?對象。然后,可以使用插入運算符?<<?將數據寫入?ostringstream?對象。最后,可以通過?str()?成員函數獲取?ostringstream?對象中的字符串。

以下是一個簡單的示例代碼:

#include <iostream>
#include <sstream>
#include <string>int main() {std::ostringstream oss;int num = 123;double d = 45.6;std::string str = "hello";oss << "整數: " << num << ", 浮點數: " << d << ", 字符串: " << str;std::string output = oss.str();std::cout << output << std::endl;return 0;
}

?

創建了一個?ostringstream?對象?oss。然后,使用插入運算符?<<?將整數、浮點數和字符串寫入?oss?中。最后,通過?str()?成員函數獲取?oss?中的字符串,并將其輸出到控制臺。

3.2 常見應用場景

①字符串拼接ostringstream?可以方便地實現字符串的拼接。通過將不同類型的數據依次寫入?ostringstream?對象,然后獲取最終的字符串,可以避免使用?+?運算符進行字符串拼接時可能帶來的性能問題。

以下是一個字符串拼接的示例代碼:

#include <iostream>
#include <sstream>
#include <string>std::string concatenate(const std::string& str1, int num, const std::string& str2) {std::ostringstream oss;oss << str1 << num << str2;return oss.str();
}int main() {std::string str1 = "Hello, ";int num = 2024;std::string str2 = "!";std::string result = concatenate(str1, num, str2);std::cout << result << std::endl;return 0;
}

定義了一個?concatenate?函數,用于將兩個字符串和一個整數拼接成一個新的字符串。在函數內部,使用?ostringstream?對象將三個數據項依次寫入,然后通過?str()?成員函數獲取最終的字符串。最后,將拼接好的字符串輸出到控制臺。

②數據格式化ostringstream?可以用于對數據進行格式化輸出。通過設置流的格式標志和精度等參數,可以控制輸出數據的格式。

以下是一個數據格式化的示例代碼:

#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>std::string formatNumber(double num) {std::ostringstream oss;oss << std::fixed << std::setprecision(2) << num;return oss.str();
}int main() {double num = 3.1415926;std::string formatted = formatNumber(num);std::cout << "格式化后的數字: " << formatted << std::endl;return 0;
}

?

定義了一個?formatNumber?函數,用于將一個浮點數格式化為保留兩位小數的字符串。在函數內部,使用?std::fixed?和?std::setprecision(2)?控制輸出的格式,然后將浮點數寫入?ostringstream?對象。最后,通過?str()?成員函數獲取格式化后的字符串,并將其輸出到控制臺。

四、stringstream?的使用

4.1 基本用法

stringstream?類兼具?istringstream?和?ostringstream?的功能,既可以從字符串中讀取數據,也可以將數據寫入字符串。使用?stringstream?時,需要包含?<sstream>?頭文件,并創建一個?stringstream?對象。可以使用提取運算符?>>?從字符串中讀取數據,也可以使用插入運算符?<<?將數據寫入字符串。

以下是一個簡單的示例代碼:

#include <iostream>
#include <sstream>
#include <string>int main() {std::stringstream ss;// 寫入數據ss << "123 45.6 hello";// 讀取數據int num;double d;std::string str;ss >> num >> d >> str;std::cout << "整數: " << num << std::endl;std::cout << "浮點數: " << d << std::endl;std::cout << "字符串: " << str << std::endl;return 0;
}

?

?創建了一個?stringstream?對象?ss。首先,使用插入運算符?<<?將字符串?"123 45.6 hello"?寫入?ss?中。然后,使用提取運算符?>>?從?ss?中讀取一個整數、一個浮點數和一個字符串,并將它們分別存儲在變量?numd?和?str?中。最后,將讀取的數據輸出到控制臺。

4.2 常見應用場景

①數據類型轉換stringstream?可以方便地實現數據類型的轉換。例如,將整數或浮點數轉換為字符串,或將字符串轉換為整數或浮點數。

以下是一個數據類型轉換的示例代碼:

#include <iostream>
#include <sstream>
#include <string>// 整數轉字符串
std::string intToString(int num) {std::stringstream ss;ss << num;return ss.str();
}// 字符串轉整數
int stringToInt(const std::string& str) {std::stringstream ss(str);int num;ss >> num;return num;
}int main() {int num = 123;std::string str = intToString(num);std::cout << "整數轉字符串: " << str << std::endl;std::string input = "456";int result = stringToInt(input);std::cout << "字符串轉整數: " << result << std::endl;return 0;
}

?

定義了兩個函數:intToString?用于將整數轉換為字符串,stringToInt?用于將字符串轉換為整數。在函數內部,使用?stringstream?對象進行數據的寫入和讀取操作,實現數據類型的轉換。最后,將轉換結果輸出到控制臺。

②復雜數據處理:在處理一些復雜的數據時,stringstream?可以同時進行數據的讀取和寫入操作,方便地實現數據的處理和轉換。

以下是一個復雜數據處理的示例代碼:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>// 處理包含多個整數的字符串
std::vector<int> processString(const std::string& input) {std::stringstream ss(input);std::vector<int> numbers;int num;while (ss >> num) {numbers.push_back(num);}return numbers;
}// 將整數向量轉換為字符串
std::string vectorToString(const std::vector<int>& numbers) {std::stringstream ss;for (size_t i = 0; i < numbers.size(); ++i) {if (i > 0) {ss << " ";}ss << numbers[i];}return ss.str();
}int main() {std::string input = "1 2 3 4 5";std::vector<int> numbers = processString(input);std::cout << "處理后的整數向量: ";for (int num : numbers) {std::cout << num << " ";}std::cout << std::endl;std::string output = vectorToString(numbers);std::cout << "整數向量轉換后的字符串: " << output << std::endl;return 0;
}

?

定義了兩個函數:processString?用于處理包含多個整數的字符串,將字符串中的整數提取出來存儲在一個向量中;vectorToString?用于將整數向量轉換為字符串。在函數內部,使用?stringstream?對象進行數據的讀取和寫入操作,實現數據的處理和轉換。最后,將處理結果輸出到控制臺。

五、字符串流的錯誤處理和性能考慮

5.1 錯誤處理

在使用字符串流時,可能會出現一些錯誤,如讀取或寫入失敗等。可以通過檢查流的狀態標志來判斷是否發生了錯誤。常見的流狀態標志有:

  • good():檢查流是否處于正常狀態。
  • eof():檢查是否到達文件末尾。
  • fail():檢查是否發生了可恢復的錯誤。
  • bad():檢查是否發生了嚴重的錯誤。

以下是一個錯誤處理的示例代碼:?

#include <iostream>
#include <sstream>
#include <string>int main() {std::string input = "abc";std::istringstream iss(input);int num;if (iss >> num) {std::cout << "讀取成功: " << num << std::endl;} else {if (iss.eof()) {std::cout << "到達文件末尾!" << std::endl;} else if (iss.fail()) {std::cout << "讀取失敗,可能是數據類型不匹配!" << std::endl;} else if (iss.bad()) {std::cout << "發生了嚴重的錯誤!" << std::endl;}}return 0;
}

?

嘗試從一個包含字符串?"abc"?的?istringstream?對象中讀取一個整數。由于數據類型不匹配,讀取操作會失敗。通過檢查流的狀態標志,我們可以判斷出發生了讀取失敗的錯誤,并輸出相應的錯誤信息。

5.2 性能考慮

雖然字符串流提供了方便的輸入輸出功能,但在性能方面可能會有一定的開銷。特別是在頻繁進行字符串的讀取和寫入操作時,性能問題可能會更加明顯。為了提高性能,可以考慮以下幾點:

  • 減少不必要的流對象創建:盡量復用已有的流對象,避免頻繁創建和銷毀流對象。
  • 使用?reserve()?方法預分配內存:對于?ostringstream?和?stringstream?對象,可以使用?reserve()?方法預分配足夠的內存,減少內存重新分配的次數。

以下是一個使用?reserve()?方法預分配內存的示例代碼:

#include <iostream>
#include <sstream>
#include <string>int main() {std::ostringstream oss;// 預分配 1024 字節的內存oss.str().reserve(1024);for (int i = 0; i < 100; ++i) {oss << i << " ";}std::string result = oss.str();std::cout << "結果字符串的長度: " << result.length() << std::endl;return 0;
}

?

使用?reserve()?方法為?ostringstream?對象預分配了 1024 字節的內存。這樣,在后續的寫入操作中,就可以減少內存重新分配的次數,提高性能。

5.3 性能對比與分析

操作類型字符串流傳統方法(sprintf等)
類型安全性??
可擴展性??
內存管理自動需手動分配
異常處理支持不支持
執行速度較快極快(但存在風險)

結論:在需要類型安全和復雜格式控制的場景中,字符串流是更優選擇;在極端性能要求的簡單場景下,可考慮傳統方法。

六、總結

C++ 標準 IO 庫中的字符串流(istringstreamostringstream?和?stringstream)為我們提供了強大而靈活的字符串處理功能。通過字符串流,可以方便地實現字符串與其他數據類型之間的轉換、字符串的分割和拼接、數據的解析和格式化等操作。在使用字符串流時,需要注意錯誤處理和性能考慮,以確保程序的健壯性和高效性。

七、參考資料

  • ?《C++ Primer(第 5 版)》這本書是 C++ 領域的經典之作,對 C++ 的基礎語法和高級特性都有深入講解。
  • 《Effective C++(第 3 版)》書中包含了很多 C++ 編程的實用建議和最佳實踐。
  • 《C++ Templates: The Complete Guide(第 2 版)》該書聚焦于 C++ 模板編程,而using聲明在模板編程中有著重要應用,如定義模板類型別名等。
  • C++ 官方標準文檔:C++ 標準文檔是最權威的參考資料,可以查閱最新的 C++ 標準(如 C++11、C++14、C++17、C++20 等)文檔。例如,ISO/IEC 14882:2020 是 C++20 標準的文檔,可從相關渠道獲取其詳細內容。
  • cppreference.com:這是一個非常全面的 C++ 在線參考網站,提供了詳細的 C++ 語言和標準庫文檔。
  • LearnCpp.com:該網站提供了系統的 C++ 教程,配有豐富的示例代碼和清晰的解釋,適合初學者學習和理解相關知識。

希望本文對你理解和使用 C++ 字符串流有所幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73963.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73963.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73963.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言pthread庫的線程休眠和喚醒的案例

一、代碼如下 #include<stdio.h> #include<pthread.h> // 定義獨占鎖 pthread_mutex_t mutex; // 定義條件信號對象 pthread_cond_t condition; // 初始化函數 void init(){ int code pthread_mutex_init(&mutex, NULL); printf("共享鎖初…

人臉照片比對 API 接口如何對接?

隨著數字化程度加深&#xff0c;身份驗證的重要性也日益凸顯&#xff0c;它成為保障個人信息安全、維護交易秩序的關鍵環節。人臉照片比對 API 接口作為連接人臉比對技術與各類應用的橋梁&#xff0c;正發揮著越來越重要的作用&#xff0c;成為眾多企業和開發者實現高效、安全身…

java學習筆記9——常用類

字符串相關的類&#xff1a; String 指向同一個地址可才相等 注意這個地方&#xff0c;兩個person對象的name實際上指向的是同一個字符串常量池&#xff08;Tom&#xff09; String常用方法 總結&#xff1a; 1.string類的理解(以JDK8為例說明) 1.1 類的聲明 public final cl…

Day 09

文章目錄 指針數組指針和函數技術名詞解釋技術細節課堂筆記 指針數組 #include<stdio.h> int main() {int a[3] {0,1,2};//指針數組&#xff0c;它是數組&#xff0c;每個元素都是指針int *p[3];p[0] &a[0];p[0] a;p[1] &a[1];p[1] a1;p[2] &a[2];p[…

Nginx — Nginx安裝證書模塊(配置HTTPS和TCPS)

一、安裝和編譯證書模塊 [rootmaster nginx]# wget https://nginx.org/download/nginx-1.25.3.tar.gz [rootmaster nginx]# tar -zxvf nginx-1.25.3.tar.gz [rootmaster nginx]# cd nginx-1.25.3 [rootmaster nginx]# ./configure --prefix/usr/local/nginx --with-http_stub_…

計算機網絡 用deepseek幫助整理的復習資料(一)

### 計算機網絡基礎知識整理 --- #### **一、網絡類型** 1. **局域網 (LAN)** - **定義**&#xff1a;覆蓋小范圍&#xff08;如家庭、教室、公司&#xff09;。 - **特點**&#xff1a;高帶寬、低延遲&#xff0c;設備通過交換機互聯。 - **示例**&#xff1…

Linux SCP傳輸文件免密配置

文章目錄 Linux SCP傳輸文件免密配置生成SSH密鑰對將公鑰復制到遠程服務器測試SSH連接使用SCP免密傳輸文件可選配置帶密碼的秘鑰連接處理使用 ssh-agent進行緩存管理&#xff08;該方式只能確保同一個回話中&#xff0c;多次傳輸只輸一次密碼&#xff09;使用 keychain&#xf…

數字電子技術基礎(三十六)——利用Multisim軟件實現3線-8線譯碼器

目錄 1 手動方式實現3線-8線譯碼器 2 使用字選擇器實現3線-8線譯碼器 現在嘗試利用Multisim軟件來實現3線-8線譯碼器。本實驗目的是驗證74LS138的基本功能&#xff0c;簡單來說就是“N中選1”。 實驗設計&#xff1a; &#xff08;1&#xff09;使能信號&#xff1a;時&am…

wait和notify : 避免線程餓死(以及votile內存可見性和指令重排序問題)

各位看官&#xff0c;大家早安午安晚安呀~~~ 如果您覺得這篇文章對您有幫助的話 歡迎您一鍵三連&#xff0c;小編盡全力做到更好 歡迎您分享給更多人哦 今天我們來學習&#xff1a;wait和notify : 避免線程餓死&#xff08;以及votile內存可見性和指令重排序問題&#xff09; …

HarmonyOS 介紹

HarmonyOS簡介 隨著萬物互聯時代的開啟&#xff0c;應用的設備底座將從幾十億手機擴展到數百億IoT設備。全新的全場景設備體驗&#xff0c;正深入改變消費者的使用習慣。 同時應用開發者也面臨設備底座從手機單設備到全場景多設備的轉變&#xff0c;全場景多設備的全新底座&am…

【視覺提示學習】3.28閱讀隨想

2109.01134 CoOp通過可學習的向量來建模提示的上下文詞匯&#xff0c;這些向量可以用隨機值或預訓練的詞嵌入進行初始化&#xff08;見圖2&#xff09;。我們提供了兩種實現方式&#xff0c;以處理不同性質的任務&#xff1a;一種是基于統一上下文&#xff08;unified context…

計算機求職面試中高頻出現的經典題目分類整理

以下為計算機求職面試中高頻出現的經典題目分類整理&#xff0c;涵蓋技術核心與深度考察方向&#xff0c;答案要點已附解析思路&#xff1a; 一、數據結構與算法 鏈表操作 題目&#xff1a;反轉鏈表&#xff08;迭代/遞歸實現&#xff09;考察點&#xff1a;指針操作、遞歸思維…

uniapp選擇文件使用formData格式提交數據

1. Vue實現 在vue項目中,我們有個文件,和一些其他字段數據需要提交的時候,我們都是使用axios 設置請求頭中的Content-Type: multipart/form-data,然后new FormData的方式來進行提交。方式如下: const sendRequest = () => {const formData = new FormData()formData…

BeanDefinition和Beanfactory實現一個簡單的bean容器

目錄 什么是 Springbean 容器 設計思路 圖解 參考文章 開源地址 BeanDefinition 類 BeanFactory 類 測試類 什么是 Springbean 容器 Spring 包含并管理應用對象的配置和生命周期&#xff0c;在這個意義上它是一種用于承載對象的容器&#xff0c;你可以配置你的每個 Bea…

AI Agent開發大全第十四課-零售智能導購智能體的RAG開發理論部分

開篇 經過前面的一些課程,我們手上已經積累了各種LLM的API調用、向量庫的建立和使用、embedding算法的意義和基本使用。 這已經為我們具備了開發一個基本的問答類RAG的開發必需要素了。下面我們會來講一個基本問答類場景的RAG,零售中的“智能導購”場景。 智能導購 大家先…

向字符串添加空格

給你一個下標從 0 開始的字符串 s &#xff0c;以及一個下標從 0 開始的整數數組 spaces 。 數組 spaces 描述原字符串中需要添加空格的下標。每個空格都應該插入到給定索引處的字符值 之前 。 例如&#xff0c;s "EnjoyYourCoffee" 且 spaces [5, 9] &#xff0…

百人會上的蔚小理與「來的剛剛好」的雷軍

這就是2025百人會上的蔚小理&#xff0c;努力的李斌、宣揚飛行汽車的何小鵬與大講開源的李想。那么小米汽車的模式是什么呢&#xff1f;站在蔚小理的肩上。 這就是2025百人會上的蔚小理&#xff0c;努力的李斌、宣揚飛行汽車的何小鵬與大講開源的李想。那么小米汽車的模式是什么…

解鎖Nginx路由器匹配規則

引言 Nginx 無疑是一款備受矚目的明星產品。它以其高性能、高可靠性以及出色的并發處理能力&#xff0c;在眾多 Web 服務器和反向代理服務器中脫穎而出 &#xff0c;廣泛應用于各類網站和應用程序中。據統計&#xff0c;超過 30% 的網站都在使用 Nginx 作為其 Web 服務器&…

傳統策略梯度方法的弊端與PPO的改進:穩定性與樣本效率的提升

為什么傳統策略梯度方法&#xff08;如REINFORCE算法&#xff09;在訓練過程中存在不穩定性和樣本效率低下的問題 1. 傳統策略梯度方法的基本公式 傳統策略梯度方法的目標是最大化累積獎勵的期望值。具體來說&#xff0c;優化目標可以表示為&#xff1a; max ? θ J ( θ )…

Qwt入門

Qwt(Qt Widgets for Technical Applications)是一個用于科學、工程和技術應用的 Qt 控件庫,提供曲線圖、儀表盤、刻度尺等專業可視化組件。 1. 安裝與配置 1.1 安裝方式 源碼編譯(推薦): git clone https://github.com/qwt/qwt.git cd qwt qmake qwt.pro # 生成 Makef…