格式化输入输出函数

所谓格式化输入输出,就是不再如同上一节介绍的函数那样,都是单纯地输入输出一个字符或者一行文字。格式化输入输出,就是要将各种类型数据(包括整型、浮点型以及字符串等类型的常量或变量),混合在一起进行输入输出。在C语言中格式化输入函数主要使用scanf(或scanf_s)函数,格式化输出函数主要是printf函数。

格式化输入输出函数,能够对各种类型的数据混合地输入输出,主要是依靠一个格式控制字符串来实现的。在格式控制字符串内通过%符号加字母,对输入输出的目标数据的类型进行预先标明。控制字符串内的%符号后面的字母,我们称之为输入输出控制符。控制字符串内的每一个控制符,在控制字符串后面必须有一个相应类型的常量、变量或表达式。控制串内的控制字符与控制串后面的输入输出目标,在类型与个数上必须是一一对应的,否则在输入输出时就会出现混乱。

scanf函数

scanf函数从标准输入流中,读取用户输入一段或多段文字,并将每段文字转换到各种类型的变量中去。

函数格式:int scanf( const char *format, ... );

scanf函数主要分为控制字符串与列表参数两部分。控制字符串也就是双引号内的部分,只允许放两种文字:控制符与间隔符。控制字符串内多段控制符之间,只能是空格、逗号或者单独指定的某种间隔符。如果在控制串内随意加入一些文字,尤其是想把要打印的文字放入scanf函数的控制字符串内,那将是非常错误的。例如:scanf(“请输入你的工号%d和姓名%d”, &n, &s); 这样的语法不但会被笑掉大牙,而且程序运行的结果也不如所想。

[例3-7] 测试scanf的控制字符串

//scanf的控制字符串内除了控制符外,就只能时间隔符号了。

#include <stdio.h>

int main( )

{

int nNumb;

char sName[20];

//下面这行代码是一个错误的scanf的用法

scanf("请输入你的工号%d和姓名%s", &nNumb, &sName);

printf("你输入的工号是:%d \n", nNumb);

printf("你输入的姓名是:%s \n", sName);

return 0;

}

/* printf("请输入一个员工的工号、姓名【以空格间隔】\n");

scanf("%d %s", &nNumb, &sName);

*/

将以上代码输入到C语言编译器中进行编译、运行并查看打印结果:

a)运行之后观察是否有打印出“请输入……”的提示文字,输入一个工号和姓名后能否打印出输入的内容;

b)最好能在调试模式下单步执行,在监视器内观察scanf函数执行后,两个变量内的数据是否发生了变化;

c)用下方注释内的两行代码,代替语法错误的scanf那一行代码,再重新编译运行并查看结果;

d)最好能在调试模式下单步执行,观察scanf函数执行后两个变量内数据的变化情况。

结论:如果你想要先对用户提示再让其输入数据,你就必须用两行代码来实现。而不能像[例3-7]那样,直接将要输出的文字放在scanf的控制字符串中。

scanf函数的参数列表

在C语言中只有极少数的函数,带有…这样的参数格式,scanf与printf函数就属于这种特殊的函数。

这三个点代表控制字符串之后的参数列表中,参数的个数不受限制。普通函数的参数个数必须是固定的,比如getchar函数的参数个数是0个,putchar函数的个数是1个。如果调用普通函数时,参数的个数或类型不匹配,编译器在编译时都会报错。

值得注意的是:scanf的参数列表内,带入的每个变量都必须用&符号取变量的地址。取变量的地址带入之后,在输入数据之后scanf才将用户输入的数据,能按照每个变量的地址送入到对应的变量中。

[例3-8] 测试scanf的参数列表

//参数列表中的变量忘记了取地址的话,问题很严重。

#include <stdio.h>

int main( )

{

int nNumb=15;

char sName[20];

printf("请输入一个员工的工号、姓名【以空格间隔】:");

scanf("%d %s", nNumb, sName);

printf("你输入的工号:%d \n", nNumb);

printf("你输入的姓名:%s \n", sName);

return 0;

}

将以上代码输入到C语言编译器中进行编译、运行并查看打印结果:

a)运行之后观察打印过程是否正常,输入工号和姓名之后是否会出现程序崩溃,崩溃的提示是什么;

b)修改变量的初始化赋值,例如:int nNumb=2008;再重新编译运行,观察程序崩溃时的提示是什么;

c)在scanf函数中,分别给其中的一个变量加上取地址符号&,再重新编译运行,查看是否会出现程序崩溃;

