C/C++输入输出初级(一) (算法竞赛)

🌊用有趣的言语来阐述苦涩难懂的代码世界,让每一个技术都充满风趣!
🔭个人主页:散峰而望
🚀学习方向: C/C++等方向
📌专栏系列:
- 📖《C语言:从基础到进阶》
- 📚《编程工具的下载和使用》
- 🚀《C语言刷题》
- ⚖️《算法竞赛从入门到获奖》
💬人生格言:冀以尘雾之微,补益山海,荧烛末光,增辉岁月。
🎬博主简介



文章目录
- 前言
- 1.getchar和putchar
- 1.1 getchar()
- 1.2 putchar()
- 2. scanf和printf
- 2.1 printf()
- 2.1.1 基本用法
- 2.1.2 占位符
- 2.1.3 格式化输出
- 2.1.3.1 限定宽度
- 2.1.3.2 限定小数位
- 2.2 scanf
- 2.2.1 基本用法
- 2.2.2 占位符
- 2.2.3 scanf的返回值
- 2.3 练习
- 结语
前言
本篇文章将详细带各位了解getchar()与putchar()和scanf与printf之间的关系和区别,以便后面写代码选择更好的输入输出方式。
1.getchar和putchar
getchar()和putchar()是属于C语言的库函数,C++是兼容C语言的,所以C++中只要正确包含头文件也可以正常使用这两个函数。
1.1 getchar()
函数语法如下:
int getchar ( void );
getchar()函数返回用戶从键盘输入的一个字符,使用时不带有任何参数。
程序运行到这个命令就会暂停,等待用戶从键盘输入,等同于使用cin或scanf()方法读取一个字符。
它的原型定义在头文件 < cstdio >。
代码如下:
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{int ch;ch = getchar();cout << ch << endl;cout << (char)ch << endl;return 0;
}
getchar()不会忽略起首的空白字符,总是返回当前读取的第一个字符,无论是否为空格。如果读取失败,返回常量EOF,由于EOF通常是-1,所以返回值的类型要设为int,而不是char。
如果第一个输入的为空格,会出现什么情况 ?代码如下:
int main()
{int ch = getchar();cout << ch << endl;cout << (char)ch;//打印空格 ,a是没法读到的 cout << "xxxx" << endl;ch = getchar(); cout << (char)ch << endl;//只有再接收一次才行,才能接收a
}

竟然空格都被getchar()读入,那么回车键会不会一样都会读入呢?演示如下:
int main()
{int ch = getchar();cout << ch << endl;cout <<(char)ch;ch = getchar();cout << ch <<endl;//读取回车的ASCII值 cout << (char)ch;//打印回车,换行 cout << "xxxx" <<endl;return 0;
}

如何让getchar()函数读取失败,返回-1呢?其实需要在输入字符之前,直接按Ctrl+z就可以。
int main()
{int n = getchar();cout << n << endl;return 0;
}

getchar()通常和putchar()是一对儿,配合使用的。
1.2 putchar()
函数语法如下:
int putchar( int character );
putchar()函数将它的参数字符输出到屏幕,它的原型定义在头文件< cstdio >。
#include <cstdio>
int main()
{int ch = 0;ch = getchar();putchar(ch);return 0;
}
由上面的代码示例中可以看到用int定义的字符,cout打印的是ASCII值,那该怎么做?用putchar()。
int main()
{int n = getchar();cout << n <<endl;putchar(n);return 0;
}

同时,putchar()也可以单独使用,演示如下:
int main()
{//int n = getchar();//cout << n <<endl;//putchar(n);//putchar还可以单独使用putchar('x'); putchar('\n');//\n意思换行 putchar('a');putchar('\n');putchar('b');putchar('a\n');putchar('x\n'); //不能这样用 return 0;
}

操作成功时,putchar()返回输出的字符,否则返回常量EOF。
这里先学会这两个函数的使用,在后期算法课的模块,会学到快速读写,到时候就会用到这两个函数。
2. scanf和printf
scanf()和printf()是属于C语言的库函数,C++是兼容C语言的,所以C++中只要正确包含头文件也可以正常使用这两个函数。而且这两个函数在算法竞赛题目中使用的非常频繁,尤其是在输入输出格式控制中。
2.1 printf()
函数语法如下:
int printf ( const char * format, ... );
2.1.1 基本用法
printf()的作用是将参数文本输出到屏幕。
它名字里面的print表示打印,f代表format(格式化),表示可以定制输出文本的格式。
代码如下:
#include <cstdio>
int main()
{printf("Hello World");return 0;
}

