C++输入输出函数和底层原理详解
C++:带类的C
也就是说,C语言中的解决方案放到C++中仍然可以使用
一,C语言的输入输出方式:
C语言的标准输入输出函数,需要包含头文件<stdio.h>
在C++中,只需要包含头文件<iostream>,就可以使用C中的输入输出函数
0.stdin和stdout
0.1.stdin输入流
stdin输入流,是一个文件描述符(Linux)或者文件句柄(Windows)。其对应着输入区域,通常指键盘设备的输入。在绝大多数时候stdin可以被直接认为是键盘缓冲区。由于Unix的I/O重定向,可以将文件流重定向到任意文件和设备中,所以这里把stdin视为一个对应输入的文件。
stdin是行缓冲I/O。在使用键盘键入字符的时候,键入的字符会被放到键盘自身的缓存中(键盘硬件设备中的一部分)。在遇到换行符后,操作系统才会进行同步,将键盘缓存中的字符读入到stdin对应的内存中,叫做输入缓存区。所有从stdin读取数据的函数,都是从电脑内存中的输入缓存区读入数据。
0.2. stdout输出流
stdout输出流。对应输出区域,通常指屏幕设备的输出,被认为是屏幕缓冲区。stdout也是行缓冲I/O。用户打印数据时,数据首先从用户程度到stdout所对应的输出缓冲区中。而只有缓存遇到了换行符\n、缓存满了、缓存被刷新了、stdout关闭等情况,数据才会从stdout输出缓冲区到终端显示
0.3. stderr错误输出流
stderr是标准错误流,是无缓冲的,会立即输出到文件或输出设备上。
1. 以键盘键入的输入输出函数
1.1. 输入函数
(1)scanf()函数
语法:int scanf(const char *format, ...);
-
成功,返回成功匹配和赋值的个数。如果到达文件末尾或发生错误,则返回EOF
**目的:**从标准输入流stdin中读取输入,并按照提供的format来浏览输入
**操作:**打印引号内字符串 ,将格式说明符替换成对应变量
(2)gets()函数
语法:char *gets(char *s);
作用:
存在问题:
`gets()`没有绑定检查,字符数组在声明时,已经设定长度为nums,但,`gets()`函数会一直获得字符,存入字符数组,一直到enter结束,而不是nums次,会照成缓冲区溢出错误
解决方法:
(3)getchar()函数
语法:int getchar(void);
**作用:**从屏幕上读取下一个可用字符,并将其返回为一个整数
**注意:**单次只会读取一个单一的字符
1.2. 输出函数
输出操作一般没有针对空格、制表符的特殊行为,只有换行符\n需要特殊对待。
(1)printf()函数
语法:int scanf(const char *format, ...);
**目的:**把输出写入到标准输出流stdout中,根据提供的format产生输出
**操作:**获取变量名所在的地址,将从标准输入获得的字符串存储在对应该地址中
补充:printf,意思是print formatted,也就是格式化打印。但如目的中所说,printf()的功能其实是把字符串写入到stdout文件缓存,而只有缓存遇到了换行符\n、缓存满了、缓存被刷新了、stdout关闭等情况,才会触发真正的打印输出。
-
缓存遇到了换行符\n
-
缓存满了
缓存满了会自动清空,所以本质上也是缓存被刷新
-
缓存被刷新了
-
程序结束时,会自动清空缓冲区
-
使用fflush()函数,一般这个函数是用来刷新输出(stdout)缓存的
-
stdout被关闭
所以,平常使用的printf()函数,之所以不加\n数据也会被打印的原因是,程序结束时缓冲区刷新,从而输出缓冲区中的数据会发送到显示设备上被打印。
(2)puts()函数——自动增加换行符
语法:int puts(const char *s)
作用:把字符串s和一个尾随换行符写入到stdout,并返回打印的字符数
注意:
-
puts()函数总会在最后追加一个换行符\n
-
puts()函数会将一个字符串写入到stdout中,一直到遇到空字符才结束,但不会将空字符写入。
-
如果成功,会返回打印的字符数,所以等于打印的字符串长度加一,那个加一就是最后追加的换行符\n
(3)putchar()函数
语法:int putchar(int a);
**作用:**把字符输出到屏幕上,并返回相同的字符
注意:单词只会输出一个单一字符
补充函数:fflush()函数
语法:int fflush(FILE *stream)
-
成功,返回零值
-
失败,返回EOF,且设置错误标识符feof
**作用:**强制刷新缓冲区,将缓冲区中的数据立即写到stream指向的文件(或设备)。
2. 文件相关的输入输出函数
2.0. 文件操作前言
两种文件类型:
-
文本文件.txt:纯文本格式存储,最小维护工作,易于阅读,最小安全性,占用更大存储空间
-
二进制文件.bin:容纳更多数据,不易读取,更高安全性
文件操作:
-
声明文件
File *fp;
-
打开/创建——fopen()函数
作用:创建一个新的文件或者打开一个已有的文件
语法:FILE *fopen(const char *filename, const char *mode);
fopen_s
mode:
-
r:只读,打开一个存在的文本文件,如果文件不存在,fopen()函数返回NULL
-
w:只写文件,如果文件存在,则将文件截断为0 ,从头写,如果文件不存在则创建一个新文件
-
a:追加写文件,如果文件不存在则创建一个新文件
-
r+:读写文件,先读后写,从起始位置上开始写入文件,如果文件不存在,fopen()函数返回NULL
-
w+:读写文件,先写后读,如果文件存在,则将文件截断为0 ,从头写。如果文件不存在则创建一个新文件
-
a+:读写文件。从头开始读,追加的模式写入。如果文件不存在则创建一个新文件
-
二进制文件:rb, wb, ab, rb+, wb+, ab+
注意:
-
w模式新建文件,只有路径正确且存在,而文件不存在,才会新建文件夹,也就是说
-
路径存在,文件存在:文件截断为零,重新写入
-
路径存在,文件不存在:创建一个新文件
-
路径不存在,不会新建文件,而是返回NULL
-
r+模式,是读取文件后,从文件指针处开始写入文件
w,w+模式,是直接将文件截断为零,重新写入文件
a,a+模式,则只会从文件末尾开始追加,无论文件指针在什么位置
也就是说,如果想在文件中插入内容,只有r+模式能够实现,需要使用fseek()函数将文件指针偏移到需要插入的位置
-
rb+和r+b是等价的
-
关闭文件
作用:清空缓存区数据,关闭文件,并释放该文件的所有内存
语法:int fclose(FILE *fp);
-
成功关闭文件,返回零
-
关闭文件发生错误,返回EOF
-
读取
-
写入
2.1. 输入函数
(1)fscanf()函数
**作用:**从文件中读取字符串,遇到第一个空格或者换行符时停止读取
语法:int fscanf(FILE *fp, const char * format, 变量地址)
同scanf()函数相比,参数中多了一个fp文件指针,但其余都一样
(2)fgets()函数——推荐使用的输入函数
作用:从fp指向的输入流中读取n-1个字符。把读入的字符串复制到缓冲区buf,并在最后追加一个**NULL**字符来终止字符串。
语法:char *fgets(char *buf, int n, FILE *fp);
如果在读取最后一个字符(第n-1个字符)前,就已经遇到\n或者是文件末尾EOF,则只会返回读取到的字符,包括换行符
结束的三个条件:
-
读取n-1个字符,返回n-1个字符和一个NULL字符
-
读取到换行符\n,返回所有读取的字符,包括换行符
-
读取到文章末位EOF,返回所有读取的字符
(3)fgetc()函数
**作用:**从fp指向的输入文件中读取一个字符,
语法:int fgetc(FILE *fp);
(4)fread()函数
**作用:**从给定流stream读取数据到ptr所指向的数组中
语法:
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *stream);
-
ptr:指向一块大小为size_of_elements*number_of_elements的内存空间,将要读入的数据存放在这块空间中
-
size_of_elements:要读取的每个元素的大小,以字节为单位
-
number_of_elements:元素的个数,每个元素的大小为size_of_element字节
-
stream:指向FILE对象的指针,指定了一个输入流
2.2. 输出函数
(1)fprintf()函数
**作用:**把字符串写入到文件中
语法:int fprintf(FILE *fp, const char * format, ...)
或者,int fprintf(FILE *fp, string str)
(2)fputs()函数
**作用:**把字符串s写入到fp所指向的输入流中
语法:int fputs(const char *s, FILE *fp);
这个输入流,可以是文件流,也可以是stdout、stderr等。
(3)fputc()函数
**作用:**把参数c写入到fp指向的输入流中
语法:int fputc(int c, FILE *fp);
(4)fwrite()函数
**作用:**将ptr所指向的数组中的数据写入到给定流stream中
语法:
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *stream);
-
ptr:指向要被写入的元素数组的指针
-
size_of_elements:要被写入的每个元素的大小,单位为字节
-
number_of_elements:要被写入的元素的个数,每个元素的大小为size_of_elements字节
-
stream:指向FILE对象的指针,指定了一个输出流
二,C++的输入输出
1.<iostream>标准库
定义了cin、cout、cerr、clog对象
1.1. 标准输入流cin
**描述:**是isotream的一个实例,附属到标准输入设备,通常是键盘。全称为std::cin。
基础语法:cin >> 变量名 >>[变量2 [>> ...]];
对cin和cout效率优化代码:
std::ios::sync_with_stdio(false);
std::cin.tie(0);
另一种使用方法:接收一个字符串,遇到空格、Tab、回车都结束
#include<iostream>
using namespace std;
int main(){
char a[20];
cin >> a;
cout << a << '\n';
}
1.1.1cin.get()函数
-
cin.get(字符变量名)用来接收字符
#include<iostream>
using namespace std;
int main(){
char ch;
cin.get(ch)//只能获取一个字符
//ch = cin.get(); //或者这个
cout<<ch<<endl;
}
-
cin.get(字符数组名, 接收字符数)用来接收一行字符串,包括空格
#include<iostream>
using namespace std;
int main(){
char a[20];
cin.get(a,20); // 类似于getline。可以输入多个单词,中间空格隔开
cout << a << endl;
}
-
cin.get()用于舍弃输入流中的不需要的字符,或者舍弃回车,用来弥补cin.get(字符组名, 接收字符数)的不足
#include<iostream>
using namespace std;
int main(){
char a[20];
cin.get(a,20);
cin.get();
cout << a << endl;
cin.get(a,10);
cout << a << endl;
system("pause");
return 0;
}
1.1.2cin.getline()函数
语法:cin.getline(接收字符数组, 接收个数, 结束字符)
作用:接收一个字符串,包括空格
#include<iostream>
using namespace std;
int main(){
char m[20];
cin.getline(m, 5);
cout << m << endl;
}
最后一位为\0,所以只能看到4个字符输出
2.2. 标准输出流cout
**描述:**是iostream类的一个实例,是行缓冲I/O,连接到标准输出设备,通常是显示屏。全称为std::cout。
语法:cout << 变量1 [<< 变量2 [<< endl]];
-
<<:流插入运算符
-
endl:end line,输出时插入换行符并刷新流
通常认为使用cout对象进行输出要比printf进行输出慢的多,但事实却不一定如此,参考博客C++的cin/cout为什么比C语言的scanf/printf慢,在经过上述2.1.的优化后,将stdin和cin解绑后,其实二者速度已经差不多。
其次,根据网上一些网友的实验,endl也是拖累cout速度的一大元凶,因为endl会在添加换行符的同时刷新输出缓冲区,不断地刷新是cout效率低下的一个重要原因。(未验证)
2.3. 标准错误流cerr
描述:也叫非缓冲标准错误流,是iostream类的一个实例,附属到标准输出设备,通常是显示屏。顾名思义,cerr对象是非缓冲的,也就是说,每个流插入到cerr都会立刻发送到标准输出设备输出。
语法:cerr << 变量1 [<< 变量2 [<< endl]];
2.4. 标准日志流clog
描述:也叫缓冲标准错误流,是iostream类的一个实例,附属到标准输出设备,通常是显示屏。
语法:clog << 变量1 [<< 变量2 [<< endl]];
2.<string>标准库
1.1getline()函数
作用:接受一个字符串,可以接受空格并输出
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
getline(cin, str);
cout << str << endl;
}
类似于cin.getline()
1.2gets()
继承C的gets()
1.3getchar()
继承C的getchar()
3.<fstream>标准库
文件操作:
三个数据类型:
数据类型
|
描述
|
ofstream
|
该数据类型表示输出文件流,用于创建文件并向文件写入信息。
|
ifstream
|
该数据类型表示输入文件流,用于从文件读取信息。
|
fstream
|
该数据类型通常表示文件流,且同时具有ofstream和ifstream两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。
|
-
打开文件——open()
语法:void open(const char *filename, ios::openmode mode);
-
filename:指定要打开的文件的位置和名称
-
mode:定义文件被打开的模式
mode:
-
ios::app:追加模式
-
ios::ate:文件打开后定位到文件末尾
-
ios::in:打开文件用于读取
-
ios::out:打开文件用于写入
-
ios::trunc:如果该文件已经存在,则将文件截断为0
-
关闭文件
语法:void close();
作用:关闭打开的文件流
在C++程序结束时,会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件
-
写入文件——输出操作
同cout一样,使用流插入运算符<<向文件写入信息,只不过这里使用的对象是ofstream对象和fstream对象
-
读取文件——输入操作
同cin一样,使用流提取运算符>>从文件读取信息,只不过这里使用的对象是ifstream对象和fstream对象
-
文件位置指针
seekg:seek get,istream的成员函数
seekp:seek put,ostream的成员函数
作用:重新定位文件位置指针
语法:(以"get"为例)
seekg(long int n, voctor)
-
n:表示偏移字节量
-
voctor:查找方向
-
ios::beg:流的开头
-
ios::cur:文件指针的当前位置
-
ios::end:流的末尾
比如:
fileObject.seekg( n, ios::cur );
把文件指针从指针所在位置向后偏移n个字节
4.<iomanip>库
控制符
|
作用
|
setbase(n)
|
以n进制方式输出(n=8,10,16)
|
setfill(ch)
|
设置字符填充,ch可以是字符常量或字符变量
|
setprecision(n)
|
设置输出有效位数为n位
|
setw(n)
|
设置字符宽度为n位,只对后一个有影响
|
setiosflags(ios::uppercase)
|
以大写字母显示
|
setiosflags(ios::fixed)
|
实现对小数点后的数字的控制
|
setiosflags(ios::scientific)
|
以科学计数法显示
|
setiosflags(ios::showpoint)
|
强制显示小数点
|
setiosflags(ios::showpos)
|
强制显示正号
|
setiosflags(ios::left)
|
设置输出左对齐
|
setiosflags(ios::right)
|
设置输出右对齐
|
resetiosflags(…)
|
终止括号中的输出格式
|
补充,这篇文章是广泛阅读了网上关于输入输出流、C语言输入输出、C++输入输出函数各种详解后自己写的笔记,忘了记录学习的网页网址了…只能说十分抱歉,以后会注意的
三 附录
常用的格式说明符号
转换说明
|
输出
|
%d
|
有符号 十进制 整数 int
|
%f
|
十进制 浮点数 float
|
%lf
|
十进制 浮点数 double
|
%c
|
字符 char
|
%s
|
字符串 char*
|
-
%d:int
-
%hd:short int
-
%li:long int
-
%lli:long long int
-
%u:unsigned int
-
%lu:unsigned long int
-
%llu:unsigned long long int
-
%f:float,十进制记数法
-
%lf:double
-
%Lf:long double
-
%c:char
-
%s:string
-
%o:unsigned int 八进制
-
%[x|X]:unsigned int 十六进制整数 0[f|F]
-
%[a|A]:浮点数、十六进制、[p|P]-记数法
-
%[e|E]:浮点数、[e|E]-记数法
-
%[g|G]:根据数字自动选择%f或%[e|E]
如果获取字符时使用的格式说明符为%c,而打印字符时使用的格式说明符为%d,则会打印获取字符的ASCII码
printf()的常用修饰符
位置:在%与字母之间的位置,比如%-f
概念词汇
EOF:End Of File缩写,文件结束的标志,通常值为-1
在fgetc()和fputc()函数中,如果操作失败则返回EOF,则,这个时候的EOF代表Error Of File
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_31724803/article/details/129883449