C++青少年简明教程:C++的输入输出
C++没有提供专门的输入输出语句,输入输出不是由 C++ 本身定义的,而是在编译系统提供的 I/O 库中定义的。 在 C 语言中,输入和输出的通过函数来实现的,在 C++ 中是通过调用输入输出流库中的流对象实现的。
C++标准的头文件一般都没有.h后缀(扩展名),而在C语言的标准库中,通常使用的是.h后缀。这只是一种约定俗成的做法,并没有强制要求。
前面“C++程序结构”一节介绍过<iostream>头文件,它是input(输入) output(输出) stream(流)的缩写,翻译过来就是:输入输出流。提供了 cin对象(一般情况下代表键盘) 和 cout对象(一般情况下代表显示器),分别用于从标准输入读取流 和 向标准输出写入流。关于cin用来在程序执行期间给变量输入数据,cout实现将数据输出到显示器的操作,不再多说,详见前面的“C++程序结构”部分,现在介绍其他有关内容。
<cstdio>头文件的getchar、putchar及scanf、printf函数
【<cstdio>头文件和<stdio.h>头文件
<cstdio>是C++标准库提供的头文件,<stdio.h>是C语言标准库提供的头文件。它们都包含了一系列的输入输出函数,比如getchar、putchar、scanf、printf函数f等函数。它们的作用大致相同,只是在命名空间、可移植性等方面存在一些细微的差别。在C++中,推荐使用<cstdio>,在C程序中通常使用<stdio.h>。】
getchar 和 putchar函数是两个常用的字符输入输出函数。
getchar() 函数用于从标准输入流(通常是键盘)读取单个字符。它不需要任何参数,并且会等待用户输入字符后才能继续执行程序,并返回该字符的ASCII码值。示例用法如下:
#include <cstdio>
int main() {
char c = getchar(); // 从标准输入读取一个字符
putchar(c); // 将字符输出到标准输出
return 0;
}
putchar() 函数用于将一个字符输出到标准输出流(通常是控制台),该函数接受一个整型参数,即要输出的字符的ASCII码值。返回值:输出成功时返回输出的字符,出错时返回EOF(End of File)。示例用法如下:
#include <cstdio>
int main() {
char c = 'A';
putchar(c); // 将字符 'A' 输出到屏幕
return 0;
}
顺便提示:
getchar() 和 putchar() 最初设计用于处理 ASCII 字符,但它们也具备处理中文字符的功能。中文字符通常使用多字节编码(如UTF-8),怎么理解?
getchar() 和 putchar() 函数可以处理中文字符,是因为它们是通过底层的操作系统或编译器提供的字符输入输出功能来实现的。底层的字符输入输出功能可能会根据不同的操作系统或编译器而有所差异,对于一些特殊的字符或编码方式,可能会出现问题。所以在处理中文字符时,最好使用支持中文字符的更高级的输入输出函数,如使用 <iostream> 头文件中的 std::cin 和 std::cout。
scanf和printf是C语言中常用的输入输出函数,也可以在C++中使用。scanf用于从标准输入读取数据,而printf用于向标准输出写入数据。如果要在C++中使用需要注意一些细节。一般情况下,scanf和printf可以和cin和cout等价地使用。例如,读入一个整数可以使用scanf,输出一个整数可以使用printf:
#include <cstdio>
int main() {
int num;
printf("请输入一个整数: ");
scanf("%d", &num); // 读入一个整数
printf("您输入的整数是: %d\n", num); // 输出一个整数到标准输出
return 0;
}
需要注意的是,scanf和printf需要使用格式化字符串来指定输入输出的数据类型,因此需要多写一些代码。同时,scanf的输入参数需要使用"取地址符"&,而printf的输出参数不需要。
scanf和printf格式化输入输出介绍
scanf函数是用于格式化输入的函数,它可以从控制台或文件中按照指定的格式读取数据。
基本语法为:
scanf("格式控制字符串", 地址表达式1, 地址表达式2, ...);
其中,格式控制字符串用来指定要输入的数据类型和格式。地址表达式用来表示变量在内存中的地址,这样 scanf 函数才能将输入的数据存放到对应的变量中。格式控制字符串,包含了输入的格式。可以使用与printf相同的转换字符和格式化说明符来指定输入的类型。
【scanf的返回值:scanf函数返回成功读取的输入项的数量。若返回值小于要求输入的参数数目,则说明读取失败。例如,若输入的格式控制字符串为"%d %d",则只有两个整数均成功读取并赋值给对应变量,才会返回2。】
scanf函数用于从标准输入流中读取格式化输入。下面是一些常用的格式符及其用法:
%d:读取一个有符号十进制整数。
示例:int num; scanf("%d", &num);
%f:读取一个浮点数。
示例:float num; scanf("%f", &num);
%c:读取一个字符。
示例:char ch; scanf("%c", &ch);
%s:读取一个字符串。
示例:char str[100]; scanf("%s", str);
%lf:读取一个双精度浮点数。
示例:double num; scanf("%lf", &num);
%u:读取一个无符号十进制整数。
示例:unsigned int num; scanf("%u", &num);
%x:读取一个十六进制整数。
示例:int num; scanf("%x", &num);
%o:读取一个八进制整数。
示例:int num; scanf("%o", &num);
%p:读取一个指针。
示例:int* ptr; scanf("%p", &ptr);
%*d:跳过一个有符号十进制整数的读取,但不赋值给变量。
示例:scanf("%*d");
scanf函数的域宽(field width)参数必须是一个非负整数。这一个后面介绍。
下面是一个常用的格式符例子:
#include <cstdio>
int main() {
int a, b, c;
scanf("%d-%d-%d", &a, &b, &c);
printf("%d%d%d", a, b, c);
return 0;
}
取地址符"&"的作用是取变量的地址。地址标识内存的位置,相当于容器(如“盒子”)号码。
假设有一个变量a,相当于名为a的容器,&a表示找到了这个容器的号码,就可以使用这个容器了。
下面是scanf函数的域宽(field width)的示例:
#include <cstdio> //或用#include <stdio.h>
int main() {
int num; // 定义整数变量num
char s[6]; // 定义字符数组s,可以存储5个字符和一个空字符
printf("请输入一个整数:\n"); // 提示用户输入整数
scanf("%4d", &num); // 读取用户输入的4位整数,存储在变量num中
int c; // 定义整数变量c,用于接收getchar()读取的字符
while ((c = getchar()) != '\n' && c != EOF); // 清空输入缓冲区,防止对后续字符串输入产生不良影响
printf("请输入一个字符串:\n"); // 提示用户输入字符串
scanf("%6s", s); // 读取用户输入的不超过6个字符的字符串,存储在字符数组s中
printf("整数: %d\n", num); // 打印用户输入的整数
printf("字符串: %s\n", s); // 打印用户输入的字符串
return 0; // 程序结束,返回0表示正常退出
}
示例中使用scanf函数来读取用户输入,%4d 用于只获取不超过4位的整数,%6s 用于只获取不超过6个字符的字符串,避免了用户输入过长的情况。同时,在读取完整数后通过while循环和getchar函数清空了输入缓冲区,避免了后续字符串读取出现异常。最后,将读取到的整数和字符串分别打印出来。
请注意,域宽参数是可选的,如果省略,则scanf函数将读取尽可能多的字符,直到遇到空格、制表符或换行符为止。
printf函数是用于格式化输出的函数,它可以将数据格式化输出到控制台或文件中。基本语法为:
printf("格式控制字符串", 值1, 值2, ...);
其中,值1、值2 等表示要输出的变量或常量,可以有多个。
"格式控制字符串"由两种类型的字符组成:普通字符和格式化指令。
【printf的返回值:printf函数返回成功打印(输出)的字符数量。如果发生错误,则返回负值。例如,如果使用printf输出了6个字符,则返回值为6。】
普通字符是指在格式控制字符串中直接显示的字符,不会影响输出的格式。
格式化指令由百分号(%)后面的字符组成,用于指定输出值的类型和格式。常用的格式化指令包括:
%d:以十进制整数的形式输出。
%f:以浮点数的形式输出,默认输出6位小数。
%c:以字符的形式输出。
%s:以字符串的形式输出。
%p:以指针的形式输出。
%x:以十六进制数的形式输出。
在printf函数中,你可以使用精度和字段宽度等选项控制输出的位数和格式。
字段宽度(Field Width):可以使用数字来指定输出字段的最小宽度。如果输出的数据长度小于字段宽度,则会使用填充字符(默认为空格)在左侧或右侧进行填充。示例:
int num = 42;
printf("%5d\n", num); // 输出 " 42",字段宽度为5,右对齐
printf("%-5d\n", num); // 输出 "42 ",字段宽度为5,左对齐
精度(Precision):对于浮点数,可以使用.n的格式来指定小数点后的位数。对于字符串,可以使用.n来指定输出字符的最大数量。如果数据的长度超过了精度值,那么会截断超出部分,若不足默认补零。示例:
double pi = 3.1415926535;
printf("%.2f\n", pi); // 输出 "3.14",".2" 表示精度限制两位小数。"f" 则表示浮点数类型。
左对齐(Left Alignment)和零填充(Zero Padding):
可以使用-标志来指定输出左对齐。默认情况下,输出是右对齐的。
可以使用0标志来指定使用零进行填充字段宽度。默认情况下,使用空格进行填充。
左对齐和零填充示例:
int num = 42;
printf("%-5d\n", num); // 输出 "42 ",字段宽度为5,左对齐
printf("%05d\n", num); // 输出 "00042",字段宽度为5,零填充
十六进制前缀(Hexadecimal Prefix):对于以十六进制表示的整数,可以使用#标志来添加前缀0x或0X。示例:
int num = 42;
printf("%#x\n", num); // 输出 "0x2a",以十六进制表示并添加前缀
符号显示(Sign Display):可以使用+标志来显示正数的符号(+),而默认情况下只显示负数的符号(-)。符号显示示例:
int num1 = 42;
int num2 = -42;
printf("%+d\n", num1); // 输出 "+42",显示正数的符号
printf("%+d\n", num2); // 输出 "-42",显示负数的符号
下面是一个具体例子:
// 要引入cstdio头文件,这个头文件和iostream一样,定义了C语言的输入和输出
#include <cstdio>
using namespace std;
int main() {
double pi = 3.14159265;
// printf提供一个格式化字符串,数据会按格式要求输出
printf("%.3f", pi); //输出:3.142
return 0;
}
修改此程序,不用 printf()输出,改用cout输出:
需要用到<iomanip>头文件中的fixed输出修饰符和setprecision函数。
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double pi = 3.14159265;
// 使用 cout 输出浮点数并保留 3 位小数
cout << fixed << setprecision(3) << pi; //输出:3.142
return 0;
}
fixed 是一个输出修饰符,它指示 cout 输出浮点数时使用固定小数点表示法,而不是默认的科学计数法。scientific设置浮点数输出为科学计数法形式。
setprecision(3) 是一个 I/O 操作符,用于设置输出流的精度。在这里,我们将精度设置为3,这意味着小数点后只保留3位有效数字。
所以,通过以上代码,将输出结果限制为小数点后三位。对于变量 pi 的值 3.14159265,经过设置输出格式和精度后,最终输出的结果为 3.142。
此程序用到的<iomanip>头文件后面介绍。
下面再给一个使用scanf和printf函数的完整示例:
#include <cstdio>
int main() {
int num;
printf("请输入一个整数: ");
scanf("%d", &num);
printf("您输入的整数是: %d\n", num);
double floatingNum;
printf("请输入一个浮点数: ");
scanf("%lf", &floatingNum);
printf("您输入的浮点数是: %.2f\n", floatingNum);
return 0;
}
在这个示例中,首先使用 printf 输出提示信息,然后使用 scanf 从用户输入中读取数据。读取整数时,使用 %d 格式符,并通过 & 操作符将变量的地址传递给 scanf;读取浮点数时,使用 %lf 格式符,同样需要使用 & 操作符来传递变量地址。使用 printf 将读取到的数据格式化输出到屏幕上。注意,在输出浮点数时,我们使用了 %.2f 的格式控制,限制只显示两位小数。
C++的<iomanip>头文件
注意,std 命名空间中的常用操纵符和<iomanip> 头文件中的常用操纵符分别属于两者。这些操纵符(Manipulators)对于控制流的输入和输出非常有用。
std命名空间中常用于流的操纵符有:
endl 插入一个换行符
ends 插入一个空字符
dec 让流以十进制方式解释输入或显示输出
hex 让流以十六进制方式解释输入或显示输出
oct 让流以八进制方式解释输入或显示输出
fixed 让流以定点表示法显示数据
scientific 让流以科学表示法显示数据
下面介绍<iomanip>头文件的操纵符:
<iomanip>是C++标准库中的头文件,用于控制输入输出流的格式化。<iomanip>头文件常用于控制标准输出流的格式,例如设置输出浮点数时的位数、调整对齐方式、设置填充字符等等。【Standard library header <iomanip> - cppreference.com 或 https://cplusplus.com/reference/iomanip/ 】它提供了一些函数和操作符,用于设置输出流的格式,常见的使用场景包括控制输出的小数位数、设置输出的字段宽度等。
例如:
setw(int n):设置字段宽度为 n 字符,用于调整输出的对齐方式。示例:
cout << setw(5) << 42 << endl; //输出 42,以域宽5输出整数42,前面填充有3个空格。
setprecision(int n):设置浮点数的精度为 n 位小数。通常和fixed组合来设置输出浮点数的精度。如果用Setprecision指定的小数点后的位数大于实际数字的位数,默认使用零进行填充;如果小数点后的位数小于实际数字的位数,将按照四舍五入的规则进行四舍五入。示例:
cout << setprecision(3) << 3.14159 << endl; //输出 3.14
cout << fixed << setprecision(3) << 3.14159 << endl; //输出 3.142
setfill(char c):将字段填充字符设置为 c。通常与 setw()一起使用。示例:
cout << setw(5) << setfill('*') << 42 << endl; //输出 ***42,前面填充有*字符。
setiosflags(flag):设置指定的 I/O 操作标志,如科学计数法、固定小数点表示法等。
resetiosflags(flag):重置(恢复到默认)指定的 I/O 操作标志。也称为清除格式化标志。
showpos:在正数前显示加号(+)。noshowpos:不显示正数前的加号。示例:
cout << showpos << 12.34 << endl; //输出+12.34,显示正数前的加号。
cout << noshowpos << 12.34 << endl; //输出12.34,不显示正数前的加号。
scientific:使用科学计数法表示法输出浮点数。不是固定小数位数的打印格式。默认情况下,在科学计数法中,小数部分将以6位精度显示。你可以使用setprecision来控制小数部分的位数。示例:
cout << scientific << 0.00123 << endl; //将会以科学计数法输出1.230e-003。
left用于左对齐输出,默认情况下,数字和文本在域内左对齐。right用于右对齐输出,即数字和文本在域内右对齐。Left和right通常与 setw()一起使用。示例:
int num = 42;
cout << setfill('#') << setw(5) << left << num << endl; // 输出 42###,即后面填充有3个#。
cout << setfill('0') << setw(5) << right << num << endl; // 输出00042,即前面填充有3个0。
setbase(n) 函数只支持十进制、八进制和十六进制,不支持二进制,默认是十进制。【setbase 设置基数与使用dec、hex 或oct等效。】示例:
int number = 42;
cout << "Decimal: " << number << endl; //输出:Decimal: 42
cout << "Octal : " << setbase(8) << number << endl; //输出:Octal : 52
cout << "Hex : " << setbase(16) << number << endl; //输出: Hex : 2a
要使用<iomanip>头文件,需要在代码中包含语句:#include <iomanip>。
例1、源码如下:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double num = 3.1415926;
cout << setprecision(3) << num << endl;
cout << setw(10) << setfill('*') << num << endl;
return 0;
}
输出结果为:
3.14
******3.14
在这个示例中,setprecision(3)设置输出的小数位数为3,setw(10)设置输出的字段宽度为10,setfill('*')设置输出的填充字符为*。
例2、源码如下:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int number = 42;
cout << "Default: " << endl;
cout << number << endl;
cout << "Left-aligned with setw: " << endl;
cout << setw(10) << left << number << endl;
cout << "Right-aligned with setw: " << endl;
cout << setw(10) << right << number << endl;
return 0;
}
输出结果为:
Default:
42
Left-aligned with setw:
42
Right-aligned with setw:
42
例3、下面是一个比较完整的例子:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << setw(5) << 42 << endl; // 输出 42,以域宽5输出整数42,前面填充有3个空格。
cout << setw(5) << setfill('*') << 42 << endl; // 输出 ***42,前面填充有*字符。
cout << showpos << 12.34 << endl; // 输出+12.34,显示正数前的加号。
cout << noshowpos << 12.34 << endl; // 输出12.34,不显示正数前的加号。
cout << setprecision(3) << 3.14159 << endl; // 输出 3.14,设置精度为3并输出浮点数。
cout << fixed << setprecision(3) << 3.14159 << endl; // 输出 3.142,设置固定精度为3并输出浮点数。
cout << scientific << 0.00123 << endl; // 输出1.230e-003,使用科学计数法输出浮点数。
int num = 42;
cout << setfill('#') << setw(5) << left << num << endl; // 输出 42###,即后面填充有3个#。
cout << setfill('0') << setw(5) << right << num << endl; // 输出00042,即前面填充有3个0。
return 0;
}
运行效果:
C和C++在输入输出方面的关系
C++是在 C 语言的基础上发展起来的,它继承了 C 语言的许多特性,如数据类型、运算符和控制结构等。然而,C++也加入了许多新的特性,如面向对象编程、继承、多态和异常处理等,使得 C++比 C 语言更加强大和灵活。
数据的输入输出是非常重要的,它允许程序与用户或者其它程序进行交互和通信。数据的输入输出通常是通过键盘,屏幕,磁盘文件或者其它设备来进行的。
在输入输出方面,C和C++都使用stdio.h头文件中定义的标准输入/输出函数来进行输入输出操作,例如printf、scanf、fscanf、sprintf、sscanf等。这些函数的使用方法在C和C++中基本相同。
但是,C++还引入了一种流式输入输出机制,即iostream,它是C++库中的一部分,定义了几个类来进行输入输出操作,例如iostream、istream、ostream、ifstream、ofstream等。这种机制可以通过运算符重载来实现更方便、更可读性更高的输入输出操作。
另外需要注意的一点是,在C中,字符串常量是通过字符数组来表示的,而在C++中,字符串常量是通过一个叫做std::string的类来表示的,它可以方便地进行各种操作。例如,在C++中,我们可以使用std::cout输出字符串常量,而在C中则需要使用printf或puts函数来输出。
总的来说,C++在输入输出方面相对于C提供了更为方便和灵活的方法,但C++也可以使用C的标准输入输出函数进行输入输出操作。
下面给出一个演示例子:
输入一个双精度浮点数,保留8位小数,输出这个浮点数。
输入一行,一个双精度浮点数。样例输入
3.1415926535798932
输出一行,保留8位小数的浮点数。样例输出
3.14159265
下面是C风格的源码:
#include <cstdio> //或用#include <stdio.h>
int main() {
double num;
scanf("%lf", &num); //读取一个double类型的浮点数
printf("%.8f\n", num); // 设置输出小数点后8位
return 0;
}
下面是C++风格的源码:
#include<iostream>
#include<iomanip>
using namespace std;
main(){
double num;
cin >> num;
cout << fixed << setprecision(8) << num << endl;
return 0;
}
其中,fixed 和 setprecisionI/O 是操纵符(manipulators),用于控制浮点数的输出格式。
【顺便提示:在竞赛编程中,为了节省时间和方便,常常使用 #include <bits/stdc++.h>,这个头文件并不是C++标准的一部分,但它在许多编译器(特别是GCC和Clang)中都被支持,并且被广泛用作一种快速编写代码的方式,因为你不需要显式地包含每一个你需要的标准库头文件。
<bits/stdc++.h> 是一个非标准的包含所有标准 C++ 库的头文件。它主要用于方便地包含常用的 C++ 标准库头文件,可以减少包含多个头文件的麻烦。这个头文件在一些编译器和环境中是支持的,但并不是标准规定的头文件。
该头文件包含了很多 C++ 标准库的头文件,包括 <iostream>、<vector>、<algorithm> 等等。因此,如果你包含了这个头文件,就不需要单独包含其他标准库头文件,可以直接使用其中的类和函数。
虽然<bits/stdc++.h>在某些情况下可能很方便,但在生产代码或项目中通常不推荐使用它。相反,你应该显式地包含你需要的标准库头文件,以确保代码的可读性、可移植性和编译效率。】