scanf()函数

函数名: scanf 功  能: 执行格式化输入 用  法: int scanf(char *format[,argument,...]); scanf("格式控制字符串",输入参数一,输入参数二)

格式控制字符串表示输入的格式:(int型用%d,float用%f,double型用%lf)

%d 十进制有符号整数  %u 十进制无符号整数  %f 浮点数  %s 字符串  %c 单个字符  %p 指针的值  %e 指数形式的浮点数  %x, %X 无符号以十六进制表示的整数  %0 无符号以八进制表示的整数  %g 自动选择合适的表示法

输入参数是指向变量的地址,所以要在变量前面加&

1.scanf函数的基本用法

scanf函数是一个阻塞式的函数,这个函数一个标准的输入函数,也就是说这个函数会等待标准输入设备(比如键盘)输入数据,并且会将输入的数据赋值给地址对应的变量

//

//  main.c

//  scanfMethod

//

//  Created by Mac on 14-2-20.

//  Copyright (c) 2014年 itcast. All rights reserved.

//

#include <stdio.h>

int main(int argc, const char * argv[])

{

    // insert code here...

    printf("请输入一个整数:");

    int a;

    //这里要使用&这个符号,这个符号表示引用变量a的地址,这个函数的意思就是当我输入一个整数的时候,会讲这个整数赋给变量a这个变量的地址

    scanf("%d",&a);

    printf("%d*%d=%d\n1",a,a,a*a);

    return 0;

}

2.scanf函数接收多个值的用法

当scanf函数接收多个值的时候,我们可以通过符号(不包括%)将多个输入值分割开来,但是值得注意的是当分割符号式空格的时候,我们可以用空格或者tab键或者回车键来讲输入的值分开

 1 //
 2
 3 //  main.c
 4
 5 //  scanfMethod
 6
 7 //
 8
 9 //  Created by Mac on 14-2-20.
10
11 //  Copyright (c) 2014年 itcast. All rights reserved.
12
13 //
14
15
16
17 #include <stdio.h>
18
19
20
21 int main(int argc, const char * argv[])
22
23 {
24
25
26
27     // insert code here...
28
29     printf("请输入三个整数:");
30
31     int a,b,c;
32
33     //注意如果分割符号式空格则我们在输入数据的时候可以通过空格或者tab键或者回车键来代替空格
34
35     scanf("%d*%d*%d",&a,&b,&c);
36
37     printf("%d*%d*%d=%d\n1",a,b,c,a*b*c);
38
39     return 0;
40
41 }

注意事项:

(1) 对于字符串数组或字符串指针变量,由于数组名和指针变量名本身就是地址,因此使用scanf()函数时,不需要在它们前面加上"&"操作符。

(2) 可以在格式化字符串中的"%"各格式化规定符之间加入一个整数,表示任何读操作中的最大位数。

(3) scanf()函数中没有精度控制。

如: scanf("%5.2f",&a); 是非法的。不能企图用此语句输入小数为2位的实数。

(4) scanf中要求给出变量地址,如给出变量名则会出错

如 scanf("%d",a);是非法的,应改为scanf("%d",&a);才是合法的。

(5) 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔。

C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。

(6) 在输入字符数据(%c)时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。

例如:


1

scanf("%c%c%c",&a,&b,&c);

输入为:


1

def

则把‘d‘赋予a, ‘ (空格)‘赋予b,‘e‘赋予c。因为%c 只要求读入一个字符,后面不需要用空格作为两个字符的间隔,因此把‘ ‘作为下一个字符送给b。

只有当输入为:def 时,才能把‘d‘赋于a,‘e‘赋予b,‘f‘赋予c。 如果在格式控制中加入空格作为间隔,


1

scanf("%c%c%c",&a,&b,&c);

则输入时各数据之间可加空格。

我们用一些例子来说明一些规则:


1

2

3

4

5

6

7

8

9

#include<stdio.h>

intmain(void)

{

chara,b;

printf("inputcharactera,b\n");

scanf("%c%c",&a,&b);/*注意两个%c之间没有任何符号*/

printf("%c%c\n",a,b);

return0;

}

由于scanf函数"%c%c"中没有空格,输入M N,结果输出只有M。而输入改为MN时则可输出MN两字符,见下面的输入运行情况: input character a,b

输入:


1