上面命令会在屏幕上输出一行文字“Hello World”。
printf()不会在行尾自动添加换行符,运行结束后,光标就停留在输出结束的地方,不会自动换行。
为了让光标移到下一行的开头,可以在输出文本的结尾,添加一个换行符\n。
#include <cstdio>
int main()
{printf("Hello World\n");return 0;
}

如果文本内部有换行,也是通过插入换行符来实现,如下方代码:
int main()
{printf("Hello\nWorld\n");printf("Hello\n");printf("World\n");return 0;
}

2.1.2 占位符
printf()可以在输出文本中指定占位符。所谓“占位符”,就是这个位置可以用其他值代入。
#include <cstdio>
// 输出 There are 3 apples
int main()
{printf("There are %d apples\n", 3);return 0;
}

上面示例中,There are %d apples\n是输出文本,里面的%d就是占位符,表示这个位置要用其他值来替换。占位符的第一个字符一律为百分号%,第二个字符表示占位符的类型,%d表示这里代入的值必须是一个整数。
printf()的第二个参数就是替换占位符的值,上面的例子是整数3替换%d。执行后的输出结果就是There are 3 apples。
常用的占位符除了%d,还有%s表示代入的是字符串。
int main()
{printf("%s will come tonight\n", "zhangsan");return 0;
}

上面示例中,%s表示代入的是一个字符串,所以printf()的第二个参数就必须是字符串,这个例子是zhangsan。执行后的输出就是zhangsan will come tonight。
输出文本里面可以使用多个占位符。
int main()
{printf("%s says it is %d o'clock\n", "lisi", 21);return 0;
}

上面示例中,输出文本%s says it is %d o’clock有两个占位符,第一个是字符串占位
符%s,第二个是整数占位符%d,分别对应printf()的第二个参数(lisi)和第三个参数
(21)。执行后的输出就是lisi says it is 21 o’clock。
printf()参数与占位符是一一对应关系,如果有n个占位符,printf()的参数就应该有n + 1个。如果参数个数少于对应的占位符,printf()可能会输出内存中的任意值。
占位符列举:
printf()的占位符有许多种类,与数据类型相对应。
下面列出常用的占位符,方便查找,具体含义在后面章节介绍。
| 占位符 | 介绍 |
|---|---|
| %d | 十进制整数 |
| %lld | 十进制long long int类型 |
| %f | 小数(包含float类型和double类型) |
| %lf | double类型浮点数 |
| %Lf | long double类型浮点数 |
| %c | 字符 |
| %s | 字符串 |
| %a | 十六进制浮点数,字母输出为小写 |
| %A | 十六进制浮点数,字母输出为大写 |
| %e | 使用科学计数法的浮点数,指数部分的e为小写 |
| %E | 使用科学计数法的浮点数,指数部分的E为大写 |
| %i | 整数,基本等同于%d |
| %g | 6个有效数字的浮点数。整数部分一旦超过6位,就会自动转为科学计数法,指数部分的e为小写 |
| %G | 等同于%g,唯一的区别是指数部分的E为大写 |
| %hd | 十进制short int类型 |
| %ho | 八进制short int类型 |
| %hx | 十六进制short int类型 |
| %hu | unsigned short int类型 |
| %ld | 十进制long int类型 |
| %lo | 八进制long int类型 |
| %lx | 十六进制long int类型 |
| %lu | unsigned long int类型 |
| %llo | 八进制long long int类型 |
| %llx | 十六进制long long int类型 |
| %llu | unsigned long long int类型 |
| %Le | 科学计数法表示的long double类型浮点数 |
| %n | 已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中 |
| %o | 八进制整数 |
| %p | 指针 |
| %u | 无符号整数(unsigned int) |
| %x | 十六进制整数 |
| %zd | size_t类型 |
| %% | 输出一个百分号 |
2.1.3 格式化输出
printf()可以定制占位符的输出格式。
2.1.3.1 限定宽度
printf()允许限定占位符的最小宽度。
#include <cstdio>
int main()
{printf("%5d\n", 123); // 输出为 " 123" return 0;
}

