C/C++语言本身并不带输入和输出(即I/O)功能,而是提供了输入输出库,也称为I/O库。通过I/O库,我们可以完成输入和输出的操作。大多数C程序使用一种称为stdio(标准I/O)的I/O库,该库也能够在C++中使用。但是,在C++程序中,一种称为iostream(I/O 流库)的I/O库用得更多。 在C++中,I/O使用了流的概念-字符(或字节)流。每一个I/O 设备传送和接收一系列的字节,称之为流。输入操作可以看成是字节从一个设备流入内存,而输出操作可以看成是字节从内存流出到一个设备。流是输入输出设备的另一个名字-一个文件、屏幕、键盘等。要使用C++标准的I/O流库的功能,必须包括两个头文件: #include<iostream.h> #include<iomanip.h> iostream.h文件提供基本的输入输出功能,iomanip.h 文件提供格式化的功能。通过包含iostream流库,内存中就创建了一些用于处理输入和输出操作的对象。标准的输出流(通常是屏幕)称为cout,标准的输入流(通常是键盘)称为cin。 输出变量d的值到标准输出设备的语法形式如下: cout << d; 注意:(<<)是双小于号,不是左移操作符,它是一种输出操作符,指出程序哪个流发送数据。 本语句表示传送d的值到标准的输出设备(由cout表示)。理解这个语句的一种方法是调用了函数operator<<,d是函数参数(关于函数调用,在第五章学习)。明确地说,为了输出d的值到cout,可以使用语句: cout.operator<<(d); 由于"cout.operator<<(d);"写起来繁琐,我们更喜欢把它写成"cout << d;"。
对于C语言的程序中,使用的是stdio(标准I/O)库,在这个库中不仅定义了面向控制台(显示器和键盘)的输入输出,还分别定义了文件输入输出函数和面向内存的输入输出函数。在C++程序中,我们最常使用的是iostream(I/O 流库),它是基于面向对象的,可以实现stdio库的所有功能,通过它统一了标准I/O、文件和存储块的函数接口,使得对所有设备的操作看上去都一样,隐藏了内部实现。与标准C输入输出库的各种各样的函数相比,输入输出流更容易、更安全、更有效。为了保证兼容性,I/O流类和C标准输入输出函数库是可以共同使用的。 使用stdio库,需要在程序中包含stdio.h头文件,若使用iostream库,需要包含iostream.h头文件,如果要带参数的格式化输入输出,还需要包含iomanip.h头文件。 使用stdio库的标准输入输出,要使用scanf和printf函数,scanf函数是从标准输入(键盘)设备读入,printf是向标准输出设备(显示器)输出。 iostream库在iostream.h中预定义了四个全局的流对象:cout、cerr、clog和cin,用于标准输出和输入,cout和cin在程序设计中会经常用到。cout流对象控制向控制台(显示器)的标准输出,cin控制从控制台(键盘)输入。
2.7.1 标准输出 输出内置的数据类型到标准的输出设备,用<<运算符和cout输出流。例如: cout << d; // 输出d cout << d << endl; // 输出d并换行 cout << "This is the value of d : " << d << endl; // 输出字符串、d并换行 一个语句中多次使用<<等价于<<单独使用多次,即最后一个语句等价于: cout << "This is the value of d : " ; cout << d; cout << endl; 符号endl的功能是换行,并清除输出缓冲区。变量的值以缺省的格式打印,改变打印格式方法在后面介绍。
C语言的转义字符在C++中仍然有效,所以在iostream中,我们可以使用转义字符,比如要达到回车的效果,我们可以使用: cout<<endl; 也可以使用: cout<<'\n'; 如果实现简单的格式化输出,我们可以使用制表符: cout<<"name\tage\tsex"<<endl;
2.7.2 标准输入 标准输入的用法与标准输出类似,使用>>运算符和cin输入流。语句: cin >> d; 是从标准输入读(或抽取)一个值到变量d,并与语句中的数据类型匹配。例如:如果d是整型数,上面的命令读数字,直至没有遇到数字为止;如果d是浮点数,该命令读数字、小数点、指数,直至没有遇到合适的字符为止。 假如把输入和输出语句结合在一起使用,可能会发生问题。我们编写程序时,常常先用一个输出语句打印提示,然后要求用户输入数据。对于一些C++编译器,在输入语句抽取数据前,应先输出一个换行符。例如2-9: 否则,可能达不到目的。
经验:如何记<<和>>:cout是c出,出了就小(<<)了; cin是c进,进则收入,就大(>>) 注意:cin流不使用指针引用变量,不应给cin传递一个指向变量的指针,如果这样做cin将返回错误。例如,下面的程序cin_err.cpp ,当编译它时将返回六个错误:
 |
例2-8: |
|
#include <iostream.h> void main(void) { int age; float salary; char name[128]; cout << "Enter your first name age salary: "; cin >> &name >> &age >> &salary; cout << name << " " << age << " " << salary; } |
 |