屏幕显示:


1

1

2

3

4

5

6

7

8

9

#include<stdio.h>

intmain(void)

{

chara,b;

printf("inputcharactera,b\n");

scanf("%c%c",&a,&b);/*注意两个%c之间有个空格*/

printf("\n%c%c\n",a,b);

return0;

}

本例表示scanf格式控制串"%c %c"之间有空格时, 输入的数据之间可以有空格间隔。

(7) 如果格式控制串中有非格式字符则输入时也要输入该非格式字符。

例如:


1

scanf("%d,%d,%d",&a,&b,&c);

其中用非格式符“ , ”作间隔符,故输入时应为:


1

5,6,7

又如:


1

scanf("a=%d,b=%d,c=%d",&a,&b,&c);

则输入应为


1

a=5,b=6,c=7

如输入的数据与输出的类型不一致时,虽然编译能够通过,但结果将不正确。


1

2

3

4

5

6

7

8

9

#include<stdio.h>

intmain(void)

{

inta;

printf("inputanumber");

scanf("%d",&a);

printf("%ld",a);

return0;

}

由于输入数据类型整型, 而输出语句的格式串中说明为长整型,因此输出结果和输入数据不符。输出并不是输入的值。

如将scanf("%d",&a); 语句改为 scanf("%ld",&a);

输入数据为长整型,输入输出数据才相等。

问题一

如何让scanf()函数正确接受有空格的字符串?如: I love you!


1

2

3

4

5

6

7

8

#include<stdio.h>

intmain(void)

{

charstr[80];

scanf("%s",str);

printf("%s",str);

return0;

}

输入:


1

Iloveyou!

上述程序并不能达到预期目的,scanf()扫描到"I"后面的空格就认为对str的赋值结束,并忽略后面的"love you!".这里要注意是"love you!"还在键盘缓冲区(关于这个问题,网上我所见的说法都是如此,但是,我经过调试发现,其实这时缓冲区字符串首尾指针已经相等了,也就是说缓冲区清空了,scanf()函数应该只是扫描stdin流,这个残存信息是在stdin中)。我们改动一下上面的程序来验证一下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include<stdio.h>

#include<windows.h>

intmain(void)

{

charstr[80],str1[80],str2[80];

scanf("%s",str);/*此处输入:Iloveyou!*/

printf("%s\n",str);

Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*/

/*

不是sleep(5)

1,函数名是Sleep不是sleep。

2,C/C++中,unsignedSleep(unsigned)应该是毫秒ms.

*/

scanf("%s",str1);/*这两句无需你再输入,是对stdin流再扫描*/

scanf("%s",str2);/*这两句无需你再输入,是对stdin流再扫描*/

printf("%s\n",str1);

printf("%s\n",str2);

return0;

}

输入:


1

Iloveyou!

输出:


1

2

3

I

love

you!

好了,原因知道了,所以结论是:残留的信息 love you是存在于stdin流中,而不是在键盘缓冲区中。那么scanf()函数能不能完成这个任务?回答是:能!别忘了scanf()函数还有一个 %[] 格式控制符(如果对%[]不了解的请查看本文的上篇),请看下面的程序:


1

2

3

4

5

6

7

8

#include<stdio.h>

intmain(void)

{

charstr[50];

scanf("%49[^\n]",str);/*scanf("%s",string);不能接收空格符*/

printf("%s\n",str);

return0;

}

问题二

键盘缓冲区残余信息问题


1

2

3

4

5

6

7

8

9

10

11

12

13

#include<stdio.h>

intmain(void)

{

inta;

charc;

while(c!=‘N‘)

{

scanf("%d",&a);

scanf("%c",&c);

printf("a=%dc=%c\n",a,c);/*printf("c=%d\n",c);*/

}

return0;

}

scanf("%c", &c);这句不能正常接收字符,什么原因呢?我们用printf("c = %d\n", c);将C用int表示出来,启用printf("c = %d\n", c);这一句,看看scanf()函数赋给C到底是什么,结果是c=10 ,ASCII值为10是什么?换行即\n.对了,我们每击打一下"Enter"键,向键盘缓冲区发去一个“回车”(\r),一个“换行"(\n),在这里\r被scanf()函数处理掉了(姑且这么认为吧^_^),而\n被scanf()函数“错误”地赋给了c.解决办法:可以在两个scanf()函数之后加getch(), getchar(),但是要视具体scanf()语句加那个,这里就不分析了,读者自己去摸索吧。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include<stdio.h>