结论:普通的整型、浮点数等类型的变量,代入到scanf的参数列表时必须取地址。否则,如果不取地址scanf函数会将变量内的数值当做内存地址。以VS编译器为例,当nNumb内的数值是15时,运行时输入数据之后回车的错误提示是:“写入0x0000000F地址时访问冲突”;当nNumb内的数值是2008时,输入数据之后提示是:“写入0x000007D8地址时访问冲突”。

图3-2 scanf参数错误分析

如图3-2所示,当普通变量不取地址直接代入scanf函数,在用户输入数据之后会产生软件崩溃。很显然,scanf函数把变量内存放的数据当做了内存地址,把数据送入了数据错误的内存地址造成崩溃。以上提示界面是来自于win7操作系统,win10操作系统不提示直接退出进程。

只有数组型变量可以不用取地址带入scanf函数,运行时用户输入数据之后程序也正常运行不会出错。原因是数组型变量自身就是一个内存地址,因此在scanf函数中数组型变量前可以不用加取地址符号&。

scanf函数的间隔符

scanf函数的控制串内,除了控制符(%号加一个字母)之外,其余的文字都应该算作是间隔符。例如:两段控制符之间用空格间隔,用户输入数据时就必须用空格间隔;如果两段控制符之间用逗号,用户输入时就必须用逗号间隔;如果两段控制符之间没有间隔符,缺省用户还是要用空格做间隔符。

[例3-9] 测试scanf的间隔符

#include <stdio.h>

int main( )

{

int x=0,y=0;

printf("请输入两个数字【格式是:x=…,y=…】:");

scanf("x=%d,y=%d", &x, &y);

printf(“你输入的是:x=%d,y=%d\n”, x, y);

return 0;

}

将以上代码输入到C语言编译器中进行编译、运行并查看打印结果:

a)运行之后直接输入两个数字以逗号间隔(例如:100,200),观察输入之后打印的结果是否正常;

b)按照提示的格式输入两个数字(例如:x=100,y=200),观察输入值后打印的结果是否正常;

c)最好能在调试模式下单步执行,在监视器内观察scanf函数执行后,两个变量内的数据是否发生了变化。

[例3-10] 继续测试scanf的间隔符

#include <stdio.h>

int main( )

{

int nNumb=15;

char sName[20];

printf("请输入一个员工的工号、姓名【格式是:工号=… 姓名=…】:");

scanf("工号=%d姓名=%s", &nNumb, sName);

//参数列表中的变量忘记了取地址的话,问题很严重。

printf("你输入的工号:%d \n", nNumb);

printf("你输入的姓名:%s \n", sName);

return 0;

}

将以上代码输入到C语言编译器中进行编译、运行并查看打印结果:

a)运行之后直接输入学号和姓名以空格间隔(例如:1008 张珊),观察输入之后打印的结果是否正常;

b)按照提示的格式输入两个数据(例如:工号=1009 姓名=李思思),观察输入值后打印的结果是否正常;

c)最好能在调试模式下单步执行,在监视器内观察scanf函数执行后,两个变量内的数据是否发生了变化。

结论:原来在scanf的控制串内,不止是空格和逗号等才能作为间隔符。控制串内控制符以外其他所有文字,包括控制符前面的文字也都应该算作是间隔符。在用户输入数据时,必须把这些间隔符一起按格式要求输入。否则,用户输入的内容如果缺少这些间隔符,不符合控制串内的格式要求的话,输入的数据都是无效的或不会被接收的。

printf函数

printf函数不但可以输出一行或多行文字,而且还可以混合输出的各种类型的数据(常量或变量)。

函数格式:int printf( const char *format, ... );

图3-3 printf函数解析

一、printf与scanf函数的相同点:

a) printf与scanf函数在格式上相似,也是分为控制字符串与列表参数两部分;

b)参数列表内输入输出目标的个数可以是很多个(没有上限),类型也可以是多种多样的;

c)控制串内的控制符与控制串后的参数列表中的输入输出目标,在个数与类型上必须一一对应的;

二、printf与scanf函数的不同点:

a) scanf函数在参数列表中的每一项,必须是变量而不能是常量,而且必须对每一个变量取地址(数组除外);

b) printf函数在参数列表中的每一项,可以是变量也可以是常量或者其他表达式,而且即使是变量取地址或不取地址都是可以的;

c)printf函数参数列表中的变量,如果取地址打印的就是变量的地址,否则打印的就是变量内的数值。

d)scanf函数的控制串内只能有控制符与间隔符,而printf函数可以将各种文字与控制符混合在一起输出;

e)scanf函数的控制串内的控制符,或者参数列表内的变量个数至少是1个。而printf函数的控制串内的控制符个数,或者参数列表内的目标个数可以是0个,代表简单文字输出;

 [例3-11]测试printf的格式化输出

