《10小时学C语言》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
计算器程序讲义10小时学会c语言☆★☆★☆☆★☆★☆☆★☆★☆☆★☆★☆☆★☆★☆☆★☆★☆☆★☆★☆☆★☆★翁不要完全相信书上及老师所讲的内容,只有自己实作オ是真的。☆李栋梁Sep.22,1997参考书目:10小时学会C语言[修订版]施保旭着儒林出版社!997年6月初版3版page10132132404655内容・第一章C语言简介与TurboC的使用・第二章C程序的结构・第三章常数与变数・第四章基本输出入函式・第五章流程图与抉择指令・第六章循环与自动重复・第七章数组与指针・第八章函数与呼叫・第九章档案存取■第一章C语言简介与TurboC的使用◎C语言的优点:〇效率高:C语言的编译器会产生最小的程序代码。〇可移植性/移植性高:经过些许的修改,可以在不同的平台使用。〇功能强而有弹性。
1〇需要记忆的东西很少,易于写作。◎TurboC的安装:已安装在学校主机。TurboC的环境设定:TurboC安装的目录必须设定在PATH的系统变量。如:PATH=C:\TC;C:\DOS;如此TC才能正常工作。◎TurboC的使用只要设定好PATH变量,在DOS提示号输入TC,就可以执行TurboC的整合环境了。TC将编辑(Ediり、编译(Compile)、连结(Link)、除错(Debug)、档案管理(File)、...等等的坊能整合在・鈕,所以我们称之为整合环境。最好先用CD蛤指令,变更工作目录到你要写C的目录,再执行TC,这样所产生的档案,就会里这个目录里面,便于备份与管理。◎移动光标方向键ーtI一可以用来移动光标。◎删除文字将光标移到你要删除的文字上,再按下Del键即可。将光标移到要删除文字的右边,再按下BS退位键也可以。◎加载文字文件(C语言原始码文件)按下功能键F3或按F10选FilefLoad就会出现ー个询问窗口要求输入文件名:LoadFileName*.C其中的文件名可以使用万用字符・或?,或直接指定你要的檔名。若是使用万用字符,TC会再秀出ー个窗口让你选择所要的档案,你可以用方向键移动反白光棒,按Enter键则是选择反白的档案。◎储存编辑的文字文件按下功能键F2或按F10选File-Save就会储存目前编辑档案。若你想另外取・个档名,并加以存盘,就必须按F10选File-Writeto就会出现ー个询问窗口要求输入文件名:NewName输入新的档名,按下Enter即可。◎编译并执行目前的所编辑的程序TurboC是一种编译语言系统,你所写的程序,经过TC的编译(pass1)及连结(pass2)后,产生可执行档(.exe),才能在PC上执行。按下Ctrl+F9或按F10选Run-Run,TC会编译目前所编辑的程序,如果没有错误发生,TC会立即执行所编辑的程序。TC在执行完程序后,会立刻切换回到TC的整合环境,如果你还想看刚オ程序执行的结果,可以按卜Alt+F5或按F10选Run-Userscreen,就会切换到执行画面,再按下任何ー键,就会冋到TC的整合环境。◎结束TurboC按下Ait+X或按F10选FilefQuit便可结束TurboCo若你还有已编修尚未储存的档案,TC会问你要不要存。VerifyNONAME.Cnotsaved.Save?(Y/N)
2要存就按Y,不想存就按N〇
3・第二章C程序的结构◎C程序的结构:hello.c一ー范例文件名#include
4在C语言中,调位字符(如:空白(space)、定位(tab)及换列字符)在编译时都会被忽略,所以可适时加入调位字符,使程序好看一点。要注意的是,别把ー个完整的个体拆开,如:main、printf等,这些字本身是ー个完整的个体,不可予以拆开。而在各个个体之间,可以任意加入调位字符。☆C语言中的英文字母是有分大小写的,printfO与PrintFO不同,内建的函式大多是小写的,你自一写的函式,则可以用大写来做区隔。◎printf的功用printfO的功用是在屏幕上输出数据。在TC中,在编辑区内输入printf,再将光标移到printf这个字上,按下Ctrl+F!就会看到以下Help画面:Helpprintf:formattedoutputtostdoutintprintf(constchar"format,...);Prototypeinstdio.hPrintformatsavariablenumberofargumentsaccordingtotheformat,andsendstheoutputtostdout.Returnsthenumberofbytesoutput.Intheeventoferror,itreturnsEOF.Seealsoecvtfprintfputcputsscanfvprintfー这是TC的Help窗ロ_printf是将格式化的数据输出至リ.stdout-printf的语法一要用printf应该#include的檔ー使用说明:不同的格式须要不同的参数,这些薮据会送到stdout。传冋宿是输出的byte数,若发生错误则传冋EOF一可参考相关指令:ecvt,fprintf,putc,puts,scanf,vprintf在用TC的整合环境中,只要将光标移到想进ー步了解的指令或内建的函式上,按下Ctrl+F!就可以叫出TC的Help说明窗ロ,得到该指令或函式的相关说明。printf的语法:intprintf(constchar*format,...);其中constchar*format指的是ー个格式化的字符串。const是常数的意思,在此表示format这个字符串指针传入printf函式后,它的值不会被改变。...指的是不定参数,参数的数目取决于format字符串的内容,这些参数,通常是ー些你要秀出来的变量。简单来说:printf("输出格式(含控制字符串)",要印出的数据);在C语言中是用双引号(D来引含字符串,也就是在双引号内的数据,是ー个字符串。本章只介绍%d这个控制字符串,其它的控制字符串在第四章会讲到。%d表示以整数10进位的方式秀出数据。在输出格式(含控制字符串)内有几个%d,在要印出的数据内就要有几个整数来对应。
5arith.c#include
6",printf("%d-%d=%d
7",printf("%d*%d=%d
8",printf("%d/%d=%d
9",}我们以第四列的叙述作说明:printf("%d+%d=%d
10",8,2,8+2);在输出格式(含控制字符串)内有3个%d,所以在要印出的数据的部分有8,2,及8+2三个整数对应,所以输出来的结果就是8+2=10在输出格式(含控制字符串)的最后有
11符号,这是・个控制字符,表小要更换到下刮,其它的控制字符在第四章会提到。若将本例中的
12都删除,那秀出的结果会像这样子:8+2=108-2=68*2=168/2=4◎C的四则运算计算机语言用的四则运算符号儿乎都是相同的:四则运算符号意义范例结果+加法4+26-减法(或代表负号)4-22*乘法4*28/除法4/22相关运算符号意义范例结果++变数值加1i++或++ii值加1--变数值减1i--或--ii值减1%整数除法的余数4%20在书中提到C语言没有提供次方的功能,指的是在某些计算机语言可以用・・表示次方,如:2**3,表示2的3次方;有的用A表示,如:2A8,表示
132的8次方。在C语言,没有运算符号可以表示次方,但是C语言有提供次方的函式:pow(),pow(2,3)表示2的3次方。中括号I」及大括号{}是有其它的用途,所以在作数学运算时,只要用括じ,就只能用小括号.'、ー".一.1--・个式子如果有多个运算的话,C是以先乘除后加减的方法来运算,当然我们也可以用括号()来改变这个法则,只要有括号,就优先运算。另外,在C语言内(),小括号可以多层,C在运算时,是由最内层开始运算。555***\JZ\)z\17XJZ\!/4+7355zl\/l\775**122++111126✓fkzv^(\=====他范88888+++++2222◎批汪(Comments)通常老师会要求初学者在程序的每一列加上批注,这是为了让初学者知道自己在写些什么程序代码,了解为什么要这样写,而不只是照著书Keyin程序。写批注有助于自己了解程序的内容,便于日后的修改。但写批注对于某些程序设计师而言可说是ー种噩梦,因为写批注所花的时间可能会与写程序的时间相去不远,认为写批注只是在浪费时间。对ー个相当好的程序设计师而言,也许写批注真的是浪费时间,因为好的程序代码本身就已经隐含了批注,这也是写程序相当高的境界。对一般的程序设计师而言,写ー些批注还是比较好的作法,特别是某些程序代码是你花了一段时间オ想到的「特殊」方法,加上一些批注,说明一下这个「特殊」的方法,以后要修改才能快速进入状况,否则,你可能会佩服自己当时是如何想到的这个方法,又再花一段时间才知道自己在写些什么程序代码。讲了这么多批注的正反面(正面居多)论调,在C语言中要如何写批注呢?只要用/*和*/将你要的批注内容包起来就可以了。C在编译时,会将/**/内的数据略去,就如同调位字符ー样。唯一的例外是:当/**/在ー组双引号"内时,它们就属于这组双引号所包含的字符串。在C++语言中则可用//当批注.comments.corcomments.cpp#include
14",printf("%d-%d=%d
15",printf("%d*%d=%d
16",printf("%d/%d=%d
17",//endofprogram所以这个程序目前是空的,2,8+2);*/,2,8-2);,2,8*2);,2,8/2);//divi*/sion
18◎巢状批注(NestedComments)nestcomO.c1011ffinclude
19",8,2,/*printf("%d-%d=%d
20",8,2,printf("%d*%d=%d
21",8,2,printf("%d/%d=%d
22",8,2,}:printf()*/ォ不会有错误8+2);8-2);8/2);上面的例子,有四组批注/**/,其中第三组及第四组的批注之间有部分重迭。想要Compile没有错误,必须第5列的/・与第10列的・/配,也就是第5列到第10列都是批注;另外第7列的/・与第7列的・/配,也就是第7列是批注。这种批注方式,我们称之为巢状批注。TurboC内定是不可使用巢状批注的,上面的例子会是第5列的/・与第7列的・/配,结果在第!0列的・/会变成是多余的,造成Compile错误。扌[开巢状批注的方法:按卜F10fOptionsfCompilerSourceNestedcommentsOff蒋Off设为On就可以了。◎巢状批注的使用时机在前面的例子只是为了说明巢状批注,也许你会觉得这样的用法是自找麻烦,但是以下的例子,你越会认为有巢状批注的功能还是比较好的。在nestcoml.c中,每••列的printf();后面都加上了批注。若要把这儿列程序变成批注,不使用嵬状批注,就会像nestcom2.cー样,必须在每一列的printfO;前后再加上/**/,若是使用巢状批注,就像nestcom3.cー样,只要在这儿列的前后加/**/就可以了。nestcoml.c^include
23",printf("%d-%d=%d
24",printf("%d*%d=%d
25",printf("%d/%d=%d
26",}
27nestcomz.c1011ffinclude
28",/*printf("%d-%d=%d
29",/*printf("%d*%d=%d
30",/*printf("%d/%d=%d
31",}222288882222+-*/8888-2+8*6--2二2*8*nestcom3.c1011#include
32",printf("%d-%d=%d
33",printf("%d*%d=%d
34",printf("%d/%d=%d
35",町}222288882222+-*/8888****〇6.4.44==--=2222+-//8888****
36•第三章常数与变数C语言的数据可分为常数(constant)及变量(variable),常数指的是固定不变的数,例如:〇,L2等数值,或是用双ホ号定义的字符串,我们也称之为字符中常数。变量指的是数值可以改变的数,例如:ー个整数变量,我们可以把它设成1,然后再改为10,或是其它的整数数值。ー个程序若没有变量,那纯粹只是将常数秀出来而已,好比是用文字编辑器编辑・个档案,再用type把它秀出来ー样。有了变量,就可以做不同的变化。◎变量的型态Char,int,long,float,doubleetc.〇◎变数的命名如同档案的命名,变量的名字要取得有意义,在C中,名字可以取得很长,但是要用英文的,所以你可以把变量用中翻英来命名。◎变量的命名规则a到2)或是底线(_)〇到9〇保留字是给编译器使用,不可以当成〇变量名称的第一个字符必须是英文字母〇第二个字符以后可以使用前述字符,再〇变量名称的大小写是不同的。〇变量名称的最前面32个字符仃效。〇不可以使用「保留字」当变量的名称,变量名称。TC有以下的保留字:流程:型别:运算:ifswitchgotocharvoidshorttypedefautointerruptelsefordefaultcasereturnintlongregistersignednearfarstructunionconststaticcdecl缓存器:_AL_BL_CL_DL_BP_AH_BHCHDH:D1dobreakwhilecontinuefloatdoubleunsignedhugeenumvolatileexternpascalasm_cs_CS_ds二DS_esZesssss"SP◎变量的设定使用变量时,应该先考虑这个数可能的数值范围,用以选定变量的型别,例如:用・个数来存班上的人数,•个合班的大班级可能超过百人,但最大不太可能超过千人,所以选ー种变量型别可存!000以下的数值,在此可选整数。若是要用ー个数来存你的存款,则整数的上限32767可能某些同学・个月的薪资就是它的数倍,所以要选长整数,它的上限是2147483647〇在数学运算时,想要有小数的就要用浮点数(float)。在C语言中,变量宣告的语法如下:型别变量名称1[,变量名称2;I/・学生人数・//・银行存款・/例如:intNumberOfStudent;longMoneyInBank,interest;
37floatRateOflnterest;/・利息利率・/charEndOfString;/・字符串结束・/char0neStudentName[9];/*学生姓名・/在宣告变量时,我们可以设定变量的初始值(initialvalue),语法如下:/・学生人数・//・银行存款・//・利息利率in%*//・字符串结束・//・学生姓名・/型别变量名称1=初始值1[,变量名称2=初始值2[,..]];I例如:intNumberOfStudent=60;longMoneyInBank=1000000L;floatRate0flnterest=5.0;charEndOfString='\0';charOneStudentNamej9j="王大明";注意:在银行存款的设定数值!000000后加上•个L,表示这个常数数值1000000是•个长整数。因为C语言内定的型别是整数,为了防止不可预期的状况发生,最好是自己把它设定成你想要的型别,不要假设TC会帮你做好好的,要假设TC很笨不会帮你做,这样在发展大程序要除错时,就可以把问题简化,不必再考虑是不是数据型别错误,只要把程序流程或算法搞定就可以了。在K中,不加L,结巢还是正确的,但是在其它的环境下可能会不同。多加一个L并不会使程序变大或变慢,又能保障正确使用,何乐不为。〇复习一下字符与字符串:char字符只占ー个byte,以ー组单引号’引含字符数据,其表示法如下:0单一字符:'A'、’a'、‘〇‘〇0ハ进制数值:’\101'、'\141'、'\60'、'、〇'0十六进制数值:'\x41'、'\x61'、'\x30'、'\x0'字符串则是由•个以上的字符所组成的,而且以’、〇'这个字符做为结尾。表示法:"123">"ABC","abc"o以上的三个例子都是占4bytes。用strlenO可以取得字符串的长度(不含''〇'字符)。如:intStringLen=str1en("123");这样,StringLen就奪于3〇☆在使用strlen()时,必须加入#include
38在第五章中会作介绍。以下我们来看ー些设定的例子,计算圆的面积:PI=3.1415926;r=4;area=PI*r*r;以下是用变量的方式表示的范例:var.c#include
39",i,ji,i+j);printf("%d-%d=%d
40",i,ji,i-j);printf("%d*%d=%d
41",i,ji,i*j);printf("%d/%d=%d
42",i,jI,i/j);i=20;j=2;printf("%d+%d=%d
43",i,ji,i+J);printf("%d-%d=%d
44",i,Ji,i-j);printf("%d*%d=%d
45",i,ji,i*j);printf("%d/%d=%d
46",i,jl,i/j);10+2=1210-2=810*2=2010/2=520+2=2220-2=1820*2=4020/2=10变量使用的有效范围:整体变量(GlobalVariable):整体程序内区域变量(LocalVariable):函式内静态变量(StaticVariable):单ー程序内
47■第四章基本输出入函式这一章将介绍•些基本输出入的函式,使用者经由这些函式可以与计算机沟通,让程序读取使用者的输入部分。程序依使用者不同的要求,做不同的事,再将结果输出给使用者。©输出指令:printf()在第二章中,曾经谈过printf指令,现在来详细的探讨它。printf是ー种格式化的输出指令,换句话说,你可以用它来编排你所要的输出格式。printf的一般型式如下:printf("控制字符串",表达式1,表达式2控制字符串是你打算要秀出的讯息,其中利用%与、这两个字符,来控制数值的输由格式。控制字符串中每ー个%符号,表示在后面有一个表达式与它对应,表达式的值会代入这个%的位置。在%后的字符表示代入数的型别,常用的句柄如下表:printf的句柄1代表代入的数值型别1%c字符%d十进制之整数%ld十进制之长整数%f浮点数%lf倍精浮点数%Lf长倍精浮点数%s字符串表达式的型别必须跟句柄所代表的型别相符,否则会秀出不可预期的资料。另・个控制符号、,其实只是定义字符而已。在上一章已经介绍了字符的各种表示法,如:''x4「表示A字符。在C语言中,将一些特殊的控制字符另外定义,这些控制字符大部份跟光标的控制有关,如下表:控制字符DecHex功能
4810OxOA换列し也就是将光标移到下ー一列\t0x09府光标移剣ドー个定位(l+8n)\b0x08退・格,类似按下左键\a70x07喇叭叫一声\r13OxOD回到列首\f12OxOC跳页,在列表时控制列表机跳页\\92Ox5C印出、字符\,390x27印出‘字符\"340x22印出"字符\xHHOxHH印出OxHH所表示的字符%%370x25印出%字符其中,%字符的定义与在控制字符串中的表示法不同,其余的字符在定义上与在控制
49字符串中的表示法都相同。printf在做输出时,你也可以指定保留多少位置给对应的表达式放结果。指定的方式是在%之后加一个数值,如%5d:表示保留5个字符空间给ー个十进制整数;%121d:表示保留12个字符空间给一个十进制长整数。如果要输出数据的长度比你指定的保留空间还要大时,printf就不理会你的设定,把要输出的数据完整的输出,所以,你在设定保留空间时,应该注意输出数据的范围及长度,保留够大的空间,确保输出格式的整齐。在浮点数方面,你除了可以指定保留的空间外,还可以指定小数点后要取儿位。如%8.3f:表示保留8个字符空间给一个浮点数,小数部分则是占3个字符空间,由于小数点本身占ー个字符,所以整数部分占8-(3+1)=4个字符空间。printf在输出数据时,如果你指定保留的空间比要秀M数据长度还要大时,那printf先秀一些空白,再秀出数据,使总长度等于你所指定的宽度,这样等于是让输出的数据向右对齐。如果你想要让数据是向左对齐的话,可以在指定宽度时使用负数,如%-5d:表示保留5个字符空间给•个卜进制整数,若数据长度不足5,则在秀出资料后补空白。%%dIQ11ww若有指定,若无指定,若有指定,若无指定,若有指定,若无指定,定号决号负守据负出冷数正秀ド由出会ハ将秀数齐齐W度会负对对留长定有左右保出。只向向贝秀贝贝贝贝〇整数(int)及长整数(long)ffloatfdoubleflongdouble%%%若有指定,若无指定,若有指定,若无指定,若有指定,若无指定,若有指定,若无指定,〇浮点数(float)、倍精浮点数(double)及长倍精浮点数(longdouble)则保留p个字符给小数内定是保留6个字符给小数则保留w个字符含小数及小数点秀出长度将由数据决定则・,兔会莠出正负号则只有负数会秀出负号则向左对齐则向右对齐说了这么多,只有自己试试看才知道!以下是个简单的例子:print.c#include
50",123456);printf("l%51dl
51",123456);printf("l%dl
52",123);printf("l%5dl
53",123);printf("l%-5dl
54",123);
55printf("l%fl
56",12.345);printf("l%9fl
57",12.345);printf("l%9.2fl
58",12.345);printf("l%-9.2fl
59",12.345);11234561—123456大于3276?要长整数才能表示,所以用%ld11234561一所保留的5个字符不够使用,所以TC视同你没设11231I1231ー保留5个字符,只使用3个字,向右靠齐1123I一保留5个字符,只使用3个字,向左靠齐112.3450001ー小数没有指定,所以TC使用内定的6个小数。112.3450001一保留9个字符,小数部分仍使用内定值I12.351一保留9个字符,小数2个字符,向右靠齐112.35I一保留9个字符,小数2个字符,向左靠齐◎轴入指令:scanf()C语言使用scanf指令来读取keyboard输入的数据。scanf的一般型式如下:scanf("控制字符串",&变量1,&变量2,...);scanf与printf可以说是相对的,,个用来做输入,•个用来做输出。scanf的插前字符串与printf几乎是一祥。scanf的句柄代表输入的数值型别I%c%d%ld%D%f%lf%Lf%scharc;inti;long1;floatf;doubled;longdoubleId;******数.数点占滓数数浮精符数整点精倍字整长浮倍长******/*C的指针是&c*//*i的指标是&i*//*1的指标是&1/*f的指标是&f/*d的指标是&d/*Id的指标是&ld*/字符十进制之整数十进制之长整数十进制之长整数浮点数倍精浮点数长倍精浮点数字符串★注意:没有%F这种句柄,课本有误!%D的句柄只能用在scanf(),在printf()中无法使用。在用scanf时还有一点要注意,在控制字符串后的变量,使用的是指针(pointer)。什么是指标?指针就是指向内存的ー个地址,在那个地址存放着数据。例如:ー个整数变量i,它是存在内存的某ー个地址,那个地址在C语言中,是以&i来表示,我们通常称&i是i的地址,也称为i的指标。以下是常用的变量及其指针(因为它的地址固定不会改变,也称为指标常数):
60charstr[80];inta[100];longb[100];floatc[100];/・字符数组(字符串)*//*str[80]的指标是str*//・整数数组・//*a[100]的指标是a*//・长整数数组・//*b[100I的指标是b*//・浮点数数组・//*c[100I的指标是c*/以下的范例,将第三章的范例var.c变量改由scanf输入:io.c#include
61",printf("%d-%d=%d
62",printf("%d*%d=%d
63",printf("%d/%d=%d
64",}叮\!/\1/\!/书r/•1J«1J-1J-1J+-*/**1**11•11•11//.9n•1J-1J«1J-1J\\\!/•j的指标&i,&j*/Enter2integers:204Now,Ifindthat...20+4=2420-4=1620*4=8020/4=5ー相当于i=20,j=4scanf在读取多笔数据时,是把调位字符(如:空白、定位(tab)及换列字符)当作数据的分隔的记号,也就是利用scanf输入多笔数据时,必须用调位字格分隔输入的数据。如本例中,输入的i值与j值,可以用空白区隔,也可以用换列或定位来区隔。在结束输入时则要用换列字符,也就是说要按Enter〇进阶的程序设计师通常不会用scanf作为数据的输入,因为只要输入的格式有ー点点错误,scanf所得到的结果就无法预期。大部分的程序设计师会用gets()这个函式读入字符串,gets是以换列字符作为结束记号,所以,利用gets可以读入包含空白及定位的字符用。读入的字符串可以用atoi()转成整数、ヵ]atol()转成长整数、用atof()转成浮点效。更进阶的程序设计师则是自行设计监入函式,并加入一些设定防止输入错误发生,例如,在输入整数的函式中,使用者只有按下数字键オ有反应,若按下非数字键,则不会反应。也可以限定使用者输入的数据长度,防止输入的数值过大,等等。以下的范例,将华氏温度(下)换算成摄氏温度(C)f2c.c1#include
65scanf("如",&f);/*用f的指标&f=1=/c=(f-32)*5/9;/・换算公式・/printf("%ddegreesinFis%ddegreesinC.",f,c);EnterthetemperatureinF:100100degreesinFis37degreesinC.华氏温度ピF)与摄氏温度(C)的互换公式如下:C=(F-32)*5/9F=C*9/5+32以下是课本的范例,将年纪改用"日"来估算:age.c10#include
66格式化输出至stdoutprintf的语法必须#include
67",ch);printf("Character%chasASCIIcode%d.
68",ch,ch);A--YoutypedA.CharacterAhasASCIIcode65.这个范例主要是用来査询•般字符的ASCII码,请勿输入方向键,否则它的结果可能会让你失望。因为方向键及功能键等特殊按键会产生两个码,必须读两次才能得到正确的结果。第9行,用%c的控制字符,表示要秀出ch所代表的字符;用%d的控制字符,表示要秀出ch所代表的数值。☆练习实作课本习题第!0题,看看你所得到的结果与课本所列的的结果ー不一・样?☆作业■Help参考数据:Helpprintf:formattedoutputtostdoutintprintf(constchar*format,...);Prototypeinstdio.hPrintformatsavariablenumberofargumentsaccordingtotheformat,andsendstheoutputtostdout.Returnsthenumberofbytesoutput.Intheeventoferror,itreturnsEOF.SeealsoecvtfprintfputcputsscanfvprintfHelpFormatSpecifiers%[flags][width][.prec][FINIhl1]typecpydiouXXfegEFormatofOutputsigneddecimalintsigneddecimalintunsignedoctalintunsigneddecimalintinprintf=unsignedhexdecimalintlowercase;inscanf=hexadecimalintinprintf=unsignedhexdecimalintuppercase;inscanf=hexadecimallongfloatingpoint[-]dddd.dddfloatingpoint[-]d.ddde[+/-]dddformateorfbasedonprecisionsameaseexceptEforexponent格式化输出的型别:di〇uXXfegE带正负号十进制整数带正负号十进制整数不带正负号八进位整数不带正负号十进制整数不带正负号16进位整数(小写)在scanf为16进位整数不带正负号16进位整数(小写)左scanf为16进位长整薮浮点数例:314.159浮点数例:3.14159e2由精度决定用f或e的格式同e只是以E表示指数符号
69GsameasgexceptEforexponentcsinglecharactersprintcharacterstill'\0'or[.prec]%the%characterppointer:near-YYYY;far-XXXX:YYYYnstorescountofcharacterswrittensofarinthelocationpointedtobyinputargument[flag]WhatitSpecifiesnoneright-justify,pad0orblanktoleft-left-justify,padspacestoright+alwaysbeginwith+or-blankprintsignfornegativevaluesonly#convertusingalternateform:c,s,d,i,unoeffect〇0prependedtononzeroargxorXOxorOXprependedtoarge,E,falwaysusedecimalpointgorGsameasabovebutnotrailingzeros[width]EffectonOutputnatleastncharacters,blank-paddedOnatleastncharacters,0leftfill*nextargumentfromlistiswidth[.prec]EffectonOutputnonedefaultprecision.0d,i,o,u,xdefaultprecisione,E,fnodecimalpoint.natmostncharacters*nextargumentfromlistisprecisionModifierHowargisInterpretedargisfarpointerargisnearpointerd,i,o,u,x,Xargisshortintd,i,o,u,x,Xargislonginte,E,f,g,Gargisdouble(scanfonly)e,E,f,g,GargislongdoubleGcs%Pn同g只是以E表示指数符号单一字符打印字符直到‘、。’或指定长度打印%这个字符指标:近YYYY远XXXX:YYYY将目前已经打印出的字符数值传给输入的参数。在此,输入的参数必须是整数指标。[旗标]无靠右对齐不足在左边补空白或〇•靠左对齐不足在右边补空白+正负号一定会秀出空白只有负数オ会秀出负号#转换格式.对CjS.d.i,u没有影响〇如果数据不是〇就会先秀〇x,X在资料前加秀Ox或0Xe,E,f会秀出小数点g,G会莠出小数点,但是不补。[宽度]n指定输出的宽度,不足补空白On指定输出的宽度,不足在左补〇・由下ー个参数决定宽度[.精度]无内定的精度.0d,i,o,u,x是内定的格式e,E,f表示没有小数.n指定n个字符长度・由下ー个参数决定精度输入大小修饰词FNh111指指整整精远近短长倍标标数数数scanf)L长倍精数
70Helpscanf:performsformattedinputfromstdin由stdin读入格式化的数据intscanf(constchar*format,...);scanf的语法Prototypeinstdio.h必须#include
71・第五章流程图与抉择指令前一章的scanf好不好用呢?在多笔数据输入时,不小心输错ー笔数据,可能会导致后面的读到的数据都是错的。而错误的输入数据,自然会使输出的数据也是错误的,这就是所谓的「垃废进、拉協出」(GarbageIn,GarbageOut)〇如巢程序能分辨辎入的数据是否正确,如菓是错误的或是超过嵬围的,就可以要求很用者再输入・次。要达到这个目的,我们必须使用「判断」以及「循环」。本章将介绍如何用C来做判断,有关循环的部分参考下一章。◎预习课程:流程图(FlowChart)在进入本章之前,先介绍流程图。流程图不只可以用在程序的流程设计,也可以用在任何事件,例如:计划执行的流程图、休闲计划流程图等等。在程序设计上,小程序也许不用流程图。但是中、大型程序最好要有流程图,有了流程图,可以进ー步检视你的设计,看看是否在逻辑上有问题,看看那个部分可以再加强,那个部分可以简化,因为看流程图比看原始码要容易除错。另外流程图设计得好,程序的部分就显得相当简单了,只要把流程图的符号用对应的程序流程控制叙述取代,程序的架构就完成了。隔了・段时间,若须要增加或修改程序部分功能,有留下流程图,就可以快速进入状况,找到要修改的部分,并新增程序。以下介绍6种常用的流程图符号:意义符号表示流程图的开始或结束,每个流程图必须以开始符号开始,以结束符号作结束。〇开始/结束符号开始流程图的开始结束流程图的结束〇输入/输出符号I,I.意义例子Z输入//a,b,c///读入三笔数据;并存在a,b,c三个变数内。表示计算机与外界的连系,通常程式需从外界输入数据,程序再将执行后的结果输出给使用者。在符号中,输入数据时要注明是「输入」,在输出数据时要注明是「输出」。/输出/a,b,c将变数a,b,c的数值输出。意义符I,I.表示各种算术、函数的运算。在ー・个处理符号内可表示多个运算。〇处理符号F=100;C=(F-32)*5/9;
72〇抉择符号意义/条件、NoYesI表示各种算术、逻辑或关系运算,程序执行到这个地方必须做・决定,此项决定由符号内的条件来判断。当条件成立时,则程序流程依Yes的方向指示继续执行;当条件不成立时,则程序流程依No的方向指示继续执行〇在这个菱形符号的四个角,」二面的角通常是被上面的流程符号所指,其它的三个角,你可以任选两个角做Yes及No的流程指向,只要标明清楚就可以了。/a>=b\No当a大于或等于b时执行c=5;的运算,否则执行c=0;的运算。〇流向线意义箭头方向表示程序执行的先后次序。scanf("%d%d",&a,&b);/a>=b\NoYesI〇连接符号I,I.意义例子的远会流绘以字到字是间较往时来可或看数们空比往有页就字方别它到到线,多号数地识示受流向乱许符个的的表会需流较要接ー同们就常线的比须连有不它,,向长来能用会在要的时流种起可利。内。只同图时这看,,线号别,相。程有。图大时向符识号是的流,方程很这流接为符母接制制地流图,化连做接字连绘限的使程制简在母连或相/a>=b\No\/*\/YesI/\/b>=c\No\/一\/YesIic=l;一<——/\/a>=b\No\/——\/YesI
73/天气、\?/晴天看报纸看电影吃中饭◎关系与条件在数学上任两个数值一定会符合(•三一律」,什么是「三一律」?假设两个数:ー个是a,ー个是b,那a跟"的关系一定是下列三种的某ー种:a大于b;a等于b或a小于b=在计算机程序中,常常要判断数值间的关系,例如:一些游戏软件会在一开始要求你输入密码,输入的密码与正确的密码相等,游戏オ会继续执行;或是机密性的数据库管理系统会要求输入密码,系统再依输入的密码给予相对的权限,如:总经理可以看到全部的数据,一一般员エ只能看自己的数据。在C语言中提供了下列的关系运算子,让程序设计师判断两个数值的关系:关系运算子意义例子状况>大于a>ba是否大于b?<小于a
74两个数的关系符合三一一律,所以,当你使用上述任一个关系运算子时,所指定的状况不是成立,就是不成立。指定的状况成立,我们称之为「真(True)」,状况木成立,.我们称乏为「膜(false)」。左C语言中,假(False)是用〇来表示。不是假的,就是真的,所以,所有非〇的值,在C语言中都表示真(True)。★注意:在C语言中=是设定运算子;=是关系运算了,两者不可混用。a=3;a的数值设为3a=3a是否等于3?a等于3则此关系式为真,否则为假。◎if叙述if叙述可用来作基本的抉择:/\No/条件测试、—ヽ?/不、/成、/立I成立IYesi指令群如果某个条件成立,则要做某事。例:如果天下雨的话,我就要带伞。条件要做的事if叙述的型式如下:if(条件测试){指令群}意义:如果(条件测试)是成立的,则执行{指令群}。〇指ル群?在C前言中,所谓的指令群,乃是由数个(包括0个,1个,...)指令括在ー•对大括号中而形成。イ列如:{}►;空指令{~人i=i+1;-i=i+1;单一指令1-(i=i-1;j=i*2;}这三者都可以称为指令群。指令群的后面不必以分号做为结束,因为右大括号便足以代表结尾在何处了。当指令群内只有一个指令时,我们也可以将这・对大括号省略,此时,该指令群便与一般指令无异。当指令群内没有任何指令时,如果你要省略这对大括号,就要补上一个分号(;),表示是空指令。以下的范例,将使用者输入的数值取绝对值后再秀出:abs.c#include
75printf("Enteraninteger:");scanf("%d",&i);if(i<0)i=-i;printf("Theabsolutevalueofitis%d.
76",i);Enteraninteger:-100Theabsolutevalueofitis100.绝对值的定义:i,若i>=0-i,若i<0所以在程序第8行,当i<0成立时,就令i=-i,这样i就成为正数了。◎二重选择题:if-else叙述.No/条件测试\Yes不—ヽ?/—成成、/立立I\/只有if只能设定条件成立要做的事,再加上else则可设定条件不成立时要做的事。if-else叙述的型式如下:例如:如果好天气,就出去逛街,否则,就在家看电视。if(条件测试){指令群1}else{指令群2)意义:如果(条件测试)是成立的,则执行{指令群1};否则,执行{指令群2}以下是课本的范例,将使用者输入的两个数值找出最大值后再秀出:maxi.c1#include
77",i,j,max);H)Enter2integer:75Themaximumof7and5is7.
78◎多重选择题:if-elseif架构当状况不只一种时,光是if-else就不够用了。在C中,可以在else之后再加上if-else的架构,如此,就可多一个判断。同理,可在所加的else之后再加上if-else,直到所有状况都包含为止。如:如果气温小于20度,就穿两件衣服;气温小于!5度,就穿三件衣服;气温小于!0度,就穿四件衣服。if-elseif架构;1穴条件测试1){指令群1}elseif(条件测试ラ){指令群2}elseif(条件测试3,(指令辞3)elseif...else{指令群n}意义.如果(条件测试1)是成シ的,则执行否则,如果(条件测试2)是成立的,否则,如果(条件测试3)是成立的,•,群群-令令亍亍扌执执不成立否则,只好执行{指令群n}
79以下的范例,仿真高速公路交通警察执勤状况。police.c#include
80");10elseif(speed<90)11printf("Goodday,boss.
81");12elseif(speed<100)13printf("Toofast,slowdown!
82");14else15printf("Iwi11giveyouaticket!
83");16)Enterthespeed=50Tooslow,speedup!Enterthespeed=80Goodday,boss.Enterthespeed=95Toofast,slowdown!Enterthespeed=120Iwi11giveyouaticket!这类的程序,在设计时要注意到条件测试的顺序,否则,答案可能会有问题。如:将第12行与第8行的判断式对调,秀出讯息的第13行与第9行也对调:if(speed<100)printf("Toofast,slowdown!
84");elseif(speed<90)printf("Goodday,boss.
85");elseif(speed<60)printf("Tooslow,speedup!
86");elseprintf("Iwi11giveyouaticket!
87");这样的话,程序只会有两种输出:speed<100,秀出Toofast,slowdown!speed>=100,秀出Iwillgiveyouaticket!如果你无法确定你写的程序对不对,那你最好画画流程图来帮助判断。此程序的判断流程如下:
88/输入车速//\No表示车速三60/小于、1\60/I/\No表示车速三90/小于、1\90/I以下是课本的范例:ー个简单的四则运算计算器。calc.c1011121314151617#include
89");scanf("%f%c%f",&numl,&op,&num2);if(op='+')printf("%f+%f=%f
90",numl,num2,numl+num2);elseif(op='-')printf("%f+%f=%f
91",numl,num2,numl-num2);elseif(op=)printf("%f+%f=%f
92",numl,num2,numl*num2);elseif(op='/')
93181920printf("%f+%f=%f
94",numl,num2,numl/num2);)}Enternumber,operator,number4+84.000000+8.000000=12.000000Enternumber,operator,number5*75.000000+7.000000=35.000000AC在这个程序中,会读取二个数值以及ー个运算符号,接着判断运算符号是否是+-*/之中的ー个,如果是的话就作相对应的运算,并将结果输出。另外,第7行使用了下一章オ会提到的「循环」。这个程序会不断的执行,你必须按下Ctrl+Break或Ctrl+C才能中断它。☆有关r抉择」☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆仝前面所讲的抉择判断式子都相当简单,以下介绍三种c语言提供的方式,可以让你的「抉择」多样化。◎逻辑运算子〇&&AND假设有一个表达式:expl&&exp2则此表达式的结果为真的条件是expl为真且exp2也为真;否则此表达式的结果为假。〇!IOR假设有一个表达式:expl11exp2则此表达式的结果为真的条件是expl为真或exp2为真;只有在expl为假且exp2也为施时,此表达式的结果オ为假。〇!NOT假设有・一个表达式;!exgj则此表达式结果为真的条件寫expl为假;而当expl为真时,此表达式的唐果就是假。◎小括号指定叙述任何用小括号括住的指定叙述是一个表达式,它的值与指定值・样。例如:表达式(sum=5+3)的值为8,所以表达式((sum=5+3)<=10)结果为真,因为(8<=10)。◎逗号运算子你可以利用逗号运算子(J把多个表达式放入括号内。表达式由左至右执行或计算,整个表达式的值以盘后一个的值为准。例如;表达式(i=l,j=2,k=i+j)的值为k也就是3,因为,免设了i二1,再指定j=2,最后令k=i+j,所以k的值为3,因为k=i+j是最后一个叙述,所以这个表达式的值就等于k也就是3〇
95应用:yes.c#include
96Youpress%c.
97",ch),printf("continuexxxxxx...
98");elseprintf("
99Youpress%c.
100",ch),printf("stopxxxxxx!
101");PressYorytocontinuexxxxxx...yYoupressy.continuexxxxxx...PressYorytocontinuexxxxxx...qYoupressq.stopxxxxxx!在这个程序中,会要求使用者输入ー个字符,如果.输入的字符是Y或y则秀出Youpressy.continuexxxxxx...类似程序继续执行窠种程序;如果输入的不是Y也不是y,则秀出YoupressX.stopxxxxxx!类似程序停止执行某种程序。行中,ch=getche())="Y'11ch="y')1由键盘读入・个键值,并存到chし一整个小括号的值就等于ch所以上式可以简化为if(ch='Y'IIch='y')也就是,如果ch等于’Y’或‘y'则此判断式为真,否则为假。两1号彳大9逗以第后第用是果令在是则如指h/IZTcヨフ。第"1在
102労第要C即ス就-XXIRRssヨE9,e天宅エ、在戸士口:一口K纟口uffiYO,表イ,(''尾尾•,起tf结结.in为作号}r乍・p^iXI/Z7{.>;用ユア结是来令む旨扌10行,ー了41{printf(
103Youpress%c.
104,ch);printf("continuexxxxxx...
105");}同理,在第12行与第!3行也用了相同的方法。各位也许会发现:第9行与第!2行的程序代码完全相同的!没错,你可以想办法将第9行程序代码移到if之前,并删去第12行程序代码,这样程序就可以减小。本例只是用一下逗号运算子,所以オ将程序写成这样。
106在这里,并不是要各位把程序写得很难看懂,而是希望各位能看得懂别人所写的程序,了解・些程序设计师可能的用的「技巧」或「手段」。以上的程序,我们也可以改写如下:yes2.c10111213141516171819#include
107Youpress%c.
108",ch);printf("continuexxxxxx...
109");)else(printf("
110Youpress%c.
111",ch);printf("stopxxxxxx!
112");)这样子写,虽然程序比较长,但是在大的【注】,只是程序代码比较长,le较PLU瞿c却之后产生的.exe档是ー模・样「好看」。1【注】用TC整合环境所Compile出来旳.exe.文件中包含了除错信息(DebugInformation),宼些除错宿息包含了原始码的行号数据,因为yes.c与yes2.c的行数不同,它们的行号数据就不会相同,所以用TC整合环瑙编译出来的执行檔大小是不同的。我们可以用命令歹リ编译程序tcc来编译yes.c及yes2.c:DOS_Prompt>tccyes.cDOS_Prompt>tccyes2.c如此,产生的yes.exe及yes2.exe的档案大小就是一-样的了。•第六章循环与自动重复前一章,已经用了for循环来写程序,让程序依需求重复执行某些程序代码。在C中有许多种循环,本章就以for循环为主,介绍循环设计的技巧。◎for叙述〇for叙述的格式如下:for(指令—•;条件测试;指令二){指令群}注意:在for后而有对小括号,小括号里面的东西用分号隔成三个部份,这二个分隔用的分号绝对不可以省略掉。〇for叙述的意义:1.先执行「指令一」。2.测试看看「条件测试」是否成立?如果成立,则执行{指令群):否则,结束自动重复的动作。
1131.在执行完{指令群}后,执行「指令二」,然后回到2。〇for叙述流程图:/\不成立/条件、\测试/\/指令群在这里,指令一及指令二都是单・指令,如果你要作多项设定,那就要用到上一章最后所讲的「逗号运算子」,可以将多个指令写在・起。〇常见for叙述的用法:for(i=0;i<100;i=i+1)printf("i=%3d
114",i);for(i=0,j=0;i<100;i=i+1,j=j+2)printf("i=%3dj=%3d
115",i,j);Ofor叙述常用的格式:for(初值设定;条件测试;变化){指令群}〇for叙述常用格式的意义:1.首先依「初值设定」的要求,设定你所指定变量的值。2.测试看看「条件测试」是否成立?如果成立,则执行{指令群):否则,结束自动重复的动作。3.在执行完{指令群}后,按照「变化」的要求,改变指定变量的值,然后回到2。〇for叙述常用格式的流程图:
116〇省略的for叙述:for(指令一;条件测试;指令二){指令群}在for叙述中,指令一、条件测试、指令二以及指令群这四者都可以省略,△省略指令一:以常用格式来说,就是不做初值设定。初值可在for之前设定,或者不用做初值设定。△省略条件测试:表示不做条件测试,重复执行{指令群}。我们通常称这种循环为「无穷循环」。△省略指令二:以常用格式来说,就是不做变量数值的改变。变量数值可以在指令群中改变。△省略指令群:表示空循环,可用于时间延迟(delay)。若连大括号都要省略,则要补上分喜(;)表示空指令。for叙述括号内的指令是可以省的,但是分隔用的分号(;)则不能省。以下是课本的范例:秀出ASCI!码及相对应的字符。ascii.c
117#include
118进入循环前555!=5n初值设定545!=5第1圈后5*445!=5x4第2圈后5*4*335!=5x4x3第3圈后5*4*3*225!=5x4x3x2第4圈后5*4*3*2*115!=5x4x3x2xl离开循环后5*4*3*2*115!=5x4x3x2xl=120◎重复中有重复在for叙述所要重复执行的指令群中,也可以再含有另一个for叙述,于是便形成了重复中有重复的情形。•般我们称for叙述及所重复的指令群为for循环,而这种重复中有重复的情形,便称为巢状(nest)循环。(课本称为套迭式循环)在使用巢状循环时,最好使用缩排的编辑及巧,让你的程序更好看:叙述;for(...;...;...)(叙述;for(...;...;...)(叙述;}同样的技巧可以用在巢状if叙述,或其它类似的叙述。巢状循环可以多层,但是,各个循环之间绝对不可以交叉。以下是正确的巢状循环:I"for(...("for(for(
119)}for(...Ifor((for(...(!)1以下是不正确的巢状循环:以下的范例:印出九九表99.c#include
120");)11x1=12x1=23x1=34x1=45x1=56x1=67x1=78x1=89x1=91x2=22x2=43x2=64x2=85x2=106x2=127x2=148x2=169x2=181x3=32x3=63x3=94x3=125x3=156x3=187x3=218x3=249x3=271x4=42x4=83x4=124x4=165x4=206x4=247x4=288x4=329x4=361x5=52x5=103x5=154x5=205x5=256x5=307x5=358x5=409x5=451x6=62x6=123x6=184x6=245x6=306x6=367x6=428x6=489x6=541x7=72x7=143x7=214x7=285x7=356x7=427x7=498x7=569x7=631x8=82x8=163x8=244x8=325x8=406x8=487x8=568x8=649x8=721x9=92x9=183x9=274x9=365x9=456x9=547x9=638x9=729x9=81九九表是1到9的两个数相乘,ー个是乘数,ー个是被乘数,因此,
121我们需要两个循环,i=l要乘以1到9、i=2也要乘以1到9、...,所以要用巢状循环的方式来处理这个问题。第9行的printf("%dx%d=%2d",j,i,j*i);是属于内层循环,也就是在某ー个1值,j要由]变化至リ9〇第10行的printf("
122");是属于ホ层循环,在内层循环执行完之后,就跳下・行。◎跳出循环:break叙述有时,我们可能在重复执行到・半时,检测到某个情况发生,而希望提早结束重复的动作,便可以利用break叙述。break叙述的功能相当单纯,它用来跳出ー层的循环。注意!它只能跳出ー层循环。如果你使用两层的巢状循环,那么在内层的break只会跳出内层循环,在外层的breakオ会跳出外层循环。〇Ctrl+C或Ctrl+for(...(for((if(...)break;}…if(•••)break;1Break中断按键当程序进入无穷循环时,在某些状况下,你可以按下来中断程序的执行,但是在某些状况下,即使你按下/*外层循环开始・//*内层循环开始・//・跳出内层循环・//・内层循环结束・//・跳出外层循环・//*外层循环结束・/Ctrl+C或Ctrl+BreakCtrl+C或Ctrl+Break也没有用,只有重开机才能中断程序执行。所以,在程序中最好能正常结束,例如:使用者按下q键或x键表示结束程序等等,若你要使用无穷循环,最好能确定用Ctrl+C或Ctrl+Break可以中断程序。☆其它的循环☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆翁除了for以外,C语言还有while循环及do...while循环。◎while循环〇while叙述的格式如下:while(条件测试){指令群}〇while叙述的意义:1.测试看看「条件测试」是否成立?如果成立,则执行{指令群):否则,结束自动重复的动作。2.执行完{指令群}后,再回到1。
123Owhile叙述流程图:我们可以把while循环用for循环来表示:while(i<10)for(;i<10;)({}...}…◎do...while循环Odo...while叙述的格式如下:do(指令群}while(条件测试);〇do...while叙述的意义:1.先执行{指令群}。2.测试看看「条件测试」是否成立?如果成立,则执行{指令群):否则,结束自动重复的动作。3.执行完{指令群}后,再回到2。〇do...while叙述流程图:
124while循环与do...while循环最大的不同点在于:while循环要先条件测试,成立オ执行指令群,而do...while循环则是先执行指令群,オ条件测试,成立再・次执行指令群。
125•第七章数组与指针数组是由一群相同型态的变量所组成,当你需要一堆相同型态的变量时,用数组是最适合的。例如,要储存全班50位同学的成绩,那就需要50个变量,如果要・个ー个宣告,那就太没有效率了。这时就需要用数组了。指针则是指向变量或数组地址的运算子,任・变量或数组的数值均可经由指标的运算获得。◎数组的宣告数组宣告的格式如下:变量型别变量名称[元素个数];以储存全班50位同学的成绩为例,用整数来存成绩:intscore[50];C语言中,数组的索引值是由0开始的,所以这50个变量为:score[0],score[l],score[2],score[48],score[49]〇以下的范例:读取・周的气温,再求出其平均值。temper.c#include
126",sum/7.);1Enterthetemperatureforday122Enterthetemperatureforday220Enterthetemperatureforday318Enterthetemperatureforday419Enterthetemperatureforday523Enterthetemperatureforday624Enterthetemperatureforday726Averagetemperature=21.714286sum=0;for(day=0;day<7;day-H-))在第四章中,我们曾经列出各种变量型态的指针,以上面的例子:
127位址记忆体指标假设地址&t[0]一►皿]-t+0(1000)h&t[l]--".tロ]*t+1(1002)h&t[2]—~►皿]*t+2(1004)h&t[3]―►心]*t+3(1006)h&t[4]>t[4]-t+4(1008)h&t[5]一"►.2]*t+5(100A)h&t[6]>!也]|*一t+6(100C)h我们利用第10行scanf("%d",&t[day]);读取数据,这里用的是每ー个数组兀素的地址&t[day],day由。到G。我们也可以改用指标的方式:scanf("%d".t+day);这里的t是数组变量的名森,也就ー•个指标常数(constantpointer),在宣告数组变量的同时,就宣告了这个指标常数,只是这个指标常索的数值不是由你决定的,而是在程序执行时,它的数值オ会确定,イ旦确定,就不会改变。t+day的day是t指标的增加值,假设t为(1000)h,那t+1是(1001)h吗?C语言在作指针运算时,会依指标的型别不同,而改变递增或递减的数值。以t+1来说,t是ー个整数的指标常数,在TC2中一个整数占有2bytes,所以t+!的数值是(1002)h,而不是(1001)h。同理,t+2的数值是(1004)h〇在上例第17行,printf("Averagetemperature=%f
128",sum/7.);不知道你有没有注意到sum/7.在7后面的一点(.)?这并不是Keyin错误,而是故意的。因为sum是ー个整数变量,若写成sum/7表示整数除以整数,那结果还是整数。故意写成sum/7.就变成整数除以实数,那结果会是实数。即然是平均值,通常会有小数,所以我们用%f来秀出数据。◎字符串作为字符串结束记号。例如,我们要用一个字符串存DOS的文件名:字符串是ーー堆字符所组成的,它是一个字符数组,只是字符串它还要有个‘、〇’字符,的结束字符,所以,总共需要12+1=13个字符:DOS的檔名是主檔名最多8个字符,扩展名最多3个字符,中间以句号(.)分隔,所以需要8+3+1=12个字符来存盘名。但是别忘了字符串要有’、〇'charfilename[13];你可以用以下的程序片断来询问文件名:printf("Enterthefilename:");scanf("%12s",filename);scanf是要变量的地址,而filename[13]这个变量的地址就是filename,你也可以用&filename[O]。另外,用%12s这个句柄,表示读入的字符串只取前面12个字符再加上’'〇'字符,传给后面所指定的地址。如果你不加,12而用%s的话,当使用者输入超过13个字符时,将会发生不可预期的后果。
129以下的范例:读取ー个字符串并作输出。string.c#include
130");printf("Pleaseenterthecoordinate(00)-(94):");
1311819202122232425262728scanf("%d%d",&x,&y);/*读取指定坐标・/matrix[y][x]=<*';/・设定指定坐标・/for(y=0;y<5;y++)/・秀出数组值・/(for(x=0;x<10;x++)printf("%c",matrix[y][x]);printf("
132");Enterthecoordinate(00)-(94):53*....一因为索引值是由〇开始所以・在6,4第14行到第19行是利用ー个for循环来判断输入的数值是否在要求的范围。在使用数组时,最好要注意•下使用索引值的范围,因为C不会做数组边界检査,当你使用大于你所宣告的索引值时,在语法上,并不会有任何的错误。但是当你使用索引值超过你所宣告的的数组时,你有可能改变到别的变量,甚至是程序代码。轻微的话,只是程序结果错误,严重的话,可能导致当机。☆两维数组的指针☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆以ints[5O][3]i为例位址记忆体指标假设状况&s[0][0]-As[0][0]«—*(s+0)+0一S+0-s(1000)h&s[0][l]-As[0][l]■*—*(s+0)+1(1002)h&s[0][2]―►s[0][2]—*(s+0)+2(1004)h&s[l][0]-As[l][0]<―*(s+1)+0-S+1(1006)h&s[l][l]-As[l][l]«—*(s+1)+1(1008)h&s[l][2]-As[l][2]■*—*(s+1)+2(100A)h&s[2][0]―►s[2][0]—*(s+2)+0一S+2(100C)h—&s[48][2]s[48][2]一*(s+48)+2(30h*3+2)*2(1124)h&s[49][0]s[49][0]一*(s+49)+0一S+49(1126)h&s[49][l]一s[49][l]一*(s+49)+1(1128)h&s[49][2]一s[49]⑵-*(s+49)+2(112A)h
133S是ー个二维指标常数。一个ー维指标,我イ门必须在指标前加一个星号(*)才能取得・维数组内的变量值,同样地,在二维指标,我们必须在指标前加二个星号,才能取得二维数组内的变数值。若是二维指标前的星号少于二个,例如,没有星号或只有・个,那它所表示的就还是・个指标。另外,二维指标前如果有一个星号,那就相当是降了一维,而成为ー个ー维指标。〇二维指标的递增值ー个ー维指标,如果它所指的变量型态占有n个byte,那这个・・维指标的递增值就是n〇―•个二维数组:vartypeArrayFX][Y];如果vartype占有n个byte»那Array这个二维指标的递增值就戛Y*n,也就是Y个vartype所占的空间。Array是指向二维数组的开端&Array[O][O]»而Array+1正好指向&Array[l][O]»同理Array+i是指向&Array[i][0]o如前所述,在二维指标前加一个星号就会变成一维指标。所以ン*Array是个ー维指标、*(Array+l)是ー一维指标、...、・(Array+i)是,ー维指标、...、*(Array+(X-l))是ー・维指标,而这些•维指标都是指向第二维数组开始的地址。其中的〇三iW(X-l),如同决定Array[X][Y]中第一维(X)的位移量(Offset)。这些ー维指标的递增值・Srray+i)、...、・(Array+i)+j、…、・(Array+i)+(Y-l)就指向第二维的每一个变畳。其中的OWj三(Y-1),如同决定Array[X][Y]中第二维(Y)的位移量(Offset)。所以,*(Array+i)+j就是指向Array[i][j]这个变量,同时*(*(Array+i)+j)就是Array[i][j]这个变量。ints[50][7];★C语言不会作数组边界(Boundary)检査,例如,你宣告可是你可以使用s[0][8]>s[51][2]或s[100][200]o〇用指标的方式,修改上例,你看懂了吗?demoptr.c#include
134");printf("Pleaseenterthecoordinate(00)-(94):");scanf("%d%d",&x,&y);/・读取指定坐标・/matrix[y][x]=;/・设定指定坐标・/for(y=0;y<5;y-H-)/*秀出数组值・/(for(x=0:x<10:x++)24printf("%c",*(*(matrix+y)+x));25printf("
135");26}27)
136・第八章函数与呼叫C语言的程序,是由一•堆函数(Function)或函式(Routine)所组成的。什么是函数?以sin这个函数为例:sin:sinefunction正弦函数。doublesin(doublex);sin的语法Prototypeinmath.h必须#include
137结束函式的执行。参数(或称自变量)可以使函式具有变化性,如果省略,则表示此函式不需要参数。〇养成好习惯如果省略传回值型别,等于定义了整数型别,那要是我们所设计的函式没有传回数值,应该怎么办呢?在C语言中,有一种资料型别叫void,void表示「空」的数据型态,所以void函式名称(型别参数1,型别参数2,...))就表示这个函式没有传回任何数值。同样地,如果设计的函式不用参数,也可以用void来表示:传回值型别函式名称(void)}就表示这个函式不需要任何参数。◎呼叫函式C语言在使用变量或是函式之前,都必须先宣告所使用的变量或是函式。这也是为什么,我们优写的程序都要#include
138void既然是「空」的数据型态,所以在呼叫时就是「空的」。如果,你还记得的话,getche()会传回使用者所按下的键值,但是在这里,我们只是要使用者按下任意羅,所以读入的键值是多少我们并不在意,可以不管它,就如同呼叫不会传回数值的beep()函式一样。printf()也是有传回值的,它传回输出的byte数,而这个数值,我们通常也不会在意。以下是课本的范例:以条形图来比较数值的大小。bar.c#include 139");}/*/・秀出i个星号・/10bar()定义结束・/1112voidmain(void)13(14printf("Merry\t");/・输入参数为30*/15bar(30);16printf("John\t");/・输入参数为40*/17bar(40);18printf("Johnson\t");/・输入参数为20*/19bar(20);20printf("Sposh\t");/*输入参数为50*/21bar(50);22)hiej*j*y******************************john****************************************Johnson********************Sposh**************************************************各位可能会发现,课本在宣告bar()函式时,好像跟老师所用的不一样:bar(i)inti;/・宣告参数的数据型别・/1这种宣告参数的方式,是旧的C语言格式,目前的TC仍然可以使用。在呼叫有参数的函式时,给定的参数会代入函式中相对的变数。如:bar(30);就是给定30作为输入参数,此例来说,就是先设定i=30,再开始执行第5行以后的指令。 140以下是课本的范例:计算圆面积的副函式。area.c#include 141",areas(radius));15}Entertheradius=6Areaofthiscircle=113.097240在第14行中,areas(radius)表示以radius为参数呼叫areas()函式,areas()会传回・个fioat型别的数值。我彳门可以把areas(radius)整个当晟.个变薮莱看,而它的数值写radius有关。例如,我们要计算两个半径分别为r!及r2的圆面积总和:totalarea=areas(rl)+areas(r2);以下是课本的范例:求任意二个整数的最大值。max.c#include 142",i,j,max(i,j));1Enter2integers:68Maximumof6and8is8.事实上,TC2有提供max()这个函式,你可以在TC的整合环境下的编辑窗口内输入max,将光标移到max字上,按下Ctrl+Fl就可以看到说明HelpMacros:max,min宏指令:max,minThesemacrosgenerateinlinecodetofind以宏的方式求得两数 143themaximumorminimumvalueoftwo的最大值或最小值。integers.max(a,b)maximumoftwointegersaandb求a,b的最大值min(a,b)minimumoftwointegersaandb束a,b的最小值Definedinstdlib.h必须#include 144",i,j,max(i,j));11)Enter2integers:68Maximumof6and8is8.在这里只是要告诉各位,TC它有提供非常多的内建函式,有一些功能我们并不须要再去设计・次。如果要作练习,那就另当别论。建议有意要写程序的人,多多参考「参考手册」,大略知道所使用的语言提供了那些内建函式,要用时,只要依照它的格式来呼叫它就可以了。要不然,你可以花了许多时间在写一个内建函式,而知道的人,只要#include??.h就可以直接使用它。◎整体变量(GlobalVariable)在前面的例子中,所有的变量都只能在所宣告的函式内使用,函式与函式之间只能用传回值或是参数来传递数值。除了用传回值与参数外,在C语言中还可以使用「整体变量」。什么是「整体变量」?由字面上来看,就是适用于程序整体,都可以使用的变量。相对于整体变量的就是「区域变量(LocalVariable)J〇同样地,由字面上来看,就是只适用于程序的某ー个区域所飽使用的变量。我们要如何判断变量可以使用的范围呢?以下就来谈谈变数的生命周期。以ー个副函式来说:voidsubl(void)inti;变数i的「生」 145变数i的「灭」我们所写的函式,都会用ー对大括号{...}括起来,而在大括号内宣告的变量,就适用于大括号内。当这个函式执行结束时,在大括号内所宣告的变量,也就消逝不见。这种变量,就是区域变量,它能活动的区域,就是在所宣告的大括号内。事实上,在TC2.0中,你可以在函式中任意加入ー对大括号(},在大括号中,前面可宣告变量,之后可以是程序代码。改写前面bar.c为碗:barz.c#include 146");/・旦告printf()的原型・//・开始定义bar();j++)printf("*");/*秀出i个星号10111213141516171819202122voidmain(void)(inti=50;bar(i);(inti=20;bar(i);i=i+10;bar(i);)i=i+10;bar(i);/・使用外层的i为50・//・使用内层的i为20*//・使用内层的i为30*//・使用外层的i为60・//Z;供介期内.1生周外层i的生命周期/*bar()定义结束在主程序中,故意宣告两个同名的整数变量i,它们分别在两组巢状的大括号内。在外层面i适用于輕个main()函式。不巧的是,内医大病号也宣告了一个i,使得在内层的程序代码只能使用内层宣告的io内层大括号执行结束后,内层的i就寿终正寝,外层的i就又开始有作用了。如果,你在内层不另外宣告i这个变量,那在内层的程序也可以使用外层的i,你可以把第15行的程序代码remark掉,看看结果有什么不ー样。总归一句话,在大括号内所宣告的变量,就是区域变量。随着大括号的结束,这ー区的变数也就失去作用。等到下一次再执行到这段程序代码时,这一区的变数オ会重生。那整体变量要如何宣告呢?由上可知,只要是在大括号内宣告的就是区域变量,那整体变量,就是要宣告在大括号以外的地方。例: 147—#include<...>整体变量mi1,1程参数同样只适用于函式之内vumsiiUMiiiid)(区域变量intj,,式voidsub2(b)是参数,不是整体变量,同样只适用于函式之内1111u,.(区域变量intk;"jvoidmain(void)码{区域变量intc;■☆Cal1byValuev.s.Cal1byAddress☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆OCallbyValue传值呼叫前面我们所设计的副函式都是使用「传值呼叫」,也就是副函式的参数变量不是指针型变量。以副函式bar()为例,我们把它改写如下,它的功能同上例:bar3.c#include 148");1/・旦告printf()的原型・/)/*i值,由传进来的数值递减至0・/10111213141516171819202122voidmain(void)0053==bar(20);bar(j);printfC'j=%d 149"bar(i);printf("i=%d 150"/・以数值20呼叫bar()函式・//・以j变量的数值30呼叫bar()函式・/,j);/*秀出j的数值・//・以i变量的数值50呼叫bar()函式・/,i);/*秀出i的数值・/j=30 151i=50bar(20);表示:把20这个数值传给bar()函式做为参数i的数值,我们可以这样看被呼叫的bar()函式:voidbar(...){inti=20;传进来的数值是20for(;i>0;i--)printf("*");printf(" 152");}*变数i的灭亡bar(j);表示:把j这个变数的数值30传给bar()函式做为参数i的数值,我们可以这样看被呼叫的bar()函式:voidbar(...){inti=30;传进来的数值是变数j的数值30for(;i>0;i--)printf("*");printf(" 153");)变数i的灭亡由于是传入变量的数值,所以不论函式如何改变传入的数值,都不会影响原来传入的变数。请各位不要被变量名称所蒙骗,即使你使用与函式参数同名的变量,它一样只是传值,如范例中的bar(i);表示:把i这个变数的数值50传给bar()函式做为参数i的数值,我们可以这样看被呼叫的bar()函式:voidbar(...){inti=50;传进来的数值是变数i的数值50for(;i>0;i--)printf("*");printf(" 154");)变数i的灭亡总结来说,传值呼叫,就是不会改变所传入变量的数值。如果想要改变传入的变量,就要使用「传址呼叫」。〇Cal1byAddress传址呼叫我们ー・直在使用的scanf()函式,就是一个传址呼叫的函式,其一般型式如下:scanf("控制字符串",&变量1,&变量2,...);我们传给scanfO的参数是变量的地址,所以scanf〇可以把读入的字符串依 155控制字符串的格式转换成数值,存到变量的地址,这样在结束scanfO之后,我们传给scanf()的变量数值,就会是scanf()所读入的数值。前面说过,函式符传回数值只仃・个,而利用传址呼叫的设计、就可以传回更多的数值。以下就来看一个传址呼叫的范例:将两个整数值互换。swap.c1011121314151617181920#include 156",i,j);/・传入i与j的地址・/i=%dj=%d 157",i,j);Beforeswap():i=50jSwappingi&j...Afterswap():i=30j=30=50 158・第九章档案存取前面儿章所写的程序,都是将结果直接显示在屏幕上,若有输入的数值,则利用键盘输入,想要知道程序执行的结果,就要再执行・次。本章则是将程序执行的结果存成档案,存好的档案,你可以直接显示出来看,或者是由程序直接读取数据文件,当作是输入的数值,经运算后,再另存档案。◎档案的观念我们的数据及程序,都是以档案的型式存在磁盘驱动器中。每・种应用程序通常会使用自定的格式来存取它的数据文件,应用程序之间如果没有互相支持,就不能读取对方所产生的数据文件,例如:PEII这个DOS下的文书处理器,就不能读取WORD所编辑出来的档案。在磁盘驱动器中的档案可能很多,在使用时,我们必须先指定要处理档案的名称,作「开启档案」的动作,再依程序设计的格式存取档案内的数据,处理完后,则要「关闭档案」。为什么要这么麻烦呢?因为,我们在作档案存取时,是去呼叫系统程序所提供的程序模块,在「开启档案」后,系统会预置ー些内存空间来存这个开启的档案。你在做档案数据的处理时,系统并不一定会马上将结果存回磁盘,它等预置的记忆体内的数据都处理完时,オ会将数据存入磁盘。所以在使用完档案之后,就要作「关闭档案」的动作,这样,系统才知道你已经不再使用这个档案了,而将预置内存内尚未储存的数据,存入磁盘,再收回预置的内存,供其它程序使用。如果,你不作「关闭档案」的动作,那程序就会一直占用住那ー块内存,形成内存的浪费,此外,处理档案不正常的结束,可能使新增的数据流失,还可能使磁盘驱动器的档案位置配置表(FAT,FileAllocationTable)发生失去链接(LostChain)或是交错连结(CrossLink)的状况。所以,要养成好习惯:在程序中,只要有「开启档案」,就要有对应的「关闭档案」。◎档案的开启和关闭要开启档案时,可以用fopen。其格式如下:FILE*fp.fp=fopen("文件名称","存取模式");在这里,fp是ー个指针,它指向FILE结构变量。FILE结构内存着ー些关于档案的信息,如:档案位置指示,数据传输缓冲区的长度及其在内存中的地址等等,通常我们可以不用去理会这些数值,只要会使用C所提供的档案处理函式,就可以ToFILE*fp;中的fp通常称为档案指标。在使用C所提供的档案处理函式时,只要指定好盾案指标,読是对那个已开启的档案做相对应的处理。fopen()函式的两个参数,第一个是"文件名称",也就是要处理的文件名称,如果不在所执行的目录,就要指定档案的全名,也就是要包含路径。第二个参数是"存取模式",有下列字符串可供选择:存取模式,足、war+w+a+开启•存在档案仅供读取使用。当档案不存在时,将传回错误。开启档案仅供写入。当档案不存在时,会产生新档。开启・个档案仅供增添数据。当档案不存在时,会产生新档。开启一存:在档案供读/写使用。当档案不存在时,将传网错误。开启•档案供读/写使用。当档案不存在时,会产生新档。开启・档案供读取及增添数据。当档案不存在时,会产生新档。另外,还可以再加上b,表示以二进制的模式来存取数据文件。例如:fpl=fopen("letter.txt","w");fp2=fopen("c:WworkWtest.txt","a+");fp3=fopen("score.datfp4=fopen("database.dat","w+b");要开启档案在使用完毕后,可以用fclose来关闭。其格式如下: 159fclose(已开启的档案指标);如:fclose(fp);对于已经关闭的档案,如果还要再使用,则必须重新开启。◎档案的写入要将数据输出到档案时,可以用fprintf〇其格式如下:fprintf(fp,"控制字符串",表达式1,表达式2,...);Ifprintf()的格式如同printf(),只是输入参数中的第一•个参数必须是档案指标,也就是舘定出fprintfO要蛤出到那一个档案。有关printfO请参考第四章。以下是课本的范例:将使用者输入的交易数据,编排成一份报表档案。record.c2222222bO22*»-*>—•9876543210987654321〇987654321#include 160");}voidmain(void){FILE*fp;/・档案指标・/charfilename[20];/*输出报表的文件名・/charclient[40];/・交易对象名称・/floatamount;/・交易金额・/floattotal=0;/・总金额・/printf("Filetorecordtheamount:");scanf("%19s",filename);/*读取输出报表文件名・/fp=fopen(filename,"w");/・幷启报表文件・/if(fp=NULL)/*判断是否开启成功・/printf("\aCannotopen%sforoutput! 161",filename);else{/・开启成功・/1ine(fp);printf("Client:");scanf("%39s",client); 16230for(;strcmp(client,"end")!=0;)/*clinet="end"*/313233343536373839404142434445{/・时,循环结束・/printf("Amount=");scanf("%f",&amount);total=total+amount;fprintf(fp,"%-40s$%f 163",client,amount);printf("Client:");scanf("%39s",client);11ine(fp);fprintf(fp,"%-40s$%f 164","*****Total",total);line(fp);fclose(fp);/・关闭报表文件*/)Filetorecordtheamount:testClient:Nanya_CollegeAmount=9876.54Client:ABC_CompanyAmount=1234.56Client:IJK_lmn_...Amount=2323.23Client:Xyz....Amount=2222.20Client:zzzzzzAmount=1111.10Client:endtest档案内容Nanya_CollegeABC_CompanyIJK_lmn_...Xyz....zzzzzz$9876.540039$1234.560059$2323.229980$2222.199951$1111.099976*****Tota]$16767.630859因为我们是用scanf()来读取字符串的,而scanf()会把空格符当成是数据的分隔,所以在输入客户名称时以底线代替空白。(这也是scanf()的缺点之一)第30行,循环以strcmp(client,"end")!=0作为结束的条件判断。其中,strcmp是TC的內建函式,可用来比较两个字符串是否相等,若相等,则传回〇,否则隹回非〇值。所以当使用者输入客户名称为"end"时,strcmp会传回0,而结東for循环。◎档案的读取要读取档案内的资料时,可以用fscanf。其格式如下:fscanf(fp,"控制字符串",&变量1,&变量2,...);fscanf〇的格式如同scang),只是输入参数中的第一个参数必须是档案指标,也就是指定出fscanf〇卷读取那ー个数据文件。有关scanfO请参考第四章。 165以下的范例:读取档案内容,将各个字符与ASCII值一起显示。ftoascn.c#include 166",fi1ename);elsefor(;ch!=EOF;)/*ch=EOF时,循环结束・/fscanf(fp,"%c",&ch);/・读取ー个字符・/printf("%c=%d 167",ch,ch);1fclose(fp);略省a50•5n5o1•231111•11e11====-F#in•}--:ftoascn.c1第15行,循环以ch!=EOF作为结束的条件判断。其中,EOF是ー个字符,表示档案结束(EndOfFile)的字符。所以当fscanf读取到档案结束字符时,循环就会结束执行。以下是课本的范例:读取档案内容,并将档案行距加倍后,另存新档。2space.c#include 168",filename); 169return;)/・结束main()函式・/printf("Filetobewritten:");scanf("%19s",filename);fpo=fopen(filename,"w");if(fpo==NULL)(printf("\aCannotopen%sforfclose(fpi);/・已开的return;)/・读取输出档名・//・开启输出档案・//・判断是否开启成功・/output! 170",filename);fpi在结束前要先关闭・//・结束main()函式・/for(;ch!=EOF;)(fscanf(fpi,"%c",&ch);fprintf(fpo,"%c",ch);if(ch=' 171')fprinf(fpo," 172");)/*读取ー个字符・//・号人--个字符・//・如果读到跳行字符・//・就再跳一行・/fclose(fpo);fclose(fpi);1/・关闭输出档(后开先关)*//・关闭输入档(先开后关)*/Filetoberead:testFiletobewritten:doubleddouble档案内容Nanya_College$9876.540039ABC_Company$1234.560059IJK_lmn_...$2323.229980Xyz....$2222.199951zzzzzz$1111.099976*****Tota]$16767.630859151617181920212223242526272829303132333435363738 173开启ー个「档案流」。fopen的语法必须#include 174Helpstrcmp:comparess2tosiintstrcmp(constchar*sl,constchar*s2);Prototypeinstring.hReturnsavaluethatis<0ifsiislessthans2;=0ifsiisthesameass2;>0ifsiisgreaterthans2.Performsasignedcomparison.比较两个字符串strcmp的语法必须#include 175)isfound.The 176isnotplacedinthestring.Returnsapointertotheargumentstring.Seealsoferrorgetcfopenputs由stdin读取字符串gets的语法必须#include 177〇 178不包含在所读入的字符串中。所传回的指针指向参数字符串。相关指令freadscanf/\/条件测试、不成立\1/1\?/NoI\//\I成立/ヽIYes/条件测试、——*11\2/指令群1Jヽ?/I成立iYes指令群2I
此文档下载收益归作者所有