第3课 输入与输出
一、学习目标
- 掌握C/C++基本输入/输出语句的使用(针对标准输入/输出设备)
二、学习内容
提示:这里可以添加要学的内容
- cin——输入流对象
- cout——输出流对象
- scanf()——格式输入函数
- printf()——格式输出函数
- getchar()——输入一个字符
- putchar()——输出一个字符
三、扩展学习内容
- get()——输入流对象的成员方法,如 cin.get()
- put()——输出流对象的成员方法,如 cout.put()
- gets()——从标准设备读取字符直到遇到换行符(‘\n’)为止;
- puts()——将buffer中的字符输出到标准设备,直到遇到空字符(‘\0’)为止
- getline()——读取一行
1. C++的get()方法
get()是输入流对象的成员方法,它有3种形式:无参数的;有一个参数的;有3个参数的。
无参数的调用形式为
cin.get()
cin.get()用来从指定的输入流中提取一个字符(包括空白字符),其返回值就是读入的字符。 若遇到输入流中的文件结束符,则返回文件结束标志EOF(End Of File),一般以-1代表EOF,用-1而不用0或正值,是考虑到不与字符的ASCII代码混淆,但不同的C ++系统所用的EOF值有可能不同。
1. 无参数的get()
下面的代码示例使用get()方法读取字符
#include<iostream>
using namespace std;
int main() {
char ch;
cout << "enter a sentence:" << endl;
while ((ch = cin.get()) != EOF)
cout.put(ch);
cout << "end" << endl;
return 0;
}
运行代码,进行如图1所示的测试。
上面的代码示例演示的cin.get()和cout.put()与C语言中的getchar()函数和putchar()函数相比较。
#include <stdio.h>
int main() {
int ch = 0;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
EOF是 “End of File” 的缩写,它表示文件的结束。在C和C++中,EOF是一个特殊的整数常量,用于表示文件末尾。使用EOF可以帮助我们判断何时停止读取文件,以避免无限循环或读取无效的字符。
在大多数操作系统中,按下CTRL+Z组合键会发送一个特殊的控制字符,称为"EOF"字符,它告诉正在运行的程序输入流已经结束。当你在终端或命令行窗口中输入CTRL+Z时,操作系统会将EOF字符发送给正在运行的程序。对于大多数交互式程序和循环,程序会检测到EOF字符,将其解释为输入结束的信号,并相应地终止循环或退出程序。
因此,按下CTRL+Z可以被视为一种快捷方式,用于退出循环或程序,而不必手动输入特定的退出条件。请注意,这种行为可能会因操作系统和编程语言而有所不同,因此并不能保证在所有情况下都能成功退出循环。
2. 带一个参数的get()
有一个参数的cin.get()的调用形式为
cin.get(ch)
其作用是从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回true,如失败(遇文件结束符) 则函数返回false(文件结束符 为 ctrl + z)。上面的例子可以改写如下:
#include <iostream>
using namespace std;
int main() {
char ch;
cout << "enter a sentence:" << endl;
while (cin.get(ch)) {
//读取一个字符赋给字符变量ch, 如果读取成功,cin.get(ch)为真
//读取字符为文件结束符(Ctrl + z)时,cin.get(ch)为假
cout.put(ch);
}
cout << "end" << endl;
return 0;
}
运行程序,类似的输入与输出如下:
现在,我们知道可以使用cin.get(ch)和ch = cin.get()两种形式来输入一个字符。
上面不带参数和带一个参数的cin.get()方法都是完成单个字符的输入。此时,get()方法读取下一个输入字符,即使该字符是空格,制表符或换行符。还是通过键盘仿真的文件尾,对于DOS和Windows命令提示符模式,位按下Ctrl+Z;对于UNIX,是在行首按下Ctrl+D。
但是,cin.get(ch)和ch = cin.get()还是有区别的。如下表所示。
特征 | cin.get(ch) | ch = cin.get() |
---|---|---|
传输输入字符的方式 | 赋给参数ch | 将函数返回值赋给ch |
字符输入时方法的返回值 | 指向istream对象的引用 | 字符编码(int值 ) |
达到文件末尾时方法的返回值 | 转换为false | EOF |
其实get()方法也可以接收多个字符,此时,其函数原型如下:
istream& get(char*, int, char);
istream& get(char*, int);
第一个参数用于放置输入字符串的内存单元的地址。第二个参数通常指定为要读取的最大字符数+1(额外的一个字符用于存储结尾的空字符 ‘\0’,以便将输入存储为一个字符串)。第三个参数(如果提供了的话)指定用作分节符的字符,如果没有提供第三个参数则将换行符作为分界符。
注意: get()方法在读取字符时会将换行符(分界符号)留在输入流中,getline()方法则会丢弃换行符(分界符号)。
运行下面的代码
#include<iostream>
using namespace std;
int main() {
char ch1[20], ch2[20];
cin.get(ch1, 20);
cout << ch1 << endl;
cin.get(ch2, 20);
cout << ch2 << endl;''
return 0;
}
测试效果如下
留意输出的空行,应该不难得知——这里第二个cin,我们还没输入,系统就自动把上一次遗留的回车符读取,然后打印(第二次啥也没读取到),输出的就是一个空白行。针对这种情况,可以单纯使用cin.get()来读取一个字符,这里的cin.get()属于一种特殊变体,它会读取输入流中的下一个字符。
#include<iostream>
using namespace std;
int main() {
char ch1[20], ch2[20];
cin.get(ch1, 20);
cout << ch1 << endl;
cin.get(); // 读取一个字符,即'\n'
cin.get(ch2, 20);
cout << ch2 << endl;
return 0;
}
这样第二个cin,即cin.get(ch2, 20);就可以正常的读取下一行中的字符了。
上面的代码还可以写成如下形式
#include<iostream>
using namespace std;
int main() {
char ch1[20], ch2[20];
cin.get(ch1, 20).get();
cout << ch1 << endl;
//cin.get(); // 读取一个字符,即'\n'
cin.get(ch2, 20);
cout << ch2 << endl;
return 0;
}
之所以能够直接写成cin.get(ch,20).get();这样的形式,是因为cin.get(ch, 20);使用完后会返回一个cin对象,于是就变为cin.get()了。
get没有读取完的字符还会保留在输入缓冲区中,不会删除。所以下一次可以继续读取。
下面再来看看带3个参数的get()方法输入多个字符的情况。
3. 带3个参数的get()
有3个参数的get()的方法原型为
istream& get(char *, int, char);
调用形式为
cin.get(字符数组, 字符个数n, 终止字符)
或
cin.get(字符指针, 字符个数n, 终止字符)
其作用是从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。再将前面的示例改写如下:
#include<iostream>
using namespace std;
int main() {
char ch[40];
cout << "enter a sentence:" << endl;
cin.get(ch, 20, '\n'); //指定换行符为终止字符
cout << ch << endl;
//system("pause");
return 0;
}
运行程序,输入与输出如下:
输出为"This is a demo of c",为什么只有19个字符呢?因为存放的是一个字符串,因此在19个字符之后要加入一个字符串结束标志,实际上存放到数组中的是20个字符。
get()方法中第3个参数可以省写,此时默认为’\n’。下面两行等价:
cin.get(ch, 10, '\n');
cin.get(ch, 10);
终止字符也可以用其他字符。如
cin.get(ch,10,'0'); //在遇到字符'0'时停止读取操作。
2. C++的getline()方法
getline()方法的作用是从输入流中读取一行字符,其用法与带3个参数的get()方法类似,只是getlien则会丢弃分界符号(默认换行符)。其方法原型为
istream& getline(char *, int , char);
其调用形式为
cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符)
getline属于cin类的成员函数,他可以一直读取输入知道遇到换行符,同时它会丢弃换行符换成’\0’。
下面是一个cin.getline()的用法示例。
#include<iostream>
using namespace std;
int main() {
char ch1[32], ch2[32];
cout << "enter a sentence:" << endl;
cin.getline(ch1, 32, '/'); //读20个字符或遇'/'结束
cout << ch1 << endl;
cin.getline(ch2, 32); //读20个字符或遇'/n'结束
cout << ch2 << endl;
cout << ch2 << endl;
for(int i=0; ch2[i]!='\0'; i++)
cout << ch2[i];
return 0;
}
运行程序,输入与输出如下:
代码首先使用语句cin.getline(ch1, 32, ‘/’)从输入流读取32个字符 (或遇 ‘/’ 结束),即读取"When you are old"并输出;接下来使用语句cin.getline(ch2, 32);从输入流中接续读取32个字符(或遇 ‘\n’ 结束),显然这里是遇到 ‘\n’ 结束输入,即读取"and grey and full of sleep"并输出。
注意
(1)在输入流中有一个字符指针,指向当前应访问的字符。在开始时,指针指向第一个字符,在读入一个字符后,指针会自动向后面移动到下一个字符。
(2)cin.getline()方法遇终止标志字符"/“时停止读取,终止标志字符”/"并不会放到字符数组中。
(3)用getline()方法从输入流读字符时,遇到终止标志字符时结束,指针移到该终止标志字符之后,下一个getline()方法将从该终止标志的下一个字符开始接着读入,如上面程序运行结果所示那样。如果用cin.get()函数从输入流读字符时,遇终止标志字符时停止读取,指针不向后移动,仍然停留在原位置。下一次读取时仍从该终止标志字符开始。这是getline函数和get函数不同之处。
四、练习
- 输入两个整数,按每个整数占7个字符宽度并且右对齐输出。
- 输入一个单精度浮点数,按保留4位小数输出。
- 输入一个双精度浮点数,按保留10位小数输出。
- 输入3个字符数据,按每个字符占3位且左对齐输出。
- 输出由星号 '*'组成的菱形图案。
- 输入一个字符,输出有该字符组成的金字塔图案。
其中,1、2、3题合并到一个程序中,代码如下:
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
int a, b;
cout <<"输入两个整数:" << endl;
cin >> a >> b;
cout << setw(7) << a << setw(7) << b << endl;
float f;
cout <<"输入一个单精度浮点数:" << endl;
cin >> f;
cout << fixed << setprecision(4) << f << endl;
double d;
cout <<"输入一个双精度浮点数:" << endl;
cin >> d;
cout << fixed << setprecision(10) << d << endl;
return 0;
}
第4题的参考代码如下:
#include<iostream>
using namespace std;
int main() {
char ch;
cout << "enter 3 characters such as abc or xyz etc.:" << endl;
while ((ch = cin.get()) != '\n') {
cout.put(ch);
cout << " "; // 2个空格
}
return 0;
}
第6题的参考代码如下(按学习进度,给出的代码涉及到了两重循环结构,代码所涉及内容显然超前了):
#include<iostream>
using namespace std;
int main() {
char ch;
int lines;
cin >> ch >> lines;
for(int i=1; i<=lines; i++) {
for(int k=lines-i; k>0; k--)
cout << ' ';
for(int j=1; j<=2*i-1; j++) {
cout << ch;
}
cout << endl;
}
return 0;
}
运行该程序,输入一行:* 20 回车,输出如下图所示。