文章目录
- 一、C语言的输入和输出
- 二、C++中的IO流
- 自动类型识别
- scanf和cin等输入,都是通过空格或者换行分隔开来的
- 多行测试用例如何写输入
- 三、文件流
- ifstream读取文件
- 读取文件中不同类型的数据
一、C语言的输入和输出
C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示:
这里的设备除了终端或者是控制台之外,还可能是磁盘文件,或者是网卡。
对输入输出缓冲区的理解:
1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏
蔽这部分的差异,可以很容易写出可移植的程序。
2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。
printf/scanf
fprintf/fscanf
sprintf/sscanf
int main()
{
int a=0;
printf("%d",a);
scanf("%d",&a);
printf("%d\n",a);
}
二、C++中的IO流
istream:流提取
ostream:流输出
因为提取和输出都要写一个类,非常麻烦,就写了一个特iostream,继承了这两个类的功能
(但是因为这里存在菱形继承,所以非常复杂)
自动类型识别
int main()
{
int i=0;
double j=2.2;
cout<<i<<" "<<j<<endl;
}
这是因为库底层都对其进行了函数的重载。
istream和ostream可以更好地支撑自定义类型对象的流插入和流提取。
自定义类型可以自己重载,控制流提取和流插入的方式。
(string,日期类都可以进行流插入和流提取的重载)
scanf和cin等输入,都是通过空格或者换行分隔开来的
#include<string>
int main()
{
int year ,month ,day;
//输入多个值默认输入是用空格或者换行分隔开来的。
cin>>year>>month>>day;
scanf("%d%d%d",&year,&month,&day);
scanf("%d %d %d",&year,&month,&day);//不需要去加空格
//如果日期是20221128这样输入的
//我们可以用这种方式将我们的日期进行分隔
scanf("%4d%2d%2d",&year,&month,&day);
cout<<year<<" "<<month<<" "<<day<<endl;
//因为C++不支持类似于我们上面c语言的这种写法,所以我们只能通过字符串切割来实现
string str;
cin>>str;
year=stoi(str.substr(0,4));
month=stoi(str.substr(4,2));
day=stoi(str.substr(6,2));
cout<<year<<" "<<month<<" "<<day<<endl;
}
多行测试用例如何写输入
int main()
{
int year ,month ,day;
string str;
//使用了operate bool
//怎么终止?ctrl+c直接kill -9终止进程。
//ctr+z给一个流结束的标志。
while(cin>>str)
{
year=stoi(str.substr(0,4));
month=stoi(str.substr(4,2));
day=stoi(str.substr(6,2));
cout<<year<<"年"<<month<<"月"<<day<<"日"<<endl;
}
return 0;
}
返回值是cin类型的对象。
一般是整型指针,比较运算符表达式道德结果可以做逻辑条件判断,0就是假,非0就是真,自定义类型一般是不能做while的条件类型判断的,这里存在隐式类型转换
想要让自定义类型能够进行转换,我们需要将其进行强制类型转换,但是一般用于类型转换的()被占用了,所以我们就用operator bool,将我们的类型转化成一个bool值,并将这个bool值进行返回。
这就类似于我们下面的将我们的自定义类型a赋值给内置类型int的过程。
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
int main()
{
//内置类型转换成自定义类型
//隐式类型转换
A aa1=1;//用1构造A的临时对象,再拷贝构造aa1,优化后直接构造aa1
}
如何让我们的自定义类型转换成内置类型
class A
{
public:
A(int a)
:_a(a)
{}
//重载运算符
operator int()
{
return _a;
}
private:
int _a;
};
int main()
{
//自定义类型转换成内置类型1
int i=aa1;
cout<<i<<endl;
}
三、文件流
ifstream读取文件
int main()
{
ifstream ifs("/Users/Test.cpp");
//读取一个字符
char ch=ifs.get();
while(ifs)
{
cout<<ch;
ch=ifs.get();
}
return 0;
}
读取文件中不同类型的数据
这是我们test.txt中的内容
可以更好地兼容自定义类型的读写
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
operator bool()
{
// 这里是随意写的,假设输入_year为0,则结束
if (_year == 0)
return false;
else
return true;
}
private:
int _year;
int _month;
int _day;
};
istream& operator >> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator << (ostream& out, const Date& d)
{
out << d._year << " " << d._month <<" "<< d._day ;
return out;
}
int main()
{
ifstream ifs("/Users/test.txt");
//可以使用c语言的方式从文件中读取不同类型的数据
// fscanf("%d%s%f",)
//在c++中使用ifstream会方便一些
int i;
string s;
double d;
//对于自定义类型也是可以的
//当然,可以的前提是日期类对象重载了流提取
Date de;
//流提取
ifs>>i>>s>>d>>de;
cout<<i<<endl;
cout<<s<<endl;
cout<<d<<endl;
cout<<de<<endl;
return 0;
}