intmain(void)

{

inta;

charc;

while(c!=‘N‘)

{

scanf("%d",&a);

fflush(stdin);

scanf("%c",&c);

fflush(stdin);

printf("a=%dc=%c\n",a,c);

}

return0;

}

这里再给一个用“空格符”来处理缓冲区残余信息的示例:

版本1:运行出错的程序


1

2

3

4

5

6

7

8

9

10

#include<stdio.h>

intmain(void)

{

inti;

charj;

for(i=0;i<10;++i)

scanf("%c",&j);/*这里%前没有空格*/

printf("%c",j);/*在输入十个字符之后*/

return0;

}

版本2:使用了空格控制符后


1

2

3

4

5

6

7

8

9

10

#include<stdio.h>

intmain(void)

{

inti;

charj;

for(i=0;i<10;++i)

scanf("%c",&j);/*注意这里%前有个空格*/

printf("%c",j);/*在输入十个字符之后,验证打印出来的字符是否是自己输入的最后一个字符(即输入的第十个字符)*/

return0;

}

接着,我们运行看看,首先,运行第一个版本(错误的程序)

我们输入:

0 1 2 3 4 5 6 7 8 9

结果是一个空字符

再运行第二个版本(正确的程序)

同样输入:

0 1 2 3 4 5 6 7 8 9

这一次就显示字符9,故此程序正确。

那么为什么第二个程序就正确呢,原因何在,在%前面加一个空格就这么有用,答案是肯定的,就是%前面的空格在起作用,读者看看此文章的前面部分,在scanf的使用过程中应注意的问题中已经指出:“scanf()的格式控制串可以使用空白字符或其它非空白字符,使用空白字符会使scanf()函数在读操作中略去输入中的零个或多个空白字符。”

所以在%前面加上了空格(空格属于空白字符,此外还有像制表符等也属于空白字符),在输入过程中,将略去输入中的一个或多个空白字符,所以我们输入的0 1 2 3 4 5 6 7 8 9这些字符中的空白字符就被略去了,字符9也就正确的打印出来了,这样子解释,相信大家都看明白勒吧!

问题三

输入类型与格式化字符串不匹配导致stdin流的阻塞。


1

2

3

4

5

6

7

8

9

10

#include<stdio.h>

intmain(void)

{

inta=0,b=0,c=0,ret=0;

ret=scanf("%d%d%d",&a,&b,&c);

printf("第一次读入数量:%d\n",ret);

ret=scanf("%d%d%d",&a,&b,&c);

printf("第二次读入数量:%d\n",ret);

return0;

}

我们定义了a,b,c三个变量来接受输入的内容,定义了变量ret来接收scanf函数的返回值。

正确输入的话:

但是当输入内容与格式换字符串不匹配时,结果会令人大跌眼镜(仔细分析会对scanf函数和stdin流有更深入的哦):

执行到第一个scanf时,当输入字符’b’的时候与ret=scanf("%d%d%d",&a,& amp;b,&c);中的格式化字符串不匹配,stdin流被阻塞,scanf函数不在读取后面的部分,直接将1返回,表示只将stdin流中的 1读入到了变量a中。

执行到第二个scanf时,字符’b’还是与格式化字符串不匹配,stdin流仍然被阻塞,所以没有提示输入,scanf函数将0返回。

将代码作如下修改,可以有力的证明上述结论。


1

2

3

4

5

6

7

8

9

10

#include<stdio.h>

intmain(void)

{

inta=0,b=0,c=0,ret=0;

ret=scanf("%d%d%d",&a,&b,&c);

printf("第一次读入数量:%d\n",ret);

ret=scanf("%c%d%d",&a,&b,&c);

printf("第二次读入数量:%d\n",ret);

return0;

}

当把第二个scanf函数内的格式化字符串改为”%c%d%d”时,运行结果如下:

执行到第一个scanf函数时,由于输入’b’的原因scanf函数直接返回1,stdin流阻塞。

执行到第二个scanf函数时,字符’d’与格式化字符串”%c%d%d”中的%c匹配,stdin流终于疏通,在输入6,则将变量a,b,c分别赋值为98(‘b’的ASCII码)、2、6,scanf函数返回3。

