C/简单的输入输出
机器处理东西。我们将东西喂给机器,机器给我们吐出不同的东西。锯子将树木变为木板。内燃机将汽油转化为转动的能量。计算机也一样。不过,计算机为我们处理的不是物质材料,而是信息。
我们把信息喂给计算机,告诉计算机如何处理这些信息,然后取得结果。那一部分我们输入计算机的信息称为输入,而我们从计算机收到的信息则称为输出。任何地方都可以是输入的来源。键盘击打、网络数据,抑或转换到电信号的声波都是输入的例子。输出也有众多的形式,如显示器上播放的视频、终端上显示的一段字符串,或存储在硬盘上的数据。输入的集合与输出的产生统称为输入/输出,或缩写为I/O,是计算机的一项核心功能。
有趣的是,C语言并没有内置的I/O功能,取而代之的是包含I/O函数的外部函数库。我们能把这些函数编译、链接到程序里。在章节开始时的示例“Hello, World!”中,我们已经用到一个输出库函数:printf()
。你可能会想起这个函数属于stdio.h
函数库文件。正如文件名所示,stdio.h
包含标准化的I/O函数,可用于给我们的程序增加加输入/输出能力。本章将带你探索其中的一些函数。
使用printf()
输出
编辑
现在回忆之前的演示程序:
#include <stdio.h>
int main(void)
{
printf("Hello, World!");
return 0;
}
如果你把它编译运行,你就能看到下方的句子显示在屏幕上:
Hello, World! |
这项令人惊喜的成就是由 printf()
函数实现的。一个函数就像一个“黑盒子”,它为你完成特定工作,而不显示自身的内部结构。我们也可以借助C语言写自己的函数,但那就是后话了。
你已经看到用printf()
可以输出括号中双引号里的文本。我们称包含在引号中的文本为字面字符串(简称字符串),那个字符串则是printf的一个参数。
在此澄清一下:有时为了方便起见,我们在一个函数名称后写一对圆括号,提醒我们这确实是一个函数。然而,在大家都知道讨论的对象是函数时,这并不是必需的。
正如上文的例子所言,用printf()
就像打一段文字、两端加双引号一样简单(注意这是双引号,而不是两个单引号)。也就是说,你可以把任何字符串作为printf()
的参数打印出来:
printf("This sentence will print out exactly as you see it..."); |
而一旦它被包含在合适的main()
函数中,它将会显示:
This sentence will print out exactly as you see it... |
打印数值和转义字符
编辑占位符
编辑printf()
是一个强大的函数,很可能也是C程序中最常用的函数。
接下来我们用一个问题做例子。假如我们要计算:19 + 31。让我们用C语言求出答案。
现在我们就开始写
#include "stdio.h" // this is important, since printf
// can't be used without this header
int main(void)
{
printf("19+31 is");
但是卡在这里了!printf()
只能打印字符串!幸好printf有输出数值的方法。我们要做的就是在字符串中放一个占位格式控制符。这样写:
printf("19+31 is %d", 19+31);
顾名思义,占位符%d
给19与31相加得到的具体数值“占了位置”。
这些占位符称为格式说明符。还有很多格式说明符可以与printf()
使用。如果我们有一个单精度浮点数,我们可以用%f
完整输出。其他的格式说明符有:
%d
- 整型 (同%i)%ld
- 长整型 (同%li)%f
- 单精度浮点型%lf , %g
- 双精度浮点型[1]%c
- 字符型%s
- 字符串型%x
- 十六进制型
维基百科上有printf()
全部格式说明符的列表。
Tabs和换行
编辑假使我们想输出这样的文本:
1905 312 + -----
printf()
不会在每个语句结尾输出换行符:我们必须手动操作。可是怎样做呢?
我们能做的是使用换行转义字符。转义字符是一种特殊字符,我们能写出来,但它会在屏幕上做某些特殊的事情,如发出蜂鸣声、写一个tab字符等。要想写一个换行符,可以使用\n
。所有转义字符以反斜线开始。
因此,想要实现上述的输出,应该这样写:
printf(" 1905\n312 +\n-----\n");
为了使代码更清晰,我们将这个很长的printf语句分割成几行。然后我们的程序会变成这样:
#include <stdio.h>
int main(void)
{
printf(" 1905\n");
printf("312 +\n");
printf("-----\n");
printf("%d", 1905+312);
return 0;
}
此外还有很多其他转义字符可用。另一个常见的做法是用\t
写一个tab。你还可以用\a
让电脑的蜂鸣器发出响声,不过你不应该在自己的程序里过多地使用它,因为声音的过度使用对用户的感官不很友好。
其他输出方式
编辑puts()
编辑
在不考虑任何占位符或变量时,puts()
函数是一种在屏幕上输出字符串的非常简单的方法。它和我们在"Hello, World!"这个例子里看到的printf()
函数很是相像:
puts("Print this string.");
输出到屏幕的是:
Print this string.
紧接着是一个换行符(前文已经说到过)。(puts
函数会在输出的结尾加一个换行符。)
使用scanf()
输入
编辑
scanf()
函数是与printf()
输出函数等价的输入方法——它简单但强大。在最简单的调用中,scanf的格式字符串包含一个占位符,表示用户将要输入值的类型。这些占位符大抵与printf()
函数相同——%d
表示整数,%f
表示单精度浮点数,%lf
表示双精度浮点数。
然而,与printf()
相比,scanf()
有一点不同。scanf()
函数要求你将要存储输入值的变量内存地址。 虽然这里可以使用指针(存储内存地址的变量),这毕竟是一个之后才会涉及的概念。相反,较为简单的技巧是使用取地址运算符,即&。在我们讨论指针之前,现在我们最好先把它看作"魔法"。
下面是一个典型的用例:
#include "stdio.h"
int main(void)
{
int a;
printf("Please input an integer value: ");
scanf("%d", &a);
printf("You entered: %d\n", a);
return 0;
}
如果你要描述上面scanf()
函数产生的作用,它可以读作:“读取用户输入的整数并存储到变量a所在的地址”。
假如你要用scanf输入一个字符串,你不应该包含&运算符。下面的代码会产生运行时错误,很可能导致程序崩溃。
scanf("%s", &a);
正确的用法应该是:
scanf("%s", a);
这是因为你在使用字符串(%s
)格式说明符时,你用来存储值的变量是一个数组,数组名称(在这个例子中是a)本身指向它的基地址,因此不需要取地址运算符。
注意,使用scanf()
从用户键盘上获取数据可能让你的代码易受缓冲区溢出攻击,如果你不很谨慎,则可能导致其他不可预测的行为。考虑使用 fgets()
而不是scanf()
。
参考资料
编辑- ↑ 实际上
%f
也能输出double
型数据,但输入时%f
的使用则不同。更多细节请见维基百科上对C语言数据类型的介绍。