LINUX-C成长之路(三):基本IO函数操作
2013-06-01 14:31
246 查看
在学习C语言的时候,基本的输入输出是非常重要的,因为我们时常要接收用户的输入,而且时常要将结果输出到屏幕,因此非常有必要注重地学习一下。
最常用的两个基本IO函数莫过于 printf() 和 scanf() 了,下面首先来详细地介绍一下它们。来看第一个示例代码:
[cpp] view
plaincopy
//example1.c
#include <stdio.h>
int main(void)
{
char a1 = 'A';
int a2 = 100;
float a3 = 3.14;
printf("a1=%c, a2=%d, a3=%f\n", a1, a2, a3);
short int a4 = 10;
long int a5 = 20;
long long int a6 = 30;
printf("a4=%hd, a5=%ld, a6=%lld\n", a4, a5, a6);
}
在上面的代码中,第8行和第13行就是将各种不同的数据类型打印出来,这里,%c %d %f %hd %ld %lld 这些称之为 格式控制符,其实,printf 和 scanf 函数之所以称为格式化IO函数,就是因为它们可以根据不同的格式控制符来处理各种类型的数据。
简单地讲,%d 用来表示 十进制 有符号 整型。%c 表示 字符。%f 表示浮点型数据。具体的所有的格式控制符的详细解释,请看下面的代码:
Note: 输出结果及格式是 char = 1,%c, short = 2, %hd, int = 4, %d, long = 4, %ld, long long = 8, %lld, float = 4, %f, double = 8, %lf, long double = 12, %Lf. 还有, char 类型的输出格式是%hhd, %c, h 代表half , 而以%hhd 为格式来做输入的时候, 输入1,则输出1, 输入a, 输出97,这个得特别注意。
下面,研究一下一个很重要的问题:对于 scanf() 而言,假如你要用户输入一个整数,或者输入一个浮点数,但是用户很调皮,偏不输入一个规规矩矩的你想要的数据,你的程序会如何呢? 是立即就罢工甚至爆炸呢? 还是有足够的智能来处理这些小顽皮的捣蛋呢?请看下面的例子:
[cpp] view
plaincopy
//example4.c
#include <stdio.h>
int main(void)
{
printf("请输入一个0-127之间的整数\n");
char c;
scanf("%hhd", &c);
printf("这个数对应的字符是: %c\n", c);
return 0;
}
在example4.c 中,如果用户规规矩矩地输入你所要求的 0-127之间的 ASCII码值,程序当然可以顺利运行,打印出其对应的字符,但问题是假如用户输入诸如:
abcd 或者 80.5 或者 80abcd 或者 abcd80 , 但example4.c 遇到这样的输入的时候,它是无能为力的。因为它没有任何的输入确认的判断。
首先我们要知道一个事情,就是scanf() 这个函数的返回值,事实上,scanf() 这个函数的返回值代表了其正确地得到了用户输入的数据的个数,举个例子就明白了,就如有这个一段代码:
[cpp] view
plaincopy
int a, b, c;
int n;
n = scanf("%d%d%d", &a, &b, &c);
那么用户的输入分别是:
1,依次输入 100 200 300
2,依次输入 100 abc 300
3,依次输入 abc 200 300
n 的结果,则分别是 3, 1, 0. 当用户是第一种情况的时候,100,200和300都正确地被赋值到了a,b和c3个变量中。因此scanf正确得到了 3 个值,所以返回3. 第二种情况,scanf 只能正确地得到 100 这个数据并将其赋值给 a,但是后面的 abc 不是一个整数,因此被 scanf 拒绝,且 scanf 此时立即返回 1,代表正确得到了1 个值。在第三种情况下,用户一来就输入了 abc,scanf() 函数发现状况不妙,后面的 200,300 都不被理睬,返回了一个 0 ,代表啥也没得到,啥也没赋值。
关键是:那些没有被正确匹配并且赋值的输入,到哪儿去了? 比如第二种情况下的 abc 和 300, 第三种情况下的 200 和300,它们会自动消失吗? 答案是否定的。事实上,这些用户输入的数据并非直接了当地传递给了程序中的变量,而是先由标准IO库函数“暂管”起来,将它们放在一个缓冲区中,然后,scanf() 函数从这个缓冲区中逐个地拿取数据,当数据的类型匹配时,就继续拿取,当数据的类型不匹配时,则立即停止拿取数据,并返回已经拿取的数据个数。
因此上面的第一种情况是:将100,200和300都拿取过来,分别赋值给a,b和c,然后返回一个3,代表 scanf() 从缓冲区中正确拿取了3个数据。
第二种情况是:将 100 拿取过来,赋值给a,然后碰到 abc 不符合要求,因此立即停止拿取数据,并返回 1, 代表拿了一个数据。注意,此时 abc 和 300 并未消失,而是残留在缓冲区中。
第三种情况是:一开始就遇到 abc,不符合格式要求,因此 sacnf() 立即返回一个 0 ,代表啥也没拿到。同理,此时用户输入的 abc,200 和 300 并未消失,也残留在缓冲区中。
知道了这个道理,我们在要求用户再次输入数据的时候,就要注意了,因为上次格式不匹配的数据会残留在缓冲区中,请看下面的错误的代码:
[cpp] view
plaincopy
//example5.c
int main(void)
{
printf("请输入一个整数\n");
int n, ret;
while(1)
{
ret = scanf("%d", &n);
if(ret != 1)
printf("格式不对,请再输一遍!\n");
else
break;
}
printf("你输入的数是: %d \n", n);
}
这个代码,原意是想让用户输入一个整数,然后将其输出,如果输入的不是整数,就要求用户再输入一遍。可惜这是一段错误的代码,因为假如用户输入了一个 字母 a,这个 字母将会残留在缓冲区中,影响用户的下一次输入,也就是说,不管用户再次输入什么,scanf() 函数永远会先读到那个 a,因此就变成死循环了。正确的代码如下:
[cpp] view
plaincopy
//example5.c
int main(void)
{
printf("请输入一个整数\n");
int n, ret;
while(1)
{
ret = scanf("%d", &n);
if(ret != 1)
{
while(getchar() != '\n'); // 用 getchar() 清空非法字符
printf("格式不对,请再输一遍!\n");
}
else
break;
}
printf("你输入的数是: %d \n", n);
}
其中,我们增加了第 15 行,这是一个空循环,循环条件是 getchar() != '\n' ,这句话的意思是,用getchar() 这个函数去缓冲区拿取数据,每次拿去一个字符,只要不是回车符 '\n' ,就继续循环,直到拿到回车符为止。 为什么是回车符呢? 因为用户再输入的时候,最后一定是按了一下回车键来结束输入的(本质原因是标准输入流是行缓冲类型的),因此在缓冲区中的数据一定是以
回车符 '\n' 作为结尾的,当我们用 getchar() 获取到回车符时,就表示缓冲区就被我们清空了!
Note: 用scanf 输入数据后, 如果没有取出来, 或是多输入了, 则下次取的时候,会把刚才的缓存中的数据读出来, 而读错了过后 ,数据会留在缓存。造成下次读其他的数据时报错。 用 while((ch = getchar()) != '\n')过滤掉缓存中不需要的数据。 还有 '=' 的级别比 ‘!=’ 级别高, 所以需要用括号先括起来。
最常用的两个基本IO函数莫过于 printf() 和 scanf() 了,下面首先来详细地介绍一下它们。来看第一个示例代码:
[cpp] view
plaincopy
//example1.c
#include <stdio.h>
int main(void)
{
char a1 = 'A';
int a2 = 100;
float a3 = 3.14;
printf("a1=%c, a2=%d, a3=%f\n", a1, a2, a3);
short int a4 = 10;
long int a5 = 20;
long long int a6 = 30;
printf("a4=%hd, a5=%ld, a6=%lld\n", a4, a5, a6);
}
在上面的代码中,第8行和第13行就是将各种不同的数据类型打印出来,这里,%c %d %f %hd %ld %lld 这些称之为 格式控制符,其实,printf 和 scanf 函数之所以称为格式化IO函数,就是因为它们可以根据不同的格式控制符来处理各种类型的数据。
简单地讲,%d 用来表示 十进制 有符号 整型。%c 表示 字符。%f 表示浮点型数据。具体的所有的格式控制符的详细解释,请看下面的代码:
//example2.c #include <stdio.h> int main(void) { char a1 = 'A'; printf("char a1 = %c, %d\n", a1, sizeof(a1)); // c就是character字符的意思 short a2 = 10; printf("short a2 = %hd, %d \n", a2, sizeof(a2)); // h就是half一半的意思,表示a2是“半个”整型 int a3 = 100; printf("int a3 = %d, %d\n", a3, sizeof(a3)); // d就是decimal十进制的意思 long a4 = 100; printf("long a4 = %ld, %d\n", a4, sizeof(a4)); // l就是long的意思,表示a4是一个长整型 long long a5 = 100; printf("long long a5 = %lld, %d \n", a5, sizeof(a5)); // ll就是long long的意思,表示a4是一个长长整型 float f1 = 1.0; printf("float f1 = %f, %d\n", f1, sizeof(f1)); // f就是float的意思,表示f1是一个单精度浮点型 double f2 = 1.0; printf("double f2 = %lf, %d\n", f2, sizeof(f2)); long double f3 = 1.0; printf("long double f3 = %Lf, %d\n", f3, sizeof(f3)); // 注意下,长双精度不是 %llf ,而是 %Lf char ch; scanf("%c", &ch); printf("ch = %c \n", ch); scanf("%hhd", &ch); printf("ch = %hhd \n", ch); return 0; }
Note: 输出结果及格式是 char = 1,%c, short = 2, %hd, int = 4, %d, long = 4, %ld, long long = 8, %lld, float = 4, %f, double = 8, %lf, long double = 12, %Lf. 还有, char 类型的输出格式是%hhd, %c, h 代表half , 而以%hhd 为格式来做输入的时候, 输入1,则输出1, 输入a, 输出97,这个得特别注意。
下面,研究一下一个很重要的问题:对于 scanf() 而言,假如你要用户输入一个整数,或者输入一个浮点数,但是用户很调皮,偏不输入一个规规矩矩的你想要的数据,你的程序会如何呢? 是立即就罢工甚至爆炸呢? 还是有足够的智能来处理这些小顽皮的捣蛋呢?请看下面的例子:
[cpp] view
plaincopy
//example4.c
#include <stdio.h>
int main(void)
{
printf("请输入一个0-127之间的整数\n");
char c;
scanf("%hhd", &c);
printf("这个数对应的字符是: %c\n", c);
return 0;
}
在example4.c 中,如果用户规规矩矩地输入你所要求的 0-127之间的 ASCII码值,程序当然可以顺利运行,打印出其对应的字符,但问题是假如用户输入诸如:
abcd 或者 80.5 或者 80abcd 或者 abcd80 , 但example4.c 遇到这样的输入的时候,它是无能为力的。因为它没有任何的输入确认的判断。
首先我们要知道一个事情,就是scanf() 这个函数的返回值,事实上,scanf() 这个函数的返回值代表了其正确地得到了用户输入的数据的个数,举个例子就明白了,就如有这个一段代码:
[cpp] view
plaincopy
int a, b, c;
int n;
n = scanf("%d%d%d", &a, &b, &c);
那么用户的输入分别是:
1,依次输入 100 200 300
2,依次输入 100 abc 300
3,依次输入 abc 200 300
n 的结果,则分别是 3, 1, 0. 当用户是第一种情况的时候,100,200和300都正确地被赋值到了a,b和c3个变量中。因此scanf正确得到了 3 个值,所以返回3. 第二种情况,scanf 只能正确地得到 100 这个数据并将其赋值给 a,但是后面的 abc 不是一个整数,因此被 scanf 拒绝,且 scanf 此时立即返回 1,代表正确得到了1 个值。在第三种情况下,用户一来就输入了 abc,scanf() 函数发现状况不妙,后面的 200,300 都不被理睬,返回了一个 0 ,代表啥也没得到,啥也没赋值。
关键是:那些没有被正确匹配并且赋值的输入,到哪儿去了? 比如第二种情况下的 abc 和 300, 第三种情况下的 200 和300,它们会自动消失吗? 答案是否定的。事实上,这些用户输入的数据并非直接了当地传递给了程序中的变量,而是先由标准IO库函数“暂管”起来,将它们放在一个缓冲区中,然后,scanf() 函数从这个缓冲区中逐个地拿取数据,当数据的类型匹配时,就继续拿取,当数据的类型不匹配时,则立即停止拿取数据,并返回已经拿取的数据个数。
因此上面的第一种情况是:将100,200和300都拿取过来,分别赋值给a,b和c,然后返回一个3,代表 scanf() 从缓冲区中正确拿取了3个数据。
第二种情况是:将 100 拿取过来,赋值给a,然后碰到 abc 不符合要求,因此立即停止拿取数据,并返回 1, 代表拿了一个数据。注意,此时 abc 和 300 并未消失,而是残留在缓冲区中。
第三种情况是:一开始就遇到 abc,不符合格式要求,因此 sacnf() 立即返回一个 0 ,代表啥也没拿到。同理,此时用户输入的 abc,200 和 300 并未消失,也残留在缓冲区中。
知道了这个道理,我们在要求用户再次输入数据的时候,就要注意了,因为上次格式不匹配的数据会残留在缓冲区中,请看下面的错误的代码:
[cpp] view
plaincopy
//example5.c
int main(void)
{
printf("请输入一个整数\n");
int n, ret;
while(1)
{
ret = scanf("%d", &n);
if(ret != 1)
printf("格式不对,请再输一遍!\n");
else
break;
}
printf("你输入的数是: %d \n", n);
}
这个代码,原意是想让用户输入一个整数,然后将其输出,如果输入的不是整数,就要求用户再输入一遍。可惜这是一段错误的代码,因为假如用户输入了一个 字母 a,这个 字母将会残留在缓冲区中,影响用户的下一次输入,也就是说,不管用户再次输入什么,scanf() 函数永远会先读到那个 a,因此就变成死循环了。正确的代码如下:
[cpp] view
plaincopy
//example5.c
int main(void)
{
printf("请输入一个整数\n");
int n, ret;
while(1)
{
ret = scanf("%d", &n);
if(ret != 1)
{
while(getchar() != '\n'); // 用 getchar() 清空非法字符
printf("格式不对,请再输一遍!\n");
}
else
break;
}
printf("你输入的数是: %d \n", n);
}
其中,我们增加了第 15 行,这是一个空循环,循环条件是 getchar() != '\n' ,这句话的意思是,用getchar() 这个函数去缓冲区拿取数据,每次拿去一个字符,只要不是回车符 '\n' ,就继续循环,直到拿到回车符为止。 为什么是回车符呢? 因为用户再输入的时候,最后一定是按了一下回车键来结束输入的(本质原因是标准输入流是行缓冲类型的),因此在缓冲区中的数据一定是以
回车符 '\n' 作为结尾的,当我们用 getchar() 获取到回车符时,就表示缓冲区就被我们清空了!
Note: 用scanf 输入数据后, 如果没有取出来, 或是多输入了, 则下次取的时候,会把刚才的缓存中的数据读出来, 而读错了过后 ,数据会留在缓存。造成下次读其他的数据时报错。 用 while((ch = getchar()) != '\n')过滤掉缓存中不需要的数据。 还有 '=' 的级别比 ‘!=’ 级别高, 所以需要用括号先括起来。
相关文章推荐
- Linux-C成长之路(三):Linux C编程实战之路 基本IO函数操作
- LINUX-C成长之路(三):基本IO函数操作
- Linux C——带IO缓冲的文件操作函数
- [Linux]--标准文件 IO 基本操作
- 七、Linux系统编程-文件和IO(五)fcntl函数及常用操作、文件锁
- Linux成长之路(一)——基本概念及操作、用户及文件权限管理
- linux下C通过系统调用进行基本IO操作
- linux不带缓冲的文件操作基本函数及用法示例
- Linux下文件操作的基本函数及分析
- linux 基本io操作
- Linux成长之路(二)——Linux目录结构和对文件的基本操作
- Linux 标准IO操作函数fopen fclose fread fwrite fgetc fputc fgets fputs
- Linux 软件系列之五——不带缓存的IO操作
- linux下的基本命令操作
- IO-File 文件 目录 基本操作 递归 遍历
- Linux基本操作系列(一):在CentOS 6.8安装JDK(Java环境)
- Linux基本操作系列(二):在CentOS 6.8系统上安装Tomcat并配置自动启动
- Linux学习记录--文件IO操作相关系统编程
- Linux基本命令行操作
- LINUX最常用的基本操作命令