有上述问题可知,当使用scanf函数时,如果遇到一些匪夷所思的问题,在scanf函数后正确使用fflush(stdin);,清空输入缓冲区,可以解决很多问题。以本题为例:


1

2

3

4

5

6

7

8

9

10

11

12

#include<stdio.h>

intmain(void)

{

inta=0,b=0,c=0,ret=0;

ret=scanf("%d%d%d",&a,&b,&c);

fflush(stdin);

printf("第一次读入数量:%d\n",ret);

ret=scanf("%d%d%d",&a,&b,&c);

fflush(stdin);

printf("第二次读入数量:%d\n",ret);

return0;

}

运行结果:

问题解决。

问题四

如何处理scanf()函数误输入造成程序死锁或出错


1

2

3

4

5

6

7

8

9

#include<stdio.h>

intmain(void)

{

inta,b,c;

scanf("%d,%d",&a,&b);

c=a+b;/*计算a+b*/

printf("%d+%d=%d",a,b,c);

return0;

}

如上程序,如果正确输入a,b的值,那么没什么问题,但是,你不能保证使用者每一次都能正确输入,一旦输入了错误的类型,你的程序不是死锁,就是得到一个错误的结果,呵呵,这可能所有人都遇到过的问题吧?解决方法:scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。正确的例程:


1

2

3

4

5

6

7

8

9

10

#include<stdio.h>

intmain(void)

{

inta,b,c;

while(scanf("%d%d",&a,&b)!=2)

fflush(stdin);

c=a+b;

printf("%d+%d=%d",a,b,c);

return0;

}

补充

fflush(stdin)这个方法在GCC下不可用。(在VC6.0下可以)

以下是 C99 对 fflush 函数的定义:

int fflush(FILE *stream);

如果stream指向输出流或者更新流(update stream),并且这个更新流

执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream

指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。

C和C++的标准里从来没有定义过 fflush(stdin)

fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush

函数会给那些流打上错误标记,并且返回EOF,否则返回0。

由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用

fflush(stdin) 是不正确的,至少是移植性不好的。

可采用如下方法:

方法一:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/*此函数可以和scanf函数一起使用,但使用%c输入时要注意,即此函数只能用于缓冲区非空的情况*/

#include<stdio.h>

voidflush()

{

charc;

while((c=getchar())!=‘\n‘&&c!=EOF);

}

intmain(void)

{

inta,b,c;/*计算a+b*/

while(scanf("%d%d",&a,&b)!=2)

flush();

c=a+b;

printf("%d+%d=%d",a,b,c);

return0;

}

方法二:

使用getchar()代替fflush(stdin)

程序示例:

 1 #include<stdio.h>
 2 intmain(void)
 3 {
 4 inti,c;
 5 while(1)
 6 {
 7 printf("Pleaseinputaninteger:");
 8 scanf("%d",&i);
 9 if(feof(stdin)||ferror(stdin))
10 {
11 //如果用户输入文件结束标志(或文件已被读完),或者发生读写错误,则退出循环
12 //dosomething
13 break;
14 }
15 //没有发生错误,清空输入流。通过while循环把输入流中的余留数据“吃”掉
16 while((c=getchar())!=‘\n‘&&c!=EOF);
17 //可直接将这句代码当成fflush(stdin)的替代,直接运行可清除输入缓存流
18 //使用scanf("%*[^\n]");也可以清空输入流,不过会残留\n字符。
19 printf("%d\n",i);
20 }
21 return0;
22 }

以上内容转载自网络。

时间: 2024-07-29 13:37:14

scanf()函数的相关文章

scanf函数

变量的内存:字节和地址:1.变量的存储单位是字节,每个字节都有存储地址.2.不同的数据大小占用的内存带下不同拥有的字节数也是不同的.变量的存储:1.存储是按照,先存储的放在地址教高的位置,优先存储的地址越大,存储地址用十六进制表示.2.&是取址运算符,用来获取地址.%p这个占位符用来输出地址.3.由于c语言弱语言性质,导致未初始化的变量不会报错,所以要注意变量的初始化.scanf函数说是stadio.h自带函数,用于提醒用户进行输入操作.注意:scanf只能输入变量地址,&变量名Scanf

C语言Scanf函数