例2-9: |
|
cout << " Enter the value of n : " << endl; cin >> n; 而不要写成: cout << " Enter the value of n : "; cin >> n; |
2.7.3 格式化 有两种方法设置变量的输出格式:一种方法是直接设置输出流的格式状态,另一种方法是通过输入输出操纵符。 如果选择前者,需要设置与输出流相关的标志,此后,任何数据输出到该流,将按照标志决定的格式输出;如果选择后者,可将格式化的命令嵌入到输入输出语句中。 前者也许更好,因为,我们常常为所有的输出选择一种格式,也就是说,常常不需要大量的、不同的格式。与输出流格式状态相关的标志有许多,我们仅讨论最常用的两种:精度(precision)和宽度(width)。精度是指小数点后的数字位数,宽度是指变量输出的总位数。设置精度和宽度的形式如下: cout.precision(4); cout.width(10); 用下面的语句,我们可以得到当前的精度和宽度: n = cout.precision(); m = cout.width(); 一旦设置了precision,在下一次设置以前,原设置值保持不变。width有所不同,它是数据输出的最小位数,如果宽度不够,则会分配更多的位数。也就是说,当width位数不够时,输出的数据不会被截断。而且输出操作完成后,width会恢复为缺省值。还有一些标志可以设置浮点数的固定或指数表示、输出值的对齐方法(右、左或中间)、是否显示尾部0,这些标志用成员函数setf设置。例如,假定要使用标准输出,指数表示、左对齐及显示尾部0,可以使用下面的语句: cout.setf(ios::left, ios::adjustfield); cout.setf(ios::showpoint, ios::showpoint); cout.setf(ios::scientific, ios::floatfield);
使用precision域可以控制输出的精度。对于整数,precision域用来控制输出结果的长度,如果整数值长度小于设置的精度,则输出结果的前面补0。对于浮点数,precision域用于控制小数点后面的位数。 例如: printf("%+10.5f",f); 输出浮点数f,带符号,宽度是10位(包括小数点),小数位是5位。 控制符L或l可以将整数设置为长整型输出,h可以将整数作为短整型输出。
2.7.4 printf和scanf输出输入 printf和scanf是标准的C输出输入语句,在C语言标准的头文件stdio.h中定义。但在C++中,它们也能够被使用。 一、 printf输出 printf语句的一般形式如下: printf( "格式字符串", 表达式, ... ); 该语句将"表达式"按照"格式字符串"给定的格式,显示在屏幕上。"格式字符串"包括文本字符、转义字符和格式说明符。 如果我们只要打印简单的信息,并不需要包括"表达式",例如,要打印信息:"今天是星期二",可以使用下面的printf语句: printf("Today is Thursday"); 这个语句执行的结果为:
Today is ThursdayPress any key to continue | | 需要注意的是:输出的信息与系统提示连在一起。为了解决这个问题,可以使用转义字符,常用的转义字符参见2.4.3节的内容。
C++使用操纵符(在<iomanip.h>和<iostream.h>中定义),而C提供了一系列的说明符,参见表2-10。这些说明符用于输出,也可用于输入。
 |
 |
表2-10: |
|
说明符 |
类型 |
%wd |
int 或char |
 |
w = 宽度 |
%w.df |
double w = 总的宽度(包括小数点) d = 小数位数 |
%wc |
char 或int w = 宽度 |
%ws |
char * (字符串) 格式 w = 宽度 |
%wu |
unsigned int w = 宽度 |
%wo |
八进制 |
%wx |
十六进制 |
%m.dddddde±xx %m.ddddddE±xx %m.ddddddg±xx %m.ddddddG±xx |
指数记数法 | |
 | 下面,我们给出一些格式实例,假定有下面的变量说明:
 |
 |
表2-11: |
|
变量说明 |
int x = 98; float y = 1.34567889; char letter = 'A'; char word[] = "Hello"; | |
 | 下表给出了输出这些变量的缺省的格式:
 |
 |
表2-12: |
|
语句 |
printf("Default formats: %d %f %c %s\n", x,y,letter,word); |
结果 |
Default formats: 98 1.345679 A Hello | |
 | 我们也可以改变缺省的格式。需要注意的是:输出结果是右对齐的,也就是说,当输出结果的宽度小于指定的宽度时,空格填充到左边:
 |
 |
表2-13: |
|
格式说明 |
语句 |
printf("Width specified: %5d %10.4f %5c %10s\n", x,y,letter,word); |
结果 |
Width specified: 98 1.3457 A Hello | |
 | 我们也可以打印变量的内存地址信息,但要使用unsigned格式说明符:
 |
 |