#include <stdio.h>

int main( )

{

int nNumb;

char sName[20];

float fSalary=0.0f;

printf("请输入一个员工的工号、姓名和工资【以空格间隔】\n");

scanf("%d %s %f", &nNumb, sName, &fSalary);

printf("你输入的工号:%d\t姓名:%s\t工资:%f\n",

nNumb, sName, fSalary);

printf("nNumb的地址是:0x%p\nsName的地址是:0x%p\n fSalary的地址是:0x%p\n",

&nNumb, sName, &fSalary);

return 0;

}

将以上代码输入到C语言编译器中进行编译、运行并查看打印结果:

a)运行之后输入一组数据(例如:1009 李思思 5802.51),观察输入之后打印的结果是否正常;

b)按照提示的格式输入数据,观察输入值后打印的结果是否正常;

c)最好能在调试模式下单步执行,在监视器内观察scanf函数执行后,几个变量内的数据是否发生了变化。

类型控制符

如图3-4所示,在VS2015的帮助的索引中输入“printf function”,打开“type field characters”页面,这里有最全面和权威的格式化输出函数的控制符资料。当然如果你用的不是VS2015编译器,例如在linux或者苹果系统中的编译器,你可以用 “man printf” 命令来找到一些帮助资料。

图3-4 printf函数的格式控制符

VS2015的说明资料的英文说明的实在太完美了。第一句话就是说:“在格式化指定过程中,类型控制符是一个转换方式的标示符,(它们指定)每一个对应的参数将被作为一个字符、字符串、指针、整数或者浮点数来翻译”。In a format specification, the type character is a conversion specifier that specifies whether the corresponding argument is to be interpreted as a character, a string, a pointer, an integer, or a floating-point number.

融入英文语境之后,我们才能体验到西方人对技术资料的表达是多么的优美与贴切。最后一段英文是说,整数常用控制符包括d、I、o、u、x和X,浮点数常用控制符包括a、A、e、E、f、g和G。对于64位数据的输入输出,在windows下采用“I64”作为控制符,在linux或苹果系统中采用“ll”作为控制符。

表3-1  最常用的C语言控制符:

格式

printf函数

scanf函数

单字符

%c

%c

字符串

%s

%s

有符号的十进制整数

%d

%d

单精度浮点数 (十进制记数法)

%f

%f

双精度浮点数 (十进制记数法)

%lf

%lf

无符号的十进制整数

%u

%u

无符号的十六进制整数(使用“ABCDEF”)

%x

%x

无符号的八进制整数

%o

%o

变量地址

%p

printf函数的占位控制

如图3-5所示,在VS2015的帮助的索引中输入“printf function”,打开“width Specification”页面。第一句话是说:“在格式设定中,第二种可选字段是宽度设置。宽度参数是非负数的十进制整数,用来控制最小的输出字符数量”。In a format specification, the second optional field is the width specification. The width argument is a non-negative decimal integer that controls the minimum number of characters that are output.

图3-5 printf函数的占位控制

printf函数打印时的占位控制方式,包括:整数占位控制、浮点数占位控制以及字符串占位控制等。

一、浮点数占位控制方式分为以下几种情况:

a)%f(或%lf):不指定宽度,整数部分全部输出并输出6位小数。例如:

printf("%f", 34.67852f);

printf("%l", 254.0 / 3);

b)%m.nf:输出共占m列,其中有n位小数,如数值宽度小于m左端补空格。例如:

printf("%8.3f", 34.67852f);

printf("%0.2lf", 254.0 / 3); //当m为0时,则不申请占位,按整数与小数自然需求占用。

c)%-m.nf:输出共占n列,其中有n位小数,如数值宽度小于m右端补空格。例如:

printf("%-8.3f",34.678f);

二、整数和字符串输出相同,只有占位控制和对齐控制没有小树位控制:

a)%md或%-md:-符号代表左对齐,缺省不带-符号是右对齐。例如: printf("%-8d%10s\n",1005, "张珊"); // 8和10代表的是占位管理

printf("%-8d%10s\n",1006, "李思思"); // 8和10代表的是占位管理

b)右对齐时缺省占位符是空格,如果在%符号后加一个0则以0占位。例如:

printf("%08d%-10s\n",1006, "李思思"); // 8和10代表的是占位管理

占位控制在后期项目开发中,常用与数据集合的列表打印,让各种不同长度的数据在列表中对齐。另外,在打印一个内存地址时,占位控制也很好用。例如:

int i = 88;