C语言的scanf函数 一.变量的内存分析 (一)字节与地址 ①. 内 存以字节为单位 每个字节都有自己的内存地址,根据地址就可以找到该字节.整个内存相当于一整个酒店,而酒店以房间为单位,在这里每个房间就相当于是每个字节,地址就是房 号,根据房号可以找到房间(根据地址也可以找到内存中的字节).相邻房间的房号是连续的,相邻字节的地址也是连续的.计算机中通常以十六进制表示地址. ②. 不同类型占用的字节是不一样的,数据越大则占用的字节数越多.如在64位编译器下,int类型占据4个字节,char类型占

黑马程序员——C语言基础---scanf函数

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 1,scanf函数的概念 scanf函数也叫阻塞式函数,也就是说当函数执行后,会等待用户的输入,如果用户不输入任何内容,他会一直等待.如果使用这个函数,必须包含一个头文件 stdio.h. 2,scanf函数的作用 从键盘接受用户输入的内容,保存到指定的变量中. 3,scanf函数的格式 scanf("格式控制符",输入项的地址列表); 4,scanf函数的用法 输入一个整数 int

黑马程序员————C语言基本语法(关键字、标识符、注释符、变量、Scanf函数)

第一讲 关键字 1.什么是关键字? 1) 关键字就是C语言提供的有特殊含义的符号,也叫做“保留字” 2) C语言一共提供了32个关键字,这些关键字都被C语言赋予了特殊含义 C语言关键字 auto局部变量(自动储存) break 无条件退出程序最内层循环 case   switch 语句中选择项 char  单字节整型数据 const  定义不可更改的常量值 continue 中断本次循环,并转向下一次循环 default switch 语句中的默认选择项 do  用于构成do.....while

求最大值和scanf函数的使用以及函数的声明

/* ============================================================================ Name : MaxNumber.c Author : lf Version : Copyright : Your copyright notice Description : 求最大值和scanf函数的使用以及函数的声明 ==========================================================

黑马程序员----printf函数和scanf函数

一.printf函数和scanf函数,都被定义在头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>. 二.printf函数 1.定义:printf()函数是格式化输出函数, 一般用于向终端按规定格式输出信息; 2.格式:printf("XXXXXXXX"); 三.scanf函数 1.定义:scanf()函数按用户指定的格式从键盘上把数据输入到指定的变量之中; 2.格式:scanf("%d", &numbe

C语言-数据类型、常量、变量、变量作用域、printf、scanf函数

4.数据类型介绍 数据:文本数据.音频.视频.图像.数字 C语言中有5大数据类型:基本类型.构造类型.空类型.指针类型.自定义类型 基本数据类型: 整型    长整型long int    整型int(4)    端整型short int 实型    单精度float(4)    双精度 double(8) 字符型   char(1) 内存: 1> 内存分配:4G存储大小:4*1024*1024*1024Byte; 内存的基本单元为一个字节(就是8bit) 2> 内存区域:栈 (存放局部变量)

while循环中使用scanf函数

妈的,这scanf函数学了快10年了,怎么还会出现莫名其妙的问题?看下面的代码(VS2012环境下运行): #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { char root_value = '\0'; int i =1; while (i!=5) { printf("输入:"); scanf("%c",&root_value);//用户输入节点 i++; } prin

关于scanf()函数的一点理解

习惯了c++的cin.cout之后,也不怎么关注空格,反正cin.cout会自动处理.有一次实验,创建Huffman树,要求输入空格字符,当时就懵逼了.cin咋输入空格呢? 没办法,只能重新用scanf函数了,结果各种悲剧,足足debug一个多小时,这难道就是越学越差劲系列?o(╯□╰)o scanf()和printf()严格来说并不是c的一部分,当我们用scanf()函数输入数据时,只要不回车,数据就暂存在缓冲区.因此我们可以输入一下 回车一下,也可以全部输完再回车,一般来说这两者没啥区别,但

【C语言】05-printf和scanf函数

一.printf函数 这是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>,使用它可以向标准输出设备(比如屏幕)输出数据 1.用法 1> printf(字符串) printf("Hello, World!"); 输出结果是: 2> printf(字符串, 格式符参数) 1 // 使用常量作参数 2 printf("My age is %d\n", 26); 3 4 // 也可以使用变量 5 int ag