表2-14: |
|
打印内存地址 |
语句 |
printf("Address of x: %u Address of y: %u\n", &x, &y); |
结果 |
Address of x: 4026528400 Address of y: 4026528396 | |
表达式按照格式字符串指定的格式输出。当格式字符串中没有格式说明时,printf函数就相当于输出一个普通的字符串。 例如: printf("this is a string.");
格式说明符总是以一个百分号(%)引导,当printf函数遇到第一个格式说明符时,用第一个表达式的值来替换它,遇到第二个格式说明符时,就用下一个表达式的值替换,依此类推。如果表达式个数多余格式说明符个数,则多余的参数就被抛弃。格式说明符的格式是: %[flags][width][.precision][{h|l|L}]type 每个域是由一个字符或者一个数组成,方括号扩起的域是可选项,最基本的格式是:%type。
type域字符:
 |
 |
表2-19: |
|
转换字符 |
类型 |
含义 |
C |
int |
输出一个字符 |
C |
int |
同上 |
D |
int |
输出有符号十进制整数 |
I |
int |
同上 |
O |
int |
输出无符号八进制整数 |
U |
int |
无符号十进制整数 |
X |
int |
无符号十六进制整数 |
X |
int |
同上 |
e |
double |
以科学计数法输出浮点数 |
E |
double |
同上 |
F |
double |
输出十进制浮点数 |
G |
double |
等效于%e和%f,取两者之中较短的 |
G |
double |
同上 |
P |
void指针 |
输出指针地址,格式如下:xxxx:yyyy ,xxxx 是段地址,yyyy 是偏移量,它们都是十六进制数 |
S |
char* |
输出字符串 | |
 | 例如: printf("%d%x", n, n) 是将n分别按10进制和16进制整数输出。 我们可以用flag任选符来改变输出的格式,
 |
 |
表2-20: |
|
Flag |
含义 |
缺省 |
- |
左对齐 |
右对齐 |
+ |
如果结果是有符号数,则显示符号 |
只显示负号 |
0 |
在结果前面填充0 |
无填充 |
空格 (' ') |
如果结果是有符号数且为正,则在前面填充一个空格 |
不填充空格 | |
 | 例如: printf("%+d",n); 输出整数n时显示符号(包括正号)。 可以使用width域设置输出的宽度,如果输出的宽度小于设置的宽度,用空格填充,如果大于设置的宽度,则设置的宽度将被忽略,而不会将结果裁剪。 例如: printf("%+10d", n); 输出整数n时显示符号,且宽度为10位,如n不够10位,则用空格填充,否则按实际位数显示。
二、 scanf输入 scanf语句的一般格式如下: scanf("格式字符串", 地址,…); scanf语句用"格式字符串"控制键盘读入的方式。"格式字符串"中一般只包括格式说明符,它们与printf语句中的一样,而"地址"是指变量在内存中的位置。我们看看下面的程序实例,它定义了一个int、float、char和char []变量,并使用了格式说明符:
 |
程序2-4: |
|
#include <stdio.h> #define MAX_WORD 20 void main() { int x; float a; char ch, empty; char word[MAX_WORD];
printf("Enter an integer: "); scanf("%d", &x);
printf("Enter a float: "); scanf("%f", &a);
fflush(stdin); // 清空输入缓冲区 printf("Enter a character: "); scanf("%c", &ch);
printf("Enter a string: "); scanf("%s", word);
printf("Your integer was: %d\n", x); printf("Your float was: %f\n", a); printf("Your character was: %c\n", ch); printf("Your word was: %s\n", word); } |
这个程序有几个有趣的特征,总结如下: (1) 地址。整型、浮点型和字符型变量需要使用地址运算符&,而字符串不需要,因为数组名就是数组在内存中的起始地址,有关数组和字符串的内容,我们在第六章详细介绍。 (2) fflush() 函数。我们在读字符之前,调用fflush() 函数,这个函数清空标准的输入设备缓冲区(stdin)。如果要删除缓冲区中回车换行符,就必须清空缓冲区。因为它们也是字符,如果不在读入之前清除它们,就不能正确地读入字符。 (3) 字符串。我们输入字符串"hello there",但读到空格时,scanf()就停止了,仅"hello"存入了字符串。下面是说明这种现象的一个实例,运行该程序,并输入。参看例2-10: 如果需要读取带空格的字符串,可以使用函数gets来做这件事情。gets的作用是读取一行字符到一个字符串变量中。它会读取空格,直到遇到'\n'或'\0'时才返回。
 |
例2-10: |
|
Enter an integer: 10↙ Enter a float: 1.23456↙ Enter a character: c↙ Enter a string: hello there↙ 运行结果为: Your integer was: 10 Your float was: 1.234560 Your character was: c Your word was: hello | 格式说明符的形式是: %[*][width][{h | l | L}] type scanf的格式说明符与printf的类似,最简单的形式如下: %type type域标识要读取的数据类型,它与printf函数的字符是一样的。Width是读取的最大字符数,例如,数据为"1.234456678",我们使用: double f; scanf("%5lf",&f); 那么它只会读取5个字符,即1.234到变量f中。 注意:用scanf读取字符串的时候,如果字符串中存在空格,那么它将在空格处将该字符串裁掉,只取前面部分。scanf在遇到空格,制表符时会认为数据已经读取完毕,并将读取的数据转换成相应类型,存储到地址所在的存储空间中。
|