上面示例中,%5d表示这个占位符的宽度至少为5位,可以超过5位。如果不满5位,对应的值的前面会添加空格。输出的值默认是右对齐,即输出内容前面会有空格;如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的%的后面插入一个-号。
#include <cstdio>
int main()
{printf("%-5d\n", 123); // 输出为 "123 " return 0;
}

上面示例中,输出内容123的后面添加了空格。
对于小数,这个限定符会限制所有数字的最小显示宽度。
#include <cstdio>
// 输出 " 123.450000"
int main()
{printf("%12f\n", 123.45);return 0;
}

上面示例中,%12f表示输出的浮点数最少要占据12位。由于小数的默认显示精度是小数点后6位,所以123.45输出结果的头部会添加2个空格。
2.1.3.2 限定小数位
输出小数时,有时希望限定小数的位数。举例来说,希望小数点后面只保留两位,占位符可以写成%.2f。演示如下:
#include <cstdio>
// 输出 0.50
int main()
{printf("%.2f\n", 0.5);return 0;
}

如果希望小数点后面输出3位(0.500),占位符就要写成%.3f。
这种写法可以与限定宽度占位符,结合使用。
#include <cstdio>
// 输出为 " 3.14"
int main()
{printf("%6.2f\n", 3.14);return 0;
}

上面示例中,%6.2f表示输出字符串最小宽度为6,小数位数为2。所以,输出字符串的头部有两个空格。
最小宽度和小数位数这两个限定值,都可以用*代替,通过printf()的参数传入。
#include <cstdio>
int main()
{printf("%*.*f\n", 6, 2, 0.5);return 0;
}
// 等同于printf("%6.2f\n", 0.5);

上面示例中,%*.*f的两个星号通过printf()的两个参数6和2传入。
2.2 scanf
函数语法如下:
int scanf ( const char * format, ... );
2.2.1 基本用法
scanf()函数用于读取用戶的键盘输入。
程序运行到scanf()这个语句时,会停下来,等待用戶从键盘输入。
用戶输入数据、按下回⻋键后,scanf()就会处理用戶的输入,将其存入变量。
scanf()的语法跟printf()类似。
请看下面的代码:
#include <cstdio>
int main()
{int i = 0;scanf("%d", &i);printf("%d\n", i);return 0;
}

特别注意,scanf函数的占位符后面一般不会加\n,\n是换行,一般在输出的时候才使用
它的第一个参数是一个格式字符串,里面会放置占位符(与printf()的占位符基本一致),告诉编译器如何解读用戶的输入,需要提取的数据是什么类型。这是因为C语言的数据都是有类型的,scanf()必须提前知道用戶输入的数据类型,才能处理数据。
它的其余参数就是存放用戶输入的变量,格式字符串里面有多少个占位符,就有多少个变量。上面示例中,scanf()的第一个参数%d,表示用戶输入的应该是一个整数。%d就是一个占位符,%是占位符的标志,d表示整数。第二个参数&i表示,将用戶从键盘输入的整数存入变量i。
scanf函数中存储数据的变量前面必须加上&运算符(指针变量除外),因为scanf()需要的是地址,必须将变量i的地址取出来传给scanf函数。
如果这里的变量i是数组,那就不用加&运算符。(后期慢慢介绍)
下面是一次从键盘读取多个变量的例子,先来一个简单的:
int main()
{int a, b, c, d;scanf("%d%d%d%d", &a, &b, &c, &d);printf("%d %d %d %d\n", a, b, c, d);return 0;
}

由上面的代码,会发现如果不按格式输入会出错,所以scanf函数中指定的格式和给程序输入的数据格式要严格的匹配,否则可能不能得到想要的值。

scanf()处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。


换一个例子:
int main()
{int i = 0;int j = 0;float x = 0;float y = 0;scanf("%d%d%f%f", &i, &j, &x, &y);printf("i = %d\n", i);printf("j = %d\n", j);printf("x = %f\n", x);printf("y = %f\n", y);return 0;
}
上面示例中,格式字符串%d%d%f%f,表示用戶输入的前两个是整数,后两个是浮点数。比如键盘输入1 -20 3.4 -4.0e3,这四个值依次放入i、j、x、y四个变量。
所以,用户输入的数据之间,有一个或多个空格不影响scanf()解读数据。另外,用戶使用回车键,将输入分成几行,也不影响解读。
scanf()处理用戶输入的原理是:用户的输入先放入缓存,等到按下回⻋键后,按照占位符对缓存进行解读。解读用户输入时,会从上一次解读遗留的第一个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止。
代码演示:
int main()
{int x = 0;float y = 0;// 用戶输入 " -13.45e12# 0" scanf("%d", &x);printf("%d\n", x);scanf("%f", &y);printf("%f\n", y);return 0;
}

