c++的流
C++ getline函数用法
getline()函数是一个比较常见的函数。根据名字直接望文生义,就知道这个函数是来完成读入一行数据。
下面就对C++ -- getline()函数的用法说明,以及getline()函数作为while条件的问题,总结一下:
在C++中本质上有两种getline函数:
第一种:在头文件<istream>中,是iostream类的成员函数。
第二种:在头文件<string>中,是普通函数。
///////////////////////////////////////////////////////////////////////////////////////////
第一种: 在<istream>中的getline()函数有两种重载形式:
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
作用是: 从istream中读取至多n个字符(包含结束标记符)保存在s对应的数组中。即使还没读够n个字符,
如果遇到delim 或 字数达到限制,则读取终止,delim都不会被保存进s对应的数组中。
*例程代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include "stdafx.h" #include <iostream> //使用标准输入流和标准输出流。 // std::cin ; std::cout ; std::endl int main() { char name[256], wolds[256]; std::cout << "Please input your name: " ; std::cin.getline(name, 256); std::cout << "Please input your wolds: " ; std::cin.getline(wolds, 256); std::cout << "The result is: " << name << ", " << wolds << std::endl; std::cout << std::endl; return 0; } //**输入: Mr. Ling You are wonderful ! //输出: Mr. Ling, You are wonderful ! |
*通过字数限制和设置终止符修改的代码:
int main()
{
char name[6];
std::cout << "Please input your name: ";
std::cin.getline(name, 6, '#');
std::cout << "The result is: " << name << std::ends;
std::cout << std::endl;
return 0;
}
//**输入: //streamsize限定,截断输出
wonderful
//输出:
wonder
//**输入: //所设置的结束标识符,截断输出
won#derful
//输出:
won
第二种: 在<string>中的getline函数有四种重载形式:
istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);
istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);
用法和上第一种类似,但是读取的istream是作为参数is传进函数的。读取的字符串保存在string类型的str中。
函数的变量:
is :表示一个输入流,例如 cin。
str :string类型的引用,用来存储输入流中的流信息。
delim :char类型的变量,所设置的截断字符;在不自定义设置的情况下,遇到’\n’,则终止输入。
*例程代码:
#include "stdafx.h"
#include <iostream>
#include <string>
int main()
{
std::string name;
std::cout << "Please input your name: ";
std::getline(std::cin, name);
std::cout << "Welcome to here!" << std::ends << name << std::endl;
std::cout << std::endl;
return 0;
}
//std是一个类(输入输出标准),学校的using namespace std;就行了,不用没一行都家std::
在输入时,直至遇到‘\n’或EOF, 才终止输入操作。
//**输入:
wonderful
//输出:
wonderful
*例程代码:
int main()
{
std::string name;
std::cout << "Please input your name: ";
std::getline(std::cin, name, '#');
std::cout << "Welcome to here!" << std::ends << name << std::endl;
std::cout << std::endl;
return 0;
}
//注意 不能连续用两个这种形式的getline(),因为在第一个delim后面的输入会直接进入到下一个getline()输入里面(第一个delim后面紧跟的一个数字不会出现在下一个getline中,其余都会,不造为啥)
//**输入:
wonderful#Mr.Ling
//输出:
wonderful
///////////////////////////////////////////////////////////////////////////////////////////
(EOF是C语言中为了区分有效数据和输入结束符的。
EOF的输入由系统锁定。windows下是ctrl+z,linux/unix下是ctrl+d。)
getline不是C库函数,而是C++库函数。它遇到以下情况发生会导致生成的本字符串结束:
(1)到文件结束,(2)遇到函数的定界符,(3)输入达到最大限度。
getline()函数在while中作为条件判断。
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string line;
while (getline(cin, line))
cout << line << endl;
return 0;
}
大家会发现运行时一般的输入都不能够跳出循环,可能有时还会出现莫名的错误。但是这到底是什么原因造成的呢!下面就来分析一下:
getline()函数的原型是istream& getline ( istream & is , string & str , char delim );
int main()
{
string line;
cout << "Please input a line: " << endl;
while (getline(cin, line,'#'))
cout << line << endl;
return 0;
}
然后,那么当我们输入 "You are wonderful!#Mr. Ling" 时,但是,有效的输入是 "You are wonderful!",#后面的内容并没有存入。程序运行的结果如:
//输入:
You are wondreful!#LingKing
//输出:
You are wonderful!
在这里设置‘#’为终止符时,当再输入’\n’时也不会影响。在#之前的内容都会照样输出。例如:
//输入: //含有’\n’的输入
Hello world!
You are wonderful!
Mr. Ling#wonderful!
//输出: //照样输出
Hello world!
You are wonderful!
Mr. Ling
通过getline()函数一个小小的实例,那么把getline()函数作为while的判断语句会怎么样的呢!
就分析一下while(getline(cin,line))
(注意:这里默认回车符停止读入,按Ctrl+Z(Windows)(Ctrl+D(Linux))或键入EOF(参考MSDN)回车即可退出循环。)
这个语句中,while判断语句的真实判断对象是cin的状态,也就是判断当前是否存在有效的输入流。
而输入流是对象,判断的是流返回的状态。所以正常的情况下,你怎么输入都是跳不出它的循环。
有些同志误以为while判断语句的判断对象是line(也就是line是否为空),想通过回车来跳出循环,却发现不能跳出循环。
而回车和设置的终止符都是终止getline()函数的读取操作的。但是while判断语句判断的是getline()函数的输入流是否有效。
最后一行数据被输出两次的原因:
使用c++编程序,读取文件时偶然发现读取文件时最后一行的内容读取了两次,为了搞清楚是怎么回事,就好奇探索了下。
c++读取文件最后一行打印两次的原因:使用流读取文件内容,在读取完最后一个匹配内容后(本文中读取的是int类型的数据),后面仍有一些内容(空格符或换行符或制表符),此时eof()函数并没有到达文件末尾,所有循环会再次执行,但因为没有匹配(int)类型的数据了,此时a仍然保持上一次读取的内容,并打印,最终造成了一个小bug。
解决方法
因为文件内容一般是不能改动的,所以我们要从代码上进行改进,我们换掉判定条件eof(),使用以下程序:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
string str="D:/0code/dev编程/1.txt";
ifstream in;
in.open(str,ios::in);
int a;
// while(!in.eof())
// {
// in>>a;
// cout<<a<<endl;
// }
while(in>>a)
{
cout<<a<<endl;
}
return 0;
}
最后一行数据被输出两次的原因(详解):
首先,我们的测试文档如下,最后的点表示这是一个空行,实际中并没有。
new 1.23
fan 2
jin 4.444
ge 0.10203
.
1. 使用eof来判断
先看一段错误的代码
int read_1()
{
std::ifstream file("test.txt");
std::vector<std::string> word;
std::vector<float> value;
while (true) {
// A word and a double value were both read successfully
float value_tmp;
std::string word_tmp;
file >> word_tmp >> value_tmp; // >> 在添加头文件sstream之后可以使用,否则会报错
value.push_back(value_tmp);
word.push_back(word_tmp);
if( file.eof() )
break;
}
std::cout <<"--------------"<<std::endl;
for (int i = 0; i<value.size(); i++)
{
std::cout << "word:" << word[i] <<", value:" << value[i] <<std::endl;
}
file.close();
return 0;
}
或者这么写也一样
while (!file.eof()) {
// A word and a double value were both read successfully
float value_tmp;
std::string word_tmp;
file >> word_tmp >> value_tmp; //>>在添加头文件sstream之后可以使用,否则会报错
value.push_back(value_tmp);
word.push_back(word_tmp);
}
输出结果
--------------
word:new, value:1.23
word:fan, value:2
word:jin, value:4.444
word:ge, value:0.10203
word:, value:0.10203
可以看到多了一行。
分析:eof从字面意思来看,当然是end of file,用于表明当前已经到了文件末尾,不能再读了。
但这里有一个很迷惑的陷阱:只要遇到结束符,流就会将状态置为EOF,而不管置位前的操作是否成功。
例如,使用getline函数读取文件的最后一行,如果这一行是因为遇到了EOF而结束的,那么getline操作是成功的,但eof还是会置位。
2. while循环中输出
代码如下:
int read_2()
{
std::ifstream file("test.txt");
std::vector<std::string> word;
std::vector<float> value;
float value_tmp;
std::string word_tmp;
while (file >> word_tmp >> value_tmp) {
// A word and a double value were both read successfully
value.push_back(value_tmp);
word.push_back(word_tmp);
}
if (!file.eof()) throw std::runtime_error("Invalid data from file");
std::cout <<"--------------"<<std::endl;
for (int i = 0; i<value.size(); i++)
{
std::cout << "word:" << word[i] <<", value:" << value[i] <<std::endl;
}
file.close();
return 0;
}
运行结果:
--------------
word:new, value:1.23
word:fan, value:2
word:jin, value:4.444
word:ge, value:0.10203
运行正确。
3. 使用fail进行判断
int read_3()
{
std::ifstream file("test.txt");
std::string input_str;
std::vector<std::string> str;
while(file)
{
getline(file,input_str);
if(file.fail())
break;
str.push_back(input_str);
}
std::cout <<"--------------"<<std::endl;
for (int i = 0; i<str.size(); i++)
{
std::cout << str[i] <<std::endl;
}
file.close();
return 0;
}
输出
--------------
new 1.23
fan 2
jin 4.444
ge 0.10203
4. peek()进行判断
peek()方法预读取下一个字符(不管是何符号)。从流中取出一个字符,但不移动流指针位置。
int read_4()
{
std::ifstream file("test.txt");
std::vector<std::string> word;
std::vector<float> value;
while (!file.eof()) {
// A word and a double value were both read successfully
float value_tmp;
std::string word_tmp;
file >> word_tmp >> value_tmp; //>>在添加头文件sstream之后可以使用,否则会报错
value.push_back(value_tmp);
word.push_back(word_tmp);
file.get(); // 读取最后的回车符
if(file.peek() == '\n') break;
}
std::cout <<"--------------"<<std::endl;
for (int i = 0; i<value.size(); i++)
{
std::cout << "word:" << word[i] <<", value:" << value[i] <<std::endl;
}
file.close();
return 0;
}
或者这么写也可以
while (!file.eof() && file.peek()!=EOF) {
// A word and a double value were both read successfully
float value_tmp;
std::string word_tmp;
file >> word_tmp >> value_tmp; //>>在添加头文件sstream之后可以使用,否则会报错
value.push_back(value_tmp);
word.push_back(word_tmp);
file.get(); // 读取最后的回车符
}
运行结果:
--------------
word:new, value:1.23
word:fan, value:2
word:jin, value:4.444
word:ge, value:0.10203
C++文件流文件定位
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:
1. istream &seekg(streamoff offset,seek_dir origin);
2. ostream &seekp(streamoff offset,seek_dir origin);
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
ios::beg: 文件开头
ios::cur: 文件当前位置
ios::end: 文件结尾
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。
例:
1. file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节
2. file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节
如果vc编程的话最好使用CFile类等更加方便于文件操作.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
2019-05-22 文本摘要提取语料