printf("i变量的内存地址是:0x%08x\n",&i);

scanf 与 printf 输入输出函数相关推荐

  1. C语言(输入输出函数getchar,putchar、gets、puts,scanf,printf的功能以及用法)

    常用的输入输出函数 getchar gets scanf putchar puts printf getchar int getchar( void ); 返回值为int,所以需要用一个int变量来接 ...

  2. C语言scanf()函数格式化输入和printf()格式化输出。

    scanf函数格式化输入和printf格式化输出 要实现的功能如下 完整源代码实现如下 要实现的功能如下 scanf函数格式化输入字符串和字符,printf格式化输出字符串和字符. 完整源代码实现如下 ...

  3. c语言printf函数中的格式控制字符串,C++_C语言格式化输入输出函数详解,一:格式输出函数printf() 1 - phpStudy...

    C语言格式化输入输出函数详解 一:格式输出函数printf() 1.调用形式一般为:printf("格式化控制字符串",输出表列): 2.格式化控制字符串用于指定输出格式,它有三种 ...

  4. c语言中的输入输出函数之scanf函数

    目录 前言 scanf函数 定义 scanf函数一般形式 地址表列 格式字符串 * 域宽 长度修饰符 格式字符串中存在普通字符 scanf和scanf_s的区别以及vs解决scanf报错的另一种方法 ...

  5. c语言如何持续输入字符直到指定字符结束_《小白学C》第三章 常用输入输出函数...

    第三章 常用输入/输出函数 与其他高级语言一样, C语言的语句是用来向计算机系统发出操作指令的. 当我们提到输入时,这意味着要向程序填充一些数据.输入可以是以文件的形式或从命令行中进行.C 语言提供了 ...

  6. C语言中的输入输出函数

    ----------------------------- //键盘缓存区(按enter送入)==>输入缓存区 ==>scanf ----------------------------- ...

  7. C/C++输入输出函数(I/O)总结

    在c语言的学习使用过程中,除了格式化输入输出外,还有很多输入输出函数,包括字符串输入输出.文件输入输出等.在使用的过程中一直没有认真总结过,在这里把以前学的好好总结一下,以便时间长了又忘记了. 字符串 ...

  8. 屏幕输出语句_第三章 常用输入/输出函数

    第三章 常用输入/输出函数 与其他高级语言一样, C语言的语句是用来向计算机系统发出操作指令的. 当我们提到输入时,这意味着要向程序填充一些数据.输入可以是以文件的形式或从命令行中进行.C 语言提供了 ...

  9. C语言scanf:获取输入的内容

    获取外部输入数据内容 在C语言中,有多个函数可以从键盘获得用户输入: scanf():和 printf() 类似,scanf() 可以输入多种类型的数据.getchar().getche().getc ...

最新文章

  1. java锁屏_JAVA设置桌面不锁屏设置
  2. python快速编程入门黑马-500G 史上最全的JAVA全套教学视频网盘分享
  3. qsort归纳学习(c语言版本)
  4. apache配置,保你配置成功
  5. 【机器视觉】 throw算子
  6. 转行,转向哪里?电子工程师!!!
  7. python装饰器执行顺序
  8. python学习-38迭代器和生成器
  9. Oracle中insert into select和select into的区别
  10. Hibernate面试问题与解答
  11. C#开发笔记之20-如何用C#深克隆一个对象(优雅方案)?
  12. Hadoop生态圈-zookeeper本地搭建以及常用命令介绍
  13. Spring框架----AOP的概念及术语
  14. linux 自动启动设置
  15. python起简易http server
  16. spring学习--AOP-面向切面编程(一)
  17. Tcl Tutorial 笔记6 ·while
  18. 阿里规定代码中禁用这个,为何?
  19. 【三维路径规划】基于matlab RRT算法无人机三维路径规划【含Matlab源码 155期】
  20. Nodejs 中文分词

热门文章

  1. 安卓应用设置第一个显示的界面
  2. 超级内存NVDIMM--要和内存说再见?Intel将推存储界新物种NVDIMM内存
  3. IT(计算机/软件/互联网)专业词汇宝典
  4. 西安理工大学计算机考研数据结构863整理总结
  5. Python怎样提高视频清晰度和对比度?通过这篇直接学会。
  6. 【Mysql】Mysql数据库查询“表空间”
  7. 《视搭》开源视频创作工具,保姆级搭建教程,短视频创作利器
  8. VPX高速信号处理板设计资料第240篇:4C6678_K7_DDR3_VPX高速信号处理板
  9. 【电商】管理后台之账号管理
  10. 假期第一天,第一次见丈母娘~