scanf分开写和不分开写效果是一样的

上面示例中,scanf()读取用戶输入时,%d占位符会忽略起首的空格,从-处开始获取数据,读取到-13停下来,因为后面的.不属于整数的有效字符。这就是说,占位符%d会读到-13。
第二次调用scanf()时,就会从上一次停止解读的地方,继续往下读取。这一次读取的首字符是.,由于对应的占位符是%f,会读取到.45e12,这是采用科学计数法的浮点数格式。后面的#不属于浮点数的有效字符,所以会停在这里。
2.2.2 占位符
scanf()常用的占位符如下,与printf()的占位符基本一致。
| 占位符 | 介绍 |
|---|---|
| %d | 十进制整数 |
| %lld | 十进制long long int类型 |
| %f | 小数(包含float类型和double类型) |
| %lf | double类型浮点数 |
| %Lf | long double类型浮点数 |
| %c | 字符 |
| %s | 字符串 |
| %[] | 在方括号中指定一组匹配的字符(比如%[0-9]),遇到不在集合之中的字符,匹配将会停止 |
上面所有占位符之中,除了%c以外,都会自动忽略起首的空白字符。%c不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。
如果要强制跳过字符前的空白字符,可以写成scanf(" %c", &ch),即%c前加上一个空格,表示跳过零个或多个空白字符。
#include <cstdio>
int main()
{char ch = 0;scanf("%c", &ch);printf("--%c--\n", ch);return 0;
}
在输入字符a之前,没有输入空白字符,正常读取:

在输入字符a之前,输入一些空格,读取到的是缓冲区中的第一个空格:

为了避免在读取这些空白字符,可以换一种方式:
#include <cstdio>
int main()
{char ch = 0;scanf(" %c", &ch);//%c前面的空格会让scanf强制跳过空白字符,去读取非空白字符 printf("--%c--\n", ch);return 0;
}
结果演示:


了解这一点后,当%c和%d等占位符连续使用的时候,也要注意,%c默认不会跳过空白字符的,所以在输入的时候,要非常小心,比如:
#include <cstdio>
int main()
{ int a;char ch;scanf("%d%c", &a, &ch);printf("%d %c\n", a, ch);return 0;
}
正确的输入:

错误的输入;

如果在输入的时候,就是想在整数和字符之间加上空格,那么scanf中的格式串中%c的前面就要加上空格。
int main()
{ int a;char ch;scanf("%d %c", &a, &ch);//%c的前面加上空格,是强制跳过数据输入中的空白字符 printf("%d %c\n", a, ch);return 0;
}

总之要注意,scanf中规定的输入格式和控制台输入数据的格式要保持一致才可能得到正确的结果。
2.2.3 scanf的返回值
scanf()的返回值是一个整数,表示成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回0。如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量EOF(-1)。
int main()
{int a = 0;int b = 0;float f = 0.0f;int r = scanf("%d %d %f", &a, &b, &f);printf("a=%d b=%d f=%f\n", a, b, f);printf("r = %d\n", r);return 0;
}
输入输出测试:

如果输入2个数后,按ctrl+z,提前结束输入:

在Dev-C++中按下ctrl+z,才结束了输入,我们可以看到r是2,表示正确读取了2个数值。
如果输入的数据一个都不能匹配成功的话,则输出的r是0。

如果一个数字都不输入,直接按ctrl+z,输出的r是-1,也就是EOF

掌握了scanf的返回值,我们一般会通过scanf的返回值来处理多组数据输入的竞赛题目,后面我们可以看到的。
2.3 练习
浮点除法
甲流疫情死亡率
计算并联电阻的阻值
与圆相关的计算
糖果游戏
结语
希望这篇文章可以更好的了解getchar()与putchar()和scanf与printf之间的关系和区别,下一篇将详讲cin和cout。期待各位一起共同努力。
同时愿诸君能一起共渡重重浪,终见缛彩遥分地,繁光远缀天。


