物联网工程师技术之IO输入输出技术
本章重点
语句和语句块
printf函数
scanf函数
在C语言编程中,经常需要通过输入设备(如键盘)向程序录入信息,或者将信息显示在输出设备(如屏幕),这时,可以使用输入输出语句来完成。输入输出语句是用户与程序交互的唯一途径,掌握好输入输出语句对后面的学习至关重要。本章将针对输入输出进行详细地讲解。
4.1语句
4.1.1语句
正如一栋楼是由一块块砖组成,C语言编写的程序主要由语句组成的。因此,要想写出正确的C程序,首先要学会写出正确的语句。
C语言中的多条语句也可组成一个语句块,语句块指的是用花括号{}括起来的多条语句。合理地使用语句块可以让程序的逻辑更加清晰。本小节将重点介绍什么是语句和语句块。
在C语言中,程序是由语句组成的,它是程序最基本的执行单元。先来看几个简单的例子,具体如下:
1、 用于向控制台输出Hello world中的printf语句,具体示例如下:
printf("Hello world!\n");
2、 用于跳出当前函数的返回语句,具体示例如下:
return 0;
3、 用于定义变量的语句,具体示例如下:
int i = 10;
4、 用于执行简单运算的语句,具体示例如下:
sum = 1.7f + 2.5f;
需要特别注意的是,在书写语句时,语句的末尾要有英文分号。
为了帮助大家更好地学习语句,接下来,通过一个案例来演示,如例4-1所示:
例4-1 语句
#include <stdio.h>
int main()
{
float sum = 0.0f; // 定义了一个变量sum
sum = 1.2f + 3.5f; // 将sum重新赋值
printf("%f\n", sum); // 输出语句:输出浮点数sum的值
printf("Hello world\n"); // 输出语句:输出Hello world
return 0; // 返回语句
}
程序的运行结果如图4-1所示:
图 4‑1语句
在例4-1中,main()函数中包含了5条语句,这5条语句的作用如下所示:
第4行:定义了一个浮点数变量sum,并将浮点数的初值设为0.0;
第5行:将1.2和3.5两个浮点数相加,并将加法运算的结果赋值给sum;
第6行:利用printf输出语句打印sum的值;
第7行:利用printf输出语句输出Hello world
第8行:返回语句,跳出整个main函数,程序结束。
4.1.2语句块
在C程序中,使用“{}”包含的多条语句称为一个语句块,具体示例如下:
{
float sum = 0.0f;
sum += 3.5f;
printf("%f", sum);
}
上面的示例就是一个语句块,它包含了三条语句,整个语句块定义了一个变量sum并打印它的值。 除了在形式上将一些语句组织在一起之外,语句块还有一个显著的作用就是它可以改变变量的作用域。所谓作用域就是在程序中可以正确使用这个变量的范围。定义在语句块内的变量只能在语句块内使用。为了大家更好地理解语句块变量的作用域,接下来,通过一个案例来演示,如例程4-2所示:
例4-2 语句块
#include <stdio.h>
int main()
{
int sum = 3; // 定义了一个语句块外的变量sum
{
int sum = 5; // 在语句块内定义了一个新的变量sum
printf("%d\n", sum); // 在语句块之内输出sum的值
}
printf("%d\n", sum); // 在语句块之外输出sum的值
return 0;
}
程序的运行结果如图4-2所示:
图 4‑2 语句块
从上面的运行结果中可以看出:第一次调用printf的时候,输出的sum是语句块内的sum值,这说明了在语句块内外出现重名变量时,在块内使用的还是块内的变量;第二次调用printf的时候输出的是语句块之外的sum,这说明了出了语句块之后,语句块内定义的sum就失效了,这从侧面证明了块内定义的sum作用域只在块内。
4.2printf语句
printf是C语言中最基本的输出语句,它负责向控制台中输出内容。完整的printf用法非常庞杂,本节只针对printf最常用的几种用法进行讲解,包括利用printf输出字符串,输出字符,输出整数,输出浮点数等等。
4.2.1printf输出字符串
printf最简单的用法是直接输出一串字符串,其语法格式如下所示:
printf("字符串");
需要注意的是,字符串要用英文双引号括起来。例如,之前出现过的Hello world程序,如例程4-3所示:
例4-3 printf输出字符串
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
程序的运行结果如图4-3所示:
图 4‑3 printf输出字符串
除了直接将字符串写在printf之中,printf还支持用下面的方式输出一个字符串,具体格式如下所示:
printf("%s", "字符串");
在上述语法格式中, %s表示printf要输出一个字符串,字符串则是用户真正想要输出的内容。
对例4-3进行修改,修改后的代码如例4-4所示:
例4-4 printf格式化输出字符串
#include <stdio.h>
int main()
{
printf("%s", "Hello, world!\n");
return 0;
}
程序的运行结果如图4-4所示:
图 4‑4 printf格式化输出字符串
通过图4-3和图4-4的比较,发现使用两种printf语句输出字符串的效果是一致的。
如果字符串太长,也可以将它拆成多个字符串分别输出:
printf("%s %s", "字符串", "字符串");
和此前的例子一样,这里printf的第一个参数表示真正要输出在控制台的内容。%s表示输出一个字符串,这里有两个“%s”表示要输出两个字符串,并且两个字符串之间存在一个空格。例4-5展示了如何利用printf输出多个字符串:
例4-5 printf输出多个字符串
#include <stdio.h>
int main()
{
printf("%s %s", "Hello", "world!\n");
return 0;
}
程序的运行结果如图4-5所示:
图 4‑5 printf输出多个字符串
需要说明的是,在上面的语法中两个%s之间不一定非要用空格来连接,第一个%s之前和第二个%s之后也可以有其他的内容,输出的格式完全是由用户自己控制的,比如下面的语句:
printf("%s%s\n", "Hello", " world!");
这条printf语句输出了紧挨着的两个字符串,在第二个字符串之后还输出了一个\n,但是它的效果和前面是完全一样的:原来两个字符串之间的空格被放进了要输出的第二个字符串,而第二个字符串原本的\n被单独提出来放在了第一个参数中。
4.2.2printf输出字符
printf除了可以输出字符串外,还可以输出字符,使用printf输出单个字符的语法格式如下所示:
printf("%c", 字符);
使用printf一次输出多个字符的语法格式如下所示:
printf("%c %c", 字符, 字符);
接下来,通过一个案例来演示如何利用printf输出字符的形式打印出Hello world,如例4-6所示:
例4-6 printf输出字符
1 #include <stdio.h>
2 int main()
3 {
4 printf("%c%c%c%c%c%c%c%c%c%c%c%c%c",
5 'H', 'e', 'l', 'l', 'o', ' ',
6 'w', 'o', 'r', 'l', 'd', '!', '\n');
7 return 0;
8 }
程序的运行结果如图4-6所示:
图 4‑6 printf输出字符
4.2.3printf输出整数
printf的第三个用法是输出整数。整数类型有很多种,其中,用于输出一个有符号整数的语法格式如下所示:
printf("%d", 有符号整数);
如果需要输出多个整数,只需要在printf中放入多个%d。接下来,通过一个案例来演示使用printf输出三个int类型有符号整数值的情况,如例4-7所示。
例4-7 printf输出有符号整数
#include <stdio.h>
int main()
{
int a = 15, b = -22, c = 123456; // 定义三个int类型变量
printf("%d %d %d\n", a, b, c);
return 0;
}
程序的运行结果如图4-7所示:
图 4‑7 printf输出有符号整数
在例4-7中,首先定义了三个int类型的变量a,b,c,并且它们都有初始值,然后使用printf输出这三个变量的值。
除了输出有符号整数,printf还可以输出无符号整数,语法格式如下所示:
printf("%u", 无符号整数);
其中%u表示要输出一个无符号整数。需要注意的是,如果在%u后面给出的是一个有符号整数,那么printf会首先将该整数转为无符号类型,然后再输出它的值。接下来,通过一个案例来演示如何使用printf输出两个无符号整数,如例4-8所示:
例4-8 printf输出无符号整数
#include <stdio.h>
int main()
{
unsigned short u = 456; // 定义一个无符号类型整数u
int i = -1; // 定义一个有符号类型整数i,初值为-1
printf("%u %u\n", u, i);
return 0;
}
程序的输出结果如图4-8所示:
图 4‑8 printf输出无符号整数
在上面的程序中,首先定义了一个无符号整数u,并初始化它的值为456;然后定义了一个有符号类型的int整数i,并初始化为-1。当使用printf输出无符号整数u和i时,由于i是一个有符号的整数,因此,它首先会被转换为无符号类型,然后再输出,这也是输出的i值为4294967295的原因。
除了上述几种用法,printf还可以用来输出八进制和十六进制整数。printf输出八进制的语法如下:
printf("%o", 八进制整数);
其中%o表示输出的是一个八进制整数。
printf输出十六进制整数的语法如下:
printf("%x", 十六进制整数);
或者是:
printf("%X", 十六进制整数);
两者的区别在于%x输出的十六进制整数中所有字母都是小写,而%X输出的字母都是大写。
接下来,通过一个案例来演示如何使用printf输出八进制和十六进制整数,如例4-9所示。
例4-9 printf输出其他进制
#include <stdio.h>
int main()
{
int a = 0123; // 定义了一个八进制整数0123
int b = 0x1a2b3c4d; // 定义了一个十六进制整数0x1a2b3c4d
printf("%o %x %X\n", a, b, b);
return 0;
}
运行
图 4‑9 printf输出其他进制
4.2.4在上述程序中,首先定义了一个八进制的整数a,并赋值为0123;然后定义了一个十六进制的整数b并进行赋值。最后使用printf将a以八进制的形式,b以小写十六进制和大写十六进制的形式打印出来,结果如图4-9所示。printf输出浮点数
printf不仅可以输出整数,还可以输出浮点数,使用printf输出浮点数的语法格式如下所示:
printf("%f", 浮点数);
其中%f表示以十进制的形式输出一个浮点数。看一个使用printf输出浮点数的例子,如例4-10所示
例4-10 printf输出浮点数
1 #include <stdio.h>
2 int main()
3 {
4 double e = 2.718; // 自然对数
5 float pi = 3.1416f; // 圆周率
6 printf("%f %f\n", e, pi);
7 return 0;
8 }
程序的运行结果如图4-10所示:
图 4‑10 printf输出浮点数
在这个例子中,程序里首先定义了两个浮点数e和pi,随后利用printf来输出这两个浮点数的值。需要注意的是,printf中的%f默认对应的浮点数是double类型,因此上面例子中的e会被首先转为double类型的浮点数随后再输出。
浮点数除了可以利用十进制表示之外,也可以利用科学计数法来表示。printf也支持利用科学计数法输出一个浮点数。其语法格式如下所示:
printf("%e", 浮点数);
或者是
printf("%E", 浮点数);
两者唯一的区别是在科学计数法的输出中指数符号e是小写还是大写。%e表示小写,而%E表示大写。下面的例子展示了如何利用科学计数法的形式输出一个浮点数,如例4-11所示:
例4-11 printf输出浮点数
1 #include <stdio.h>
2 int main()
3 {
4 double e = 2.718; // 自然对数
5 float pi = 3.1416f; // 圆周率
6 printf("%e %E\n", e, pi);
7 return 0;
8 }
程序的运行结果如图4-11所示:
图 4‑11 printf输出浮点数
在例4-11中,首先定义了两个浮点数e和pi,然后分别以小写和大写的形式输出了两个以科学计数法表示的浮点数的值。
printf还可以控制浮点数的输出长度。默认情况下,printf会输出小数点后六位的数。 printf还允许程序员自己设定输出小数的长度。它的语法如下所示:
printf("%.小数位数f", 浮点数);
其中小数位数指定了需要输出的小数长度。下面的例子展示了printf的这种用法,如例4-12所示:
例4-12 printf输出定长小数
1 #include <stdio.h>
2 int main()
3 {
4 float pi = 3.1416f; // 圆周率
5 printf("%.0f %.2f %.4f\n", pi, pi, pi);
6 return 0;
7 }
程序的运行结果如图4-12所示:
图 4‑12 printf输出定长小数
在例4-12中,程序首先定义了圆周率pi的值3.1416,随后使用printf分别输出pi值的整数部分,pi值带两位小数的值,pi值带四位小数的值。
4.2.5printf格式控制字符
通过前面的学习,发现要想熟练使用printf函数,关键在于掌握printf中经常使用的格式控制字符,它们控制了printf输出的具体类型。表4-1整理了4.2节中提到的所用常用格式控制字符。
表4-1 常用printf格式字符
常用格式字符 |
含义 |
%s |
输出一个字符串 |
%c |
输出一个字符 |
%d |
以十进制输出一个有符号整型 |
%u |
以十进制输出一个无符号整型 |
%o |
以八进制输出一个整数 |
%x |
以十六进制输出一个小写整数 |
%X |
以十六进制输出一个大写整数 |
%f |
以十进制输出一个浮点数 |
%e |
以科学计数法输出一个小写浮点数 |
%E |
以科学计数法输出一个大写浮点数 |
最好对表中的内容有个简单的介绍
4.3scanf语句
scanf是C语言中最基本的输入函数。它负责从控制台上接受用户的输入。和printf类似,scanf也可以灵活接受各种类型的输入,包括字符串,字符,整型,浮点数等等。本节将逐一介绍如何利用scanf从控制台上获取用户的输入。
4.3.1scanf读入字符串
本节中首先介绍如何利用scanf获得用户输入的字符串。由于scanf需要从控制台中获取输入,因此在使用scanf获取字符串之前首先要定义一个字符数组来保存获得的字符串:
char str[256];
上面的语句定义了一个字符数组str,它的大小为256,目前可以将它理解为由连续256个字符组成的一段连续的内存。
利用scanf获得字符串输入的语法如下:
scanf("%s", 字符串地址);
和printf类似,这里也用%s来表示数据的类型是一个字符串,scanf的第二个参数字符串地址指明了需要将字符串保存在什么地方。在字符数组中,数组的名称指示了字符数组的地址,因此可以直接用数组名作为scanf的第二个参数。
需要注意的是,scanf用来从控制台接受用户输入的字符串,只要用户的输入中包含了以下任意一种字符,scanf就认定用户想要输入的字符串已经完毕了。这些字符包括:
表4-2 scanf输入字符串的终止符
字符 |
含义 |
0x20 |
空格 |
\t |
水平制表符(tab键) |
\n |
换行 |
\v |
垂直制表符 |
\f |
换页 |
\r |
回车 |
从上面的表格可以看出,如果用户输入后按下了空格、回车、tab等键,scanf都会认为输入字符串已经终止。接下来,通过一个案例来演示如何使用scanf读入字符串,如例4-13所示。
例4-13 scanf读入字符串
#include <stdio.h>
int main()
{
char str[256]; // 字符数组保存得到的字符串
scanf("%s", str);
printf("%s\n", str);
return 0;
}
程序的运行结果如图4-13所示:
图 4‑13 scanf读入字符串
在例4-13中,首先定义了一个长度为256个字符的字符数组str,随后利用scanf获得用户从控制台的输入;接下来利用printf将得到的字符串打印在控制台上,例如,用户从控制台上输入了Hello world。
这从图4-13可以看出,尽管输入的字符串是Hello world,但是程序只打印了Hello。这是因为在Hello world中包含了一个空格,因此scanf只能读到之前的Hello而无视了空格之后的world。相应地,假设输入是不含空格的Helloworld,那么上述程序的运行结果如图4-14所示:
图 4‑14 scanf输入字符串
这时从图4-14看出,输入的Helloworld被完整地输出在控制台上。由于输入的Helloworld中不包含空格,因此输入完成后的回车键就被scanf认为是字符串终止的标志,整个Helloworld都被scanf读进了str数组中。
4.3.2scanf读入字符
利用scanf还可以读入单个字符,其语法格式如下所示:
scanf("%c", 字符地址);
在上述语法格式中,%c用来表示获取单个字符,字符地址用于告诉scanf获得的字符保存在哪个变量中。与scanf读取字符串不同的是,字符地址需要通过“&字符名称”的方式获取。
下面的例子中展示了如何从scanf获得用户输入的一个字符,如例4-14所示:
例4-14 scanf读入字符
#include <stdio.h>
int main()
{
char c; // 保存用户读入的字符
scanf("%c", &c);
printf("%c\n", c);
return 0;
}
程序的运行结果如图4-15所示:
图 4‑15 scanf读入字符
在例4-14中,首先读入一个字符,然后将字符在控制台上输出,用以验证scanf读入的字符是否正确。假设用户输入了一个英文字母e。
需要注意的是,scanf还可以读入一些特殊字符。假设用户输入的是一个回车,程序运行后的结果如图4-16所示:
图 4‑16 scanf读入字符
在图4-16所示的结果中,程序一共打印出三个回车,具体如下:
第一个回车:用户输入的回车;
第二个回车:printf打印的字符变量c;
第三个回车:printf输出变量c之后末尾的回车。
上面的运行结果证明了特殊字符回车被scanf以%c的形式正确地读入到了字符变量c当中。
4.3.3scanf读入整数
同printf输出整数类似,scanf读入整数时,也需要用到格式控制符%d,具体语法格式如下:
scanf("%d", 整数地址);
在上述语法格式中,%d表示scanf要读入的是一个十进制有符号整数,并将这个整数存放在第二个参数所指示的地址当中。当利用scanf读入整数时,输入的整数可以包括正负号。下面是一个利用scanf读入十进制整数的例子,如例4-15所示。
例4-15 scanf读入整数
#include <stdio.h>
int main()
{
int i; // 用来保存读入的十进制整数:
scanf("%d", &i);
printf("%d\n", i);
return 0;
}
在例4-15中,首先定义了一个int类型的变量i,然后使用scanf从控制台读入一个整数,最后使用printf将读入的整数输出在控制台上。假设用户输入的整数是1234,程序的运行结果如图4-17所示:
图 4‑17 scanf读入整数
为了验证scanf能否接受带正负号的输入,假设用户输入的是+1234,程序的运行结果如题4-18所示。
图 4‑18 scanf读入整数
如果用户输入的是-1234,程序的运行结果如图4-19所示。
图 4‑19 scanf读入整数
除了接受十进制输入,scanf也可以接受八进制或者十六进制的输入。scanf读入八进制整数的语法是:
scanf("%o", 整数地址);
其中%o表示scanf等待输入的是一个八进制整数,输入的整数也可以包括正负号。下面的例程展示了如何利用scanf读入一个八进制整数,如例4-16所示。
例4-16 scanf读入八进制数
1 #include <stdio.h>
2 int main()
3 {
4 int i; // 保存读入的整数
5 scanf("%o", &i);
6 printf("%o\n", i);
7 return;
8 }
需要说明的是:在程序中定义一个八进制常量时必须要在开头写0,但是在scanf读入八进制整数的时候这个0可以忽略不写。这是因为scanf会自动将用户的输入视为一个八进制整数。例如,不管输入123还是0123,scanf得到的都是相同的八进制整数,具体如图4-20、图4-21所示。
图 4‑20 scanf读入八进制整数
图 4‑21 scanf读入八进制整数
scanf读入十六进制整数的语法格式如下所示:
scanf("%x", 整数地址);
其中%x表示scanf等待的是一个十六进制整数,这个十六进制整数可以以0x或者0X开头,可以包括正负号,也可以混杂a到f的大小写。先来看一个例子,如例4-17所示。
例4-17 scanf读入十六进制数
#include <stdio.h>
int main()
{
int i; // 保存读入的整数
scanf("%x", &i);
printf("%x\n", i);
printf("%X\n", i);
return 0;
}
在例4-17中,首先定义了一个int类型的变量i,用来保存scanf读入的结果。接下来,利用scanf将输入的十六进制数保存在i中,并用大小写两种方式将i的值打印在控制台上。假设用户的输入是0x1a2b3c4d,程序的运行结果如图4-22所示:
图 4‑22 scanf读入十六进制整数
也可以省略最开头的0x,直接输入十六进制数字。假设用户的输入是1a2b3c4d,则程序的运行结果如图4-23所示。
图 4‑23 scanf读入十六进制整数
还可以在输入的十六进制数当中混杂大小写,比如用于输入1a2B3c4D,程序的运行结果如图4-24所示。
图 4‑24 scanf读入十六进制整数
由此可见,虽然使用scanf读取的十六进制形式不同,但最后读入的十六进制整数结果相同。
4.3.4scanf读入浮点数
使用scanf还可以读入浮点数,其基本的语法格式如下所示:
scanf("%f", 浮点数地址);
在上述语法格式中,%f表示要输入的是一个十进制小数,输入当中可以包含小数点和正负号,输入的结果保存在第二个参数浮点数地址指示的位置上。需要注意的是,在printf中%f默认对应的数据类型是double,而在scanf中%f对应的数据类型为float,因此如果要用%f来读入一个浮点数的话,需要声明一个float类型的变量。先来看一个例子,如例4-18所示。
例4-18 scanf读入浮点数
1 #include <stdio.h>
2 int main()
3 {
4 float f; // 保存读入的浮点数
5 scanf("%f", &f);
6 printf("%f\n", f);
7 return 0;
8 }
在例4-18中,首先定义了一个浮点数变量d,然后利用scanf从控制台上读入了一个浮点数,最后将浮点数的值打印出来。假设用户的输入是+123.45,程序的运行结果如图4-25所示:
图 4‑25 scanf读入浮点数
这里用户输入的+123.45在输出的时候变成了123.449997。上面的运行结果表明float的精度不足以准确保存123.45的值。想要得到更加精确的结果只能使用double。如果想要用double来保存从scanf读入的浮点数,需要将scanf中的%f改为%lf,具体格式如下:
scanf("%lf", 浮点数地址);
%lf默认对应的数据类型是double,第二个参数中的浮点数地址也必须是double变量的地址。下面的例程展示了如何利用%lf读入一个浮点数保存在double中,如例4-19所示。
例4-19 scanf读入浮点数
1 #include <stdio.h>
2 int main()
3 {
4 double d; // 保存读入的浮点数
5 scanf("%lf", &d);
6 printf("%f\n", d);
7 return 0;
8 }
上面的程序使用double类型的变量来保存读入的浮点数,提高了浮点数的精度。假设用户输入的依然是+123.456,这一次程序的运行结果如图4-26所示。
图 4‑26 scanf读入浮点数
通过图4-25和图4-26的比较,发现使用%1f读入的浮点数精度明显提高了。
scanf同样接受以科学计数法表示的浮点数。当利用scanf读入一个用科学计数法表示的浮点数时,它的语法格式如下所示。
scanf("%e", 浮点数地址);
在上述语法格式中,e表示读入的是一个科学计数法形式的浮点数,并将它保存在第二个参数所对应的浮点数当中。这里%e默认使用的数据类型也是float。下面的例子展示了%e的用法,如例4-20所示。
例4-20 scanf读入科学计数法
1 #include <stdio.h>
2 int main()
3 {
4 float e; // 保存读入的浮点数
5 scanf("%e", &e);
6 printf("%e\n", e);
7 return 0;
8 }
在例4-20中,首先定义了一个浮点数e,随后利用scanf读入一个科学计数法表示的浮点数,最后将e的值打印在控制台上。假设用户的输入是12.3e4,程序最后的运行结果如图4-27所示。
图 4‑27 scanf读入科学计数法
同样的,要想将读入的浮点数保存在double中的话,需要将%e换成%le,其语法格式如下所示:
scanf("%le", 浮点数地址);
需要注意的是,%le默认对应的数据类型是double,因此,第二个参数“浮点数地址”的数据类型也必须是double类型。下面的例程展示了%le的使用效果,如例4-21所示。
例4-21 scanf读入科学计数法
1 #include <stdio.h>
2 int main()
3 {
4 double d; // 保存读入的浮点数
5 scanf("%le", &d);
6 printf("%e\n", d);
7 return 0;
8 }
假设用户输入了12345.6789e10,上述程序的输出结果如图4-28所示。
图 4‑28 scanf读入科学计数法
注意:
在printf中,%e默认对应的数据类型就是double,而在scanf中%e对应的是float,%le对应的才是double。
4.3.5scanf格式控制字符
和printf类似,要想熟练使用scanf函数,也需要充分掌握scanf中经常使用的格式控制字符,它们控制了scanf输入的具体类型。表4-3列举了4.3节中提到的所用常用格式控制字符。
表4-3 常用scanf格式字符
常用格式字符 |
含义 |
%s |
读入一个字符串 |
%c |
读入一个字符 |
%d |
读入一个十进制有符号整型 |
%o |
读入一个八进制整数 |
%x |
读入一个十六进制整数 |
%f |
读入一个float类型浮点数 |
%lf |
读入一个double类型浮点数 |
%e |
读入一个科学计数法表示的float浮点数 |
%le |
读入一个科学计数法表示的double浮点数 |
4.4输入输出实例
scanf和printf的基本使用方法已经全部介绍完毕。本节中将要介绍一些scanf和printf共同配合使用的实例。scanf和printf构成了程序中一对完整的输入输出语句,在两者之间,程序可以对scanf获得的数据进行一定的处理,并使用printf将处理的结果输出到控制台上。
4.4.1大小写转换
下面的这个程序实现了一个很小的功能:从控制台接受用户输入的小写英文字母,并将它转化为大写英文字母输出:
例4-22 大小写转换
#include <stdio.h>
int main()
{
char ch; // 保存用户输入的字符
scanf("%c", &ch);
ch += 'A' - 'a';
printf("%c\n", ch);
return 0;
}
这里来逐行分析上述程序的作用:
第4行:定义了一个字符类型的变量ch,用来保存用户输入的字符;
第5行:从控制台接受用户输入的小写英文字母;
第6行:将小写英文字母转换为大写英文字母。由于在ASCII码中大写英文字母是连续编号的,小写英文字母也是连续编号的,因此任何一对大小写英文字母之间的差是相同的,这就是为什么在第6行中可以直接用大写A和小写a之间的差来将小写英文字母转换为大写英文字母。
第7行:将转换之后的字符打印在控制台上。
假设用户输入的是f,程序运行后的输出结果为:
图 4‑29 大小写转换
需要注意:由于在程序中并没有检查输入的范围,因此如果输入的字符不是小写英文字母的话,程序会输入未知的ASCII码结果。比如当用户输入的是一个阿拉伯数字0的时候:
图 4‑30 大小写转换
要想正确处理不合法的输入,仅仅依靠输入和输出语句是完全不够的。本书随后将要介绍的if判断结构可以用来处理不合法的输入或者其他异常情况,从而帮助程序员写出更加健壮的程序。
4.4.2计算课程得分
某所大学的C语言课程期末考试采用百分制,每个学生的期末考试分数会是一个在0到100(包含)之间的整数。然而这所大学的课程成绩采用的是4分制,即学生在每门课的最终成绩会是一个在0到4之间的浮点数。为此,C语言课程的老师决定按照如下的方式为学生登记课程分数:
课程分数=期末成绩/25
这样刚好可以将范围在0到100之间的期末考试成绩线性地转换到0到4分的课程分数。现在请设计一个程序帮助老师自动完成上述转换工作。
程序输入:一个0到100之间(包含0和100)的整数,表示考生的期末成绩
程序输出:考生的课程得分,用浮点数表示。
分析:
这个程序的结构可以被非常清晰地分解成三个部分:
从控制台读入一个整数;
计算考生的课程分数;
输出考生的课程分数;
按照这个思路程序的整体框架如下:
1 #include <stdio.h>
2 int main()
3 {
4 int score;
5 float gpa;
6 // 从控制台读入一个整数
7 // 计算考生课程分数
8 // 输出考生的课程分数
9 return 0;
10 }
其中,整数类型的score用来保存期末考试成绩,浮点数gpa用来表示考生课程分数。
首先来看第一步:从控制台输入一个整数。根据前面的知识,读入一个整数可以用scanf来完成。score是一个整数变量,所以在这里要使用的格式字符是%d。不要忘了在score前面加上&:
scanf("%d", &score);
接下来计算课程分数。计算公式非常直接:将score除以25即可:
gpa = score / 25;
最后一步输出考生的课程得分:利用printf函数可以向屏幕上输出考生的得分gpa。注意到gpa是一个浮点数, printf中的格式字符选择%f:
printf("%f\n", gpa);
完整的程序如下:
例程 4‑23 计算课程得分
1 #include <stdio.h>
2 int main()
3 {
4 int score;
5 float gpa;
6 // 从控制台读入一个整数
7 scanf("%d", &score);
8 // 计算考生得分
9 gpa = score / 25;
10 // 输出考生的得分
11 printf("%f\n", gpa);
12 return 0;
13 }
开始运行上述程序,假设现在考生的期末考试成绩是90分,按照上述公式,该名考生的课程成绩应该是3.6,然而程序的运行结果如下:
图 4‑31 计算课程得分
输出的考生课程得分是3.0,这意味着程序中存在错误。为了找出错误,可以从后向前一步一步地检查:
首先,printf的用法是正确的:gpa是浮点数,选择%f没有错,这说明此时gpa的值确实是4.5。
再向前看gpa是如何计算出来的:
gpa = score / 25;
由于score是90,而gpa是3,也就是说90/25的计算结果是3:原来错误在于程序在两个整数之间使用了除法,得到的结果被向零取整了。
明白了错误在哪里,程序就很好改了:只需要把score强制转换成浮点数,浮点数除以整数的时候会按照浮点数除法来运算,就可以得到正确的结果了:
例程 4‑24 计算课程得分
1 #include <stdio.h>
2 int main()
3 {
4 int score;
5 float gpa;
6 // 从控制台读入一个整数
7 scanf("%d", &score);
8 // 计算考生得分
9 gpa = (float)score / 25;
10 // 输出考生的得分
11 printf("%f\n", gpa);
12 return 0;
13 }
运行程序,假设这次用户输入依然是90,程序的运行结果如图4-32所示:
图 4‑32 计算课程得分
从图4-32可以看出输入90分之后得到了期望的输出3.6,这一次程序的运行结果正确。
这个例子不仅展示了如何利用scanf和printf完成基本的输入输出操作,还展示了当程序中出现问题时应该如何面对:只要逐步缩小出错的范围,就一定能找到错误并改正它!
4.5本章小结
本章首先介绍了C语言中语句和语句块的用法,随后重点介绍了C语言中的输入函数printf和输出函数scanf的具体用法。printf和scanf是C语言中最基本的语句之一,在今后的学习和实践中具有非常广泛的应用。
- 点赞
- 收藏
- 关注作者
评论(0)