关于scanf缓冲区.docx
《关于scanf缓冲区.docx》由会员分享,可在线阅读,更多相关《关于scanf缓冲区.docx(25页珍藏版)》请在冰豆网上搜索。
关于scanf缓冲区
窗体顶端
先看两个问题(以下程序运行环境为WIN2000+DEV-C++4.9.9.2):
1、执行以下程序:
[Copytoclipboard][-]
CODE:
/*****************************************************
Name:
copy_bar.c
Copyright:
kernelxu
Author:
kernelxu
Date:
2005-08-0211:
20
Description:
showtheprogressbarwhiledoingcopy
****************************************************/
#include;
intmain(void)
{
charc='\0';
int i=0;
longj=0L;
putchar('\n');
puts("Copy?
(y/n):
\n");
for(;(c=getchar())=='y'||c=='Y';)
{
printf("Coping......");
for(i=0;i<=100;i++)
{
printf("%%%3d",i);
printf("\b\b\b\b");
j=0L;
while(j<20000000)
{
j++; /*delay相当于linux中sleep(n)*/
}
}
puts("\nFinished!
\n");
puts("Copy?
(y/n):
\n");
}
system("pause");
return0;
}
该程序实现一项简单的状态条显示功能(当然只是玩玩而已),但是它不能循环进行下去,程序执行一次循环就跳出了。
2、
[Copytoclipboard][-]
CODE:
/*****************************************************
Name:
login_example.c
Copyright:
kernelxu
Author:
kernelxu
Date:
2005-08-0214:
17
Description:
takingloginforexampletosaysthaboutI/Obuffer
*****************************************************/
#include;
#include;
#defineNAME_MAX10
#defineUSER_NAME"kernelxu\0"
#definePASS_WORD123456
intmain(void)
{
charuserName[NAME_MAX]={'\0'};
unsignedlong passWord=0UL;
for(;;)
{
printf("Login:
");
gets(userName);
printf("Password:
");
scanf("%ld",&passWord);
if(passWord!
=PASS_WORD||strcmp(userName,USER_NAME)!
=0)
{
printf("LoginIncorrect!
\n");
continue;
}
break;
}
printf("[%s@localhost~]$",userName);
getch();
return0;
}
该程序只要输入的用户名超过NAME_MAX-1值或者password输入的不是正整数,就无法登录了。
以上两例程序之所以存在很大的问题,主要是在处理标准输入缓冲及选择输入函数上不够慎重。
本文先总结一下流(stream)、缓冲区(buffer)的概念,然后重点说一下这类问题的解决之道。
您对本贴的看法:
鲜花[0]臭蛋[0]
__________________________________
ANewGNU/LinuxDistribution.
至强5500服务器应用状况调查|免费android技术培训限额报名!
|CU第一本技术图书隆重上市|IT技术大调查,超薄手机等你拿
kernelxu
风云使者
注册:
2005-3-24
最后登录:
2008-08-06
帖子:
412
精华:
2
可用积分:
416(稍有积蓄)
信誉积分:
100
专家积分:
0(本版:
0)
空间积分:
0
推广积分:
0
来自:
Mars
状态:
...离线...
[个人空间][短信][博客]
[推广获积分]
2楼发表于2005-8-321:
25
关于流和缓冲区的理解以及一般标准输入问题的解决方法小结
一、流(stream):
这里讨论的是标准I/O术语流(请勿将其与系统V的STREAMSI/O系统相混淆,后者可参见Stevens的《UNIX环境高级编程》第十二章)。
引用:
1)(K&R《TheCProgrammingLanguage》P241)
QUOTE:
Astreamisasourceordestinationofdatathatmaybeassociatedwithadiskorotherperipheral.
中文版(徐宝文等译)翻译为:
QUOTE:
流(stream)是与磁盘或其它外围设备关联的数据的源或目的地。
2)(http:
//www.cs.cf.ac.uk/Dave/C/node18.html#SECTION001820000000000000000)
QUOTE:
Streamsareaportablewayofreadingandwritingdata.TheyprovideaflexibleandefficientmeansofI/O.AStreamisafileoraphysicaldevice(e.g.printerormonitor)whichismanipulatedwithapointertothestream.
翻译为:
QUOTE:
流是(表达)读写数据的一种可移植的方法,它为一般的I/O操作提供了灵活有效的手段。
一个流是一个由指针操作的文件或者是一个物理设备,而这个指针正是指向了这个流。
3)(ISO/IEC《ISO/IEC9899:
1999(E)》)
QUOTE:
Inputandoutput,whethertoorfromphysicaldevicessuchasterminalsandtapedrives,orwhethertoorfromfilessupportedonstructuredstoragedevices,aremappedintologicaldatastreams,whosepropertiesaremoreuniformthantheirvariousinputsandoutputs.
翻译为:
QUOTE:
不管是交互于诸如终端和磁带驱动器之类的物理设备,还是存取于由结构化存储设备支撑的文件,输入和输出(信息)都被映射为逻辑数据流,而流的属性却远不是诸多输入输出属性的统一。
4)(Kenneth.A.Reek著,徐波译《C和指针(PointersOnC)》第十五章P229)
QUOTE:
ANSIC进一步对I/O的概念进行了抽象。
就C程序而言,所有的I/O操作只是简单地从程序移进或移出字节的事情。
因此,毫不惊奇的是,这种字节流便被称为流(stream)。
程序只需要关心创建正确的输出字节数据,以及正确地解释从输入读取的字节数据。
特定I/O设备的细节对程序员是隐藏的。
5)(引自SergioC.Carbone《LearningCForReal》P33)
QUOTE:
Whatismeantbythestreamconcept?
-Astreamisalogical,deviceindependentwayofhandlingmanyperipheraldevices.
-Mostperipheraldevicesaredifferentandwouldrequirespecialprogramming
techniques.
-Streamsmaskthisdifferencefromtheprogrammerandallowstheprogrammerto
handlemostperipheraldevicesinthesameway.
-Streamsarebufferedinterfacesthatarethoughtofasaseriesofcharactersreadone
atatime.
-PCsarebasedonastreamarchitecture.
翻译为:
QUOTE:
流的概念意味着什么呢?
--流是独立于设备之外而操纵外设一种逻辑手段。
--大多数外设都是互异的,所以(操纵)它们需要专门的编程技术。
--流对程序员隐藏这些不同点,而准许他们以同样的方式来处理大多数外设。
--考虑到一连串的字符需要一次读一个,流(相当于)是具有缓冲作用的接口。
--个人计算机都是基于流架构的。
各大权威对流的说法有些不一致,我认为流既是数据的源或目的地的抽象,也是源和目的地之间流动信息的表示。
但流起码都暗含以下的几个方面:
1、流是一个抽象的概念,是对信息的一种表达;在程序中,流就是对某个对象输入输出信息的抽象。
就像运输工具是对一切运动载体的抽象一样。
2、流是一种“动”的概念,静止存储在介质上的信息只有当它按一定的序列准备“运动”时才称为流。
“从程序移进或移出字节”就是“动”的表现。
静止的信息具有流的潜力,但不一定是流,就像没有汽油不能行走的汽车一样,它具有运输工具的潜力,但它还不是运输工具(因为它很有可能被当作房子来用了,我就在大街上看见有精明的商人用火车车厢来做酒吧)。
3、流有源头也有目的地;程序中各种移动的信息都有其源和目的,记得编程(特别是汇编)时,老是要确定好某个操作的源操作数和目的操作数。
借用佛教一言也即是:
“万物皆有因果”,这也就像长江一样,西自唐古拉,而东去太平洋。
在高速公路上飞跑的汽车,它必有其出发地和目的地。
4、流一定带有某种信息,没有任何内容的流带着自身来表达“空”信息。
就像运输工具一样,它不运货的时候就运着自己这一身的零件(包括驾驶员)并把一样东西运到目的地,那就是它自己和一个“跑空车”的信息。
流有最小的信息单元就是二进制位,含有最小的信息包就是字节,C标准库提供两种类型的流:
二进制流(binarystream)和文本流(textstream)。
二进制流是有未经处理的字节构成的序列;文本流是由文本行组成的序列。
而在著名的UNIX系统中,文本流和二进制流是相同的(identical)。
5、流有源头也有目的地,那么它必定与源头和目的地相关联。
但人们操作流的时候,最关心的还是其目的地,也就是一个定向(orientation)的意思,就像司机运货一样,它首要关心的问题是目的地,而非起点(操作者都知道)。
在C语言中,通过打开流来关联流及其目的地,使用的函数是fopen(),该函数返回一个指向文件的指针(FILE*),该指针包含了足够的可以控制流准确地到达目的地的信息。
FILE是一个结构体(摘自TC2.0中stdio.h文件)
[Copytoclipboard][-]
CODE:
/*Definitionofthecontrolstructureforstreams
*/
typedefstruct {
short level; /*fill/emptylevelofbuffer*/
unsigned flags; /*Filestatusflags */
char fd; /*Filedescriptor */
unsignedchar hold; /*Ungetccharifnobuffer*/
short bsize; /*Buffersize */
unsignedchar *buffer; /*Datatransferbuffer*/
unsignedchar *curp; /*Currentactivepointer*/
unsigned istemp; /*Temporaryfileindicator*/
short token; /*Usedforvaliditychecking*/
} FILE; /*ThisistheFILEobject*/
将它称为流控制结构体(controlstructureforstreams)真好表现出其功能来。
举个例子就好像一卡车司机要把货物运到X公司,公司主管就会给他一张地图及X公司的基本信息,这些材料所提供的信息如果足够的话,那么它就能指导着司机准确地将货物送达了。
C中FILE这个结构体所起的作用就好像是运输公司把一切有用的指导信息封装起来的档案袋一样。
而已有关联的流要终止这种关联,就必须关闭流,使用的函数是fclose(),就像运货公司若不再给X公司运货了,那么他们就必须要终止合作协议了。
这里要注意的是:
C语言中stdin、stdout、stderr分别是标准输入流、标准输出流及标准出错流的逻辑目的,他们都默认对应相应的物理终端。
在程序运行伊始,不需要进行open()操作,流自动打开。
关于C语言流(stream)的具体细节可参看:
QUOTE:
a) K&R《TheCProgrammingLanguage》
b) Kenneth.A.Reek著,徐波译《C和指针(PointersOnC)》
c) Stevens的《UNIX环境高级编程》
d) 《ISO/IEC9899:
1999(E)》及ANSIC手册
您对本贴的看法:
鲜花[2]臭蛋[0]
__________________________________
ANewGNU/LinuxDistribution.
至强5500服务器应用状况调查|免费android技术培训限额报名!
|CU第一本技术图书隆重上市|IT技术大调查,超薄手机等你拿
kernelxu
风云使者
注册:
2005-3-24
最后登录:
2008-08-06
帖子:
412
精华:
2
可用积分:
416(稍有积蓄)
信誉积分:
100
专家积分:
0(本版:
0)
空间积分:
0
推广积分:
0
来自:
Mars
状态:
...离线...
[个人空间][短信][博客]
[推广获积分]
3楼发表于2005-8-321:
30
关于流和缓冲区的理解以及一般标准输入问题的解决方法小结
二、缓冲区(Buffer):
为了匹配计算机快速设备和慢速设备间的通信步伐,计算机中大量使用硬件缓冲区(如CPU中的Cache,内存相对于硬盘和CPU),流是传输信息的一种逻辑表示,对流的各种不同操作也可能存在使用缓冲的需求。
但是这里的buffer只是一种逻辑概念,不是物理设备。
缓冲区存在于流与具体的设备终端或者存储介质上的文件之间。
就好像运货到一个公司里一样,合同上的要求是运到X公司,但是实际上是真的把货物运到X公司的总部大楼吗?
不是。
应该是运到X公司的仓库中。
这里的仓库就有点像我们所说的缓冲区了。
也可以这么说,流运动到目的,先经过的是缓存区。
有时候是不是可以这样理解:
stdin、stdout和stderr就是标准输入流、标准输出流及标准出错流的缓存区。
1、(引自《RationaleforInternationalStandardProgrammingLanguagesC》)
QUOTE:
Buffering.UNIXallowstheprogramtocontroltheextentandtypeofbufferingforvariouspurposes.Forexample,aprogramcanprovideitsownlargeI/Obuffertoimproveefficiency,orcanrequestunbufferedterminalI/Otoprocesseachinputcharacterasitis20entered.Othersystemsdonotnecessarilysupportthisgenerality.Somesystemsprovideonlyline-at-a-timeaccesstoterminalinput;somesystemssupportprogram-allocatedbuffersonlybycopyingdatatoandfromsystem-allocatedbuffersforprocessing.BufferingisaddressedintheStandardbyspecifyingUNIX-likesetbufandsetvbuffunctions,butpermittinggreatlatitudeintheirimplementation.Aconforminglibraryneedneither25attempttheimpossiblenorrespondtoaprogramattempttoimproveefficiencybyintroducingadditionaloverhead.
2、(摘自A.D.Marshall《ProgramminginCUNIXSystemCallsandSubroutinesusingC》
http:
//www.cs.cf.ac.uk/Dave/C/)
QUOTE:
StreamI/OisBUFFERED:
Thatistosayafixed``chunk''isreadfromorwrittentoafileviasometemporarystoragearea(thebuffer).ThisisillustratedinFig.1.NOTEthefilepointeractuallypointstothisbuffer.
Fig.1(见文末)
QUOTE:
StreamI/OModelThisleadstoefficientI/Obutbeware:
datawrittentoabufferdoesnotappearinafile(ordevice)untilthebufferisflushedorwrittenout.(\ndoesthis).Anyabnormalexitofcodecancauseproblems.
标准I/O提供缓存的目的是尽可能减少使用read和write调用的数量。
它也对每个I/O流自动地进行缓存管理,避免了应用程序需要考虑这一点所带来的麻烦。
不幸的是,标准I/O库令人最感迷惑的也是它的缓存。
不同类型缓存往往使人在进行I/O操作时不知所措。
标准I/O提供了三种类型的缓存:
全缓存、行缓存、无缓存。
1、(引自ISO/IEC《ISO/IEC9899:
1999(E)》)
QUOTE:
Whenastreamisunbuffered,charactersareintendedtoappearfromthesourceoratthedestinationassoonaspossible.Otherwisecharactersmaybeaccumulatedand
transmittedtoorfromthehostenvironmentasablock.Whenastreamisfullybuffered,charactersareintendedtobetransmittedtoorfromthehostenvironmentasablockwhenabufferisfilled.Whenastreamislinebuffered,charactersareintendedtobetransmittedtoorfromthehostenvironmentas