【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.mzph.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…