解方程练习题,刚写了这个程序,运行之后发现不管输入什么数字都是无解,请问问题出在哪

10被浏览2,978分享邀请回答61 条评论分享收藏感谢收起26 条评论分享收藏感谢收起写回答各位大虾帮我看看我写的这些VB代码哪里出错了 ,不管输入什么数字都是弹出第一个msgbox_百度知道
各位大虾帮我看看我写的这些VB代码哪里出错了 ,不管输入什么数字都是弹出第一个msgbox
End IfIf a & 60 ThenMsgBox &你考试不合格&quotPrivate Sub Command1_Click()Dim a As IntegerText1 = aIf a & 60 ThenMsgBox &恭喜你考试合格&End IfIf a &gt
我有更好的答案
End IfIf a & 80 ThenMsgBox &恭喜你考试合格&End IfIf a &恭喜你;End If 还有取等的问题,按你写的,成绩优秀&quot,输入60会没反应。 Private Sub Command1_Click()Dim a As Integera = Val(Text1)
If a & 60 ThenMsgBox & 80 Then
MsgBox &End If都会弹出msgbox 最后把第二个if改为:If a & 60 And a & 80 Then
MsgBox &恭喜你考试合格&你考试不合格&End IfIf a &= 60 And a & 60 ThenMsgBox &恭喜你考试合格&恭喜你,成绩优秀&quota = Val(Text1)
这才是把Text1中输入的数的值赋给a后面的三个if有些不严谨,比如成绩为90,那么If a &= 80 ThenMsgBox &quot
采纳率:79%
Text1 = a写反了,刚申明的变量a的值为0;text1的值被变为0了正确写法是 a=int(val(text1.text))建议申明a 为 D 因为如果是小数会被加或减用这种方法只需a=val(text1.text)就好了用val的方法, 乱输的内容会被干掉
是右边的赋值给左边的比如a=1dim a as integera的初始值是0 所以始终是0分啦改成a=val(text1.text)就可以了!可以这样写Private Sub Command1_Click()select case val(text1.text)case is&60MsgBox &你考试不合格&case is &= 60 MsgBox &恭喜你考试合格&case is&80MsgBox &恭喜你,成绩优秀&end selectend sub
为您推荐:
其他类似问题
msgbox的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。C语言程序设计教程_大学生考试网
C语言程序设计教程
(第3版)邓小路 主2009.9讲 第1章 第2章 第3章 第4章 第5章 第6章 第7章 第8章 第9章C语言程序设计的概念 基本数据类型 C语言的流程控制 模块化程序设计 数组 指针 用户定制数据类型 文件 面向对象的程序设计介绍 第1章1.1 1.2 1.3C语言程序设计的概念程序与程序设计语言 C语言及其标准 C语言程序概要 1.1 程序与程序设计语言1.1.1 常量一提起计算机,人们就会联想到键盘、显示 器和主机。其实,应用要早得多、并一直流传至 今的计算机工具是算盘(见图1.1)。那么,现代 电子计算机与算盘的最大区别在哪里呢?关键在 于现代计算机可以自动完成计算过程,而算盘进 行的计算过程是在人的拨动下才能进行。图1.1 算盘 那么,为什么现代计算机可以自动完成计算过程呢?这 首先要从程序说起。程序实际上是一个非常普通的概念:按 照一定的顺序安排的工作步骤。可以说,做任何事情都有相 应的程序。做的事情不同,要求的效果不同,程序就不同。 例如,用同样的原料,采用不同的程序,会做出不同的菜肴 来。 一种工具能够自动工作,一是要有记忆功能,能够记住 程序;二是具有按照程序控制相关部件操作的能力。如果能 让算盘记住做某种计算的口诀和计算的数据,并且有能按照 口诀控制算珠自动运动的机制,则只要发出开始执行的命令, 算盘就会自动完成计算。 可惜这样的机制并没有在算盘中实现。但是,却有另外 一种机器却在这方面向前推进了一步。这就是明朝末年宋应 星在其《天工开物》中记载的中国古代提花机(见图1.2) 图1.2 中国古代的提花机 中国提花机大约出现于西汉末年(公元前)。它采用用丝线结成的“花本”(花版)控制经线起落,以织成要求的 图样。这是最早的程序控制思想。后来,提花机沿着丝绸之路传到欧洲,历经改进,1805年法国人Joseph Jacquard制 造成功用穿孔卡片(见图1.3)控制连杆(横针),用有孔 和无孔进一步控制经线起落的提花机。图1.3穿孔卡片 穿孔卡片把程序控制技术向前推进了一步。 这一技术被一位英国数学家Charles Babbage (见图1.4)引入到了计算机中机,用有孔和无孔 的组合来表示数据和程序。图1.4 英国数学家Charles Babbage 18世纪末,法国数学界调集大批数学家,组成了人工手算的流水线,经过长期艰苦奋斗,终于完成了17卷《数学用 表》的编制,但是,手工计算出的数据出现了大量错误。这件事情强烈刺激了Babbage。1812年20岁的Babbage开始计算机的研制工作,他要把函数表的复杂算式转化为差分运 算,用简单的加法代替平方运算,快速编制不同函数的数学用表,并将这种机器称为“差分机”。经过十年的努力,终 于于1822年完成了第一台差分机,可以处理3个不同的5位数,计算精度达到6位小数。1833年他又开始投身于一种“会分 析的机器”――分析机的研制中。他把机器设计成三个部分, 一 是用来储存数据信息的“仓库(The Store)”,二是进行数 这台机器虽然没有制造成功,但它的工作原理―程 序存储控制为今天的计算机奠定了基础: (1)任何工具的工作,都是由程序控制的; (2)只有工具具有了记忆程序的功能,并具有了按照 程序进行自我控制的功能,该工具才能自动工作。1.1.2 计算机程序设计语言程序要需要用某种形式(语言)来描述。例如,用算盘 进行计算,程序是用口诀描述的,珠算的语言是口诀。现代 计算机的程序则是用计算机程序设计语言来描述的。从计算 机诞生到今天,程序设计语言也在伴着计算机技术的进步不 断升级换代。 1. 机器语言 一种CPU的指令系统,也称该CPU的机器语言,它是该 CPU可以识别的一组由0和1序列构成的指令码。下面是某 CPU指令系统中的两条指令: 1 0 0 0 0 0 0 0 (进行一次加法运算) 1 0 0 1 0 0 0 0 (进行一次减法运算) 用机器语言编程序,就是从所使用的CPU的指令系统中 挑选合适的指令,组成一个指令系列。这种程序虽然可以被 机器直接理解和执行,却由于它们不直观,难记、难认、难 理解、不易查错,只能被少数专业人员掌握,同时编写程序 的效率很低,质量难以保证。这种繁重的手工方式与高速、 自动工作的计算机极不相称。这种方式仅使用于计算机出现 的初期(使用穿孔纸带的时期)的编程(用有孔、无孔,分别 代表1、0),现在已经不再使用。 2. 汇编语言 为减轻人们在编程中的劳动强度,20世纪50年代中期人 们开始用一些“助记符号”来代替0,1码编程。如前面的两 条机器指令可以写为A+B => A或ADD A,B A-B =>个样 A或SUB A,B 这种用助记符号描述的指令系统,称为符号语言或汇编 语言。 用汇编语言编程,程序的生产效率及质量都有所提高。 但是汇编语言指令是机器不能直接识别、理解和执行的。用 它编写的程序经检查无误后,要先翻译成机器语言程序才能 被机器理解、执行。这个翻译转换过程称为“代真”。代真 后得到的机器语言程序称为目标程序(object program),代 真以前的程序,称为源程序(source program)。由于汇编语 言指令与机器语言指令基本上具有一一对应的关系,所以汇 编语言源程序的代真可以由汇编系统以查表的方式进行。 汇编语言与机器语言,都是依CPU的不同而异,它们都 称为面向机器的语言。用面向机器的语言编程,可以编出效 率极高的程序。但是程序员用它们编程时,不仅要考虑解题 思路,还要熟悉机器的内部结构,并且要“手工”地进行存 储器分配。这种编程的劳动强度仍然很大,给计算机的普及推广造成很大的障碍。3. 高级语言汇编语言和机器语言是面向机器的,不同类型的计算机所用的汇编语言和机器语言是不同的。1954年出现的FORTRAN语言以及随后相继出现的其它高级语言,开始 使用接近人类自然语言的、 但又消除了自然语言中的二义性的语言来描述程序。这 些高级语言使人们开始摆脱进行程序设计必须先熟悉机器的 桎梏,把精力集中于解题思路和方法上。 第一种高级语言是1954年问世的FORTRAN语言。此后不久,不同风格、不同用途、不同规模、不同版本的面向过程的高级语言便风涌而起。据统计,全世界已有2500种以上 的计算机语言,其中使用较多的有近百种。图1.5为几种广 泛流行的高级语言的发展变迁情况。 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 Ada Modula-2PascalALGOL60 ALGOL68 CPL BCPL BCSmalltalk 80 C++ JavaSimula 67BASICFORTRAN PL/1 COBOL LISPANSI-BASIC QBASIC VB FORTRAN90 FORTRAN77PROLOG&&图1.5几种广泛流行的高级语言的发展变迁情况 1.1.3 高级语言程序的开发过程一般来说,程序开发的一般过程有如图1.6所示几个步骤图1.6 高级语言程序的开发过程 1. 分析一般来说,一个具体的问题要涉及许许多多的方面,这 是问题的复杂性所在。为了便于求解,往往要忽略一些次要 方面。这种通过忽略次要方面,而找出解题规律,就称为建 立模型。 2. 建立模型,表现模型 表现模型就是用一种符号-语言系统来描述模型。一般 来说,模型的表现会随着对问题抽象程度的加深和细化,不 断由领域特色向计算机可解释、执行靠近,中间也可能采用 一些其他的符号系统,如流程图等,直到最后用一种计算机 程序设计语言描述出来。 3. 源程序的编辑 源程序的编辑就是在某种字处理环境下,用 具体的程序设计语言书写并修改的过程。为此就 要掌握一种计算机程序设计语言。还要应用一种 专用程序编辑器或通用的文字编辑器进行。4. 程序的编译(或解释)与链接写出一个高级语言程序后,并不是就可以立 即拿来执行。要让机器直接执行,还要将它翻译 成由机器可以直接辨认并可以执行的机器语言程 序。为区别它们,把用高级语言写的程序(文件) 称为源程序(文件),把机器可以直接辨认 并执行的程序(文件)称为可执行程序(文件)。这一 过程一般分为两步: 第1步:在程序编辑过程中输入到源文件中的是一些 字符码,但是机器可以直接处理的是0、1信息。为此, 首先要将源程序文件翻译成0、1码表示的信息,并用相应的文件保存。这种保存0、1码信息的文件称为目标程序文件。由源文件翻译成目标文件的过程称为编译。在 编译过程中,还要对源程序中的语法和逻辑结构进行检查。编译任务是由称做编译器(compiler)的软件完成的。目标程序文件还不能被执行,它们只是一些目标程 序模块。 第2步:将目标程序模块以及程序所需的系统 中固有的目标程序模块(如执行输入输出操作的模块)链接成一个完整的程序。经正确链接所生成的文件才是可执行文件。完成链接过程的软件称为链接器(linker)。图1.7为编译和链接过程的示意图。 程序在编译、链接过程中,也可能发现错误。 这时要重新进入编辑器进行编辑。 图1.7编译和链接过程的示意图 5. 程序的测试与调试 经编译、链接的程序文件,生成可执行文件,就可以让计算机执行了。但是,并不是就可以得到预期的结果而交付用户使用了,因为程序仍然会存在某些错误。因此,每一个 人编写出一个程序后,在正式交付使用前,总要试通一下。“试通”就是试运行程序,也就是对程序进行测试。测试是以程序通过编译、没有语法和链接上的错误为前 提,目的是找出程序中可能存在的错误并加以改正。因此, 应该测试程序在不同情况下运行的情况,输入不同的数据可 以检测出程序在不同情况下运行的情况。测试的数据应是以 “程序是会有错误的”为前提精心设计出来的,而不是随心 所 欲地乱凑而成的。它不仅应含有被测程序的输入数 据,而且还应包括程序执行它们后预期的结果。每 次测试都要把实际的结果与预期的结果相比较,以 观察程序是否出错。 6. 编写程序文档经过了问题分析、设计、程序编码、测试后, 程序开发的工作基本上结束了。但是,这时还不能 交付使用。因为,随着程序规模的增大和日益复杂 化,程序的使用和运行也越来越不那么直接,用户 要运行程序,还需要知道许多信息,如: ● 程序的功能 ● 需要输入的数据类型、格式和取值范围 ● 需要使用的文件数量、名称、内容以及存放位置等 ● 程序运行需要的软、硬件环境 ● 程序的装入、启动方法以及交互方式等。 为此,程序开发者需要向用户提供这些资料――称为程序使用说明书或用户文档。需要说明的是,在许多软件中,这些内容已经部分或全部地以“readme‖或“help‖的形式 提供。目前,程序文档已经成为软件开发产品的必要部分。文 档在程序使用和维护中的重要性也改变了软件的概念,使之由早期的“软件是计算机程序的总称”演化为“软件是计算 机 7. 程序的维护 程序交付用户使用之后,并不是万事大吉了。 由于多种原因,还可能要对程序进行修改。交付之后对程序的修改称为程序的维护。维护程序的原因主要有: ● 原来的程序没有完全满足用户要求; ● 用户要求的改变; ● 程序中遗留有错误,在运行中被发现。程序的维护可以由开发者进行,也可能是由别人进行。为能便于程序的维护,开发者应当提供必 要的技术资料,并且要保证程序的可读好――能让 人看懂。 1.2 C语言及其标准1.2.1 C语言的出现C语言是目前程序设计领域中最有影响力的一种程 序设计语言。可是,它却是“漫不经心”地开发出来的。 20世纪60年代,Bell实验室的Ken Thompson (见图1.8)着手开发后来对计算机产生了巨大影响的UNIX 操作系统。为了描述UNIX,Thompson首先将当时的一种专门用来描述系统程序的BCPL语言改进为他称为B的语言。1970年Thompson发表了用汇编语言和B语言写成的PDP-7 上实现UNIX的初版。 1971年,Dennis Ritchie(见图1.8)开始协助Thompson开发UNIX。他对B语言做了进一步 的充实和完善,加入数据类型和新的句法,于 1972年推出了一种新型程序设计语言――C语言 (取BCPL的第2个字母)。为了使UNIX操作系统推广,1977年Dennis M.Ritchie 发表了不依赖于具体机器系统的C语言编译文本《可移植的C语言 编译程序》。于是,C语言是借助UNIX操作系统的 翅膀而起飞的,UNIX操作系统也由于C而得已快速 移植落地生根,两者相辅相承,成就了软件开发史上历时30年的时代。 图1.8Thompson(左)和Ritchie(中)于1999年接受当时美国总统克林顿授予的国家技术勋章1978年Brian W.Kernighian和Dennis M.Ritchie出 版了名著《The C Programming Language》,从而使 C语言成为目前世界上流行最广泛的高级程序设计语言。 以后,又有多种程序设计语言在C语言的基础上产生,如 C++、Visual C++、Java、C#等。 1.2.2 C语言的标准C语言的灵活性、丰富性、可移植性很快得到了普遍的 承认,接着适合于各种不同操作系统(UNIX,MS-DOS,CP/M-80,86等)和不同机种(字长为8bit~32bit)的C语言编译系统相继出现。1982年美国国家标准局(ANSI)语言标准化委 员会成立了一个委员会开始着手进行C语言的标准化工作,并 于1983年公布了第一个C语言标准草案(83 ANSI C)。1989 年,ASNI又发布了一个完整的C语言标准――ANSI X3.1591989,通常称做“ANSI C‖,简称“C89‖。1990年,国际标 准 组织ISO/JEC JTC1/SC22/WG14采纳了C89,做了少编辑性修改后,以国际标准ISO/IEC 发布,通常称其为“C90‖,它同C89基本相同。 1995年,WG14对C89做了两处技术修订和一个扩充。人们将其称为“C89增补1‖或“C95‖。同时,WG14开始着 手对C标准做全面修订,并于1999年完成获得通过,形成正式的C语言标准,命名为ISO/IEC ,简称“C99‖。 本书将基于C99介绍C 语言程序设计的基本方法。目前 各厂家所提供的所有C编译系统都还未实现C99所建议的功 能。为了读者能实际运行C程序,本书所介绍的程序都是符合ASNI C标准并能在大多数C编译系统通过和运行的程序。但 在文字叙述中,会介绍C99所增加的新功能,以使读者今后 能顺利地过渡到用C99编程。 1.3 C语言概要1.3.1 函数任何一部机器都是用部件组装而成的。计算机程序和机器一样,也是由一些部件构建起来的。C语言程序部件是函数。也就是说,设计C语言程序就是设计它的构成函数。 下面举例说明C语言程序中的函数是什么样 的。 例1.1 一个输出一串字符的C程序。 /* 文件名:ex010101.c */#include &stdio.h& int main(void) { printf(&Programming is fun.&); // 输出一串字符 return 0; /* 向操作系统返回一个数字0 */ } 这是一个非常简单的C语言程序,它的执行结果 是显示一行字符: Programming is fun. 说明:(1)这里 int main (void){… }是一个函数。这个函数的名字为“main‖。这个名字是专用的,表示这个函数是“主函数”。所谓主函数,就是执行这 个程序时,由操作系统直接调用的函数。每一个C语言程序必须也只能有一个主函数。 (2)函数名后面的圆括号用于表示参数。一般说来,用函数进行计算,需要给定参数。但是广义的计算也可以没有参数而只执行一个过程。在C语言程序中,参数部分写为 Dvoid‖,表示该函数没有参数,只执行一个过程。“void‖可以省写,如程序第一行可写为: int main()在许多教材和程序中,可以常常见到这种形式的主函数首行。但是,C标准建议写上void,使含义清晰。在本书的 程序中都是写成main(void) 形式的。(3)再后面的一对花括号中的部分称为函数体,用来表明该函数的功能是如何实现的。通常,函数体用一些语句 表述。C语言规定语句必须用分号结束。先分析下面的语句:printf(″Programming is fun.″);它的功能是调用编译系统提供的函数库中的一个函数 printf(),来输出后面的一串字符。函数printf的使用比较 复杂,后面将陆续介绍。 (4)函数名前面的“int‖表明函数的返回值是一个整数。有的操作系统(如Unix)要求在执行一个程序后应向系统返回 一个整数值,如程序正常执行和结束,应返回0,否则返回一个非0值。因此,需要将main函数指定为int(整型),同时在函数体的最后写一返回语句: return 0; 它的功能是向调用者(操作系统)返回0值,表示主函数正 常结束(也就是程序正常结束)。此语句必须写在函数体的最后一行才有意义,因为只要执行到这条语句,就表达程序正常结束,向操作系统返回一个0,如果程序未执行到这个返回语 句就非正常结束了,就不会向操作系统返回0。操作系统会据此作出相应的处理。 有的操作系统(如DOS,Windows)并无程序必须返回 整数的要求,因此,可以不指定main函数为整型。这时可 在main函数的前面加上void,如∶ void main(void) 或 void main() 表示main函数是无类型的,不返回任何类型的值。显然在 main函数的最后也不必写返回语句“return 0;‖。读者可以 在其他教材或程序中看到这种形式的main函数。 以上两种用法都是是合法的、有效的,编程者可以根 据情况决定。为了使程序具有一般性,采用以下形式∶ int main(void) 并在函数体最后有“return 0;‖语句。 (5)程序最前面的# include &stdio.h&是一种在程序编译之前要处理的内容,称为编译预处理命 令。编译预处理命令还有一些,它们都用“#‖开头,并且不用分号结束,所以不是C语言的语句。这里的编译预处理命令称为文件包含命令,它的作用是在编译之前把程序中需要使用关于系统定义的 函数printf()的一些信息文件stdio.h包含进来。用“.h‖作为后 缀 的文件称为头文件。 (6)“/* … */‖中的文字用于做一些说明――注释,让读程序的人容易读懂。例如,注释/* 文件名:ex1_01.c */ 是告诉读程序的人,这个程序的源代码用文件ex1_01保存。 而其他两个注释是对其左面两条语句功能的说明。 上面的程序只由一个函数组成 (在主函数中又调用了库函数 例1.2 计算两个整数(2,3)相加的结果 /* 文件名:ex010201.c */ # include &stdio.h& int add (int ,int ); /* 声明后面将要使用函数add()*/ int main (void) { /* 声明后面使用的变量s是整型的*/ s = add(2,3); /* 调用add()进行计算,并用s接收*/ printf(&The sum is: %d&, s); /* 输出s的值 */ return 0; } int add (int a,int b) /* 函数add()的定义 */ { /* 定义一个整数sum,用于存放和*/ sum = a + /* 将a和b求和,并把结果送sum*/ /* 返回sum的值到调用者*/ } 说明 (1)图1.9表明了该程序的执行过程。为了清晰,仅列 出了执行语句。将2和3传递给a和b 操作系统main () { ② s = add(2, 3); add(int a, int b) { 计算a+b 返回sum的值 到调用处 sum = a + } 编译系统提供库函 数printf 进行计算 并输出结果① 操作系统 ex1_02.ex 调用main() e③ printf(“The sum is %d”, s);return 0; 返回操作系 } 统④图1.9 程序ex1_02的执行过程 ① 经过编译、链接后的C语言程序就成为一个可执行文 件。例如,程序的ex1_02的默认可执行文件名为 “ex1_02.exe‖。若要执行这个程序,只要在操作系统的命 令 执行环境中打入这个文件名,系统就会开始执行这个程序。 对于C语言程序而言,首先从调用主函数开始。 ② 在主函数main中,第一个语句是 s = add(2, 3);但是,这个语句的执行要分如下步骤才能完成。● 调用函数add(),同时将数据2和3分别传送给函数add()中的变量a和b;● 使用表达式a + b进行加法计算。 ●将和用“=‖赋给函数add()中的变量sum中。注 意 用return语句将sum的值返回的函数add()的调“=‖是赋值操作符,不是等号。C语言中的等号是“==‖。●用处。● 将函数add()的返回值送给主函数中的变量s。③ 执行函数printf(),输出下面的内容:The sum is 5 这个语句的执行也需要如下多个步骤才能实现:● 圆括号中的引号中的“The sum is:‖要求原样输出。● 圆括号中的引号中的“%‖表示后面的字符“d‖是一 个格式字符,要求将双引号后面的表达式的值,按照整型数据输出。 ● 函数printf()将流程返回到调用处。printf( )也有返回值(成功返回输出的字符个数;失败时,返回 一个负整数),但是一般不用。 ④ 执行main()中的返回语句return,用“0‖向 操作系统送回“平安”信号。(2)变量及其类型本例中的s和sum都称为变量。变量是程序中被命 名的数据实体,并且它的值是可以改变的。同时,为了便于计算与存储,C语言中程序中所使用的每个数据都被规范化了。 这种数据的规范称为数据类型。 本例中使用语句int s; 和 int sum; 的作用就是声明了两个变量s和sum名字和类型(用“int‖表明它们是整型数据)。变量在使用之前都要先行声明。 (3)函数的声明 本例中的 int add(int,int ); 称为函数声明。函数声明的作用是让编译器知道该函数的原型(包括返回类型、参数个数和类型,以便对调用语句进行 语法检查。如果定义在调用前,从定义可以直接获得这些信息,就可以不写声明;如果调用在定义之前,则需要一个原型声明说明这些信息。 对于编译系统提供的库函数,它们的定义不在程序中, 因此需要给出相应的原型声明。为了方便使用,系统把某些 类型的库函数的原型声明写在某个头文件中,程序员只要把要求的头文件用文件包含语句写在程序中函数调用之前,就等 于 把 原 型 声 明 写 在 了 函 数调 用 之 前 。 这 就 是使 用 函 数 printf( ),必须在其前写一条#include &stdio.h&的原因。 (4)关于printf( )函数的参数 printf( )函数的参数有两部分:前面的用双引号引起的部 分称为“控制串”。控制串由一些字符组成,这些字符可以分成两类:第一类字符可以直接显示出来,第二类字符作为格式说明符使用。或者说,除了格式说明符之外的字符,都是 可以直接显示的。格式说明符是由“%‖开头,后面跟着的是 格 式码。本例中的“d‖就是格式码,它后面输出的数据按照带 符 号十进制输出。其他格式说明符将陆续介绍。 (5)关于赋值运算在C语言中,符号“=‖称为赋值运算符,它的作用是把后面(右面)的值,送到其前(左面)的变量(左值)中。一 例1.3 计算一个数的正弦值的C语言程序。#include &stdio.h& #include &math.h& int main(void) { /*定义x为实型变量*/ x = sin(0.19199); /*调用sin函数*/ printf(&%f\n&,x); //调用printf函数,输出x的值 } 程序的执行结果如下:0.190813 说明: (1)“‖是声明:x是一个实型变量。 (2)“x = sin(0.19199)‖可执行一次函数调用,求出 0.19199弧度的正弦值,并赋给实型变量x。sin( )是一个库函 数,math.h是其要求的头文件。 (3)printf( )中的格式说明符“%f‖,指定一个实型格式输出(前面介绍的%d是整型数据格式符)。通常输出的数据在小数后有6位数字;小数点前的数字位数不指定,根据实际 值的位数输出。格式说明符的类型要与后面要输出的数据类型相一致。(4)printf( )中的“\n‖称为转义字符序列,前面加了 反斜杆后,“n‖不再作为字符,而是作为一条换行命令使用。 转 从这一小节可以得出如下结论:● C语言程序是由函数组成的。●设计C语言程序时,一个必须设计的函数是主函数。C语言的执行是从系统调用主函数开始的。●主函数的部分功能也可以通过其他子函数补充实现。子函数应当首选从函数库中的函数;函数 库中没有时。可以考虑自行设计。●使用库函数时,要用文件包含命令将需要的头文件包含到程序中调用该库函数之前。 1.3.2 C语言的标准由前一小节中的例子可以看出,在C语言程序中, 函数下面的组成单位是语句。在C99中,基本的语句有表达式语句、流程控制语句和块语句。1. 表达式语句 C语言程序的具体计算过程是由表达式完成的。表 达式是由运算符(如上述+,=等)、变量(如上述s, sum,a,b,x等)和常量(如上述2,3,0.19199等) 组成。前面使用过的 s = add(2, 3) sum = a + b x=sin(0.19199) 都是表达式。表达式加上语句结束符(分号)就构成表达式语句。学习C语言程序设计,必须掌握正 确地使用变量、常量和运算符的表示方法和使用规则。变量和常量的使用涉及它们的数据类型、表示 (命名)规则等,后面要专门介绍。 C语言中的运算符种类很多,正确地使用这些 运算符,有三点需要注意: ● 它们的含义。特别要区分一个运算符符号在 C语言中和在普通数学中的意义的不同。如“=‖。 ● 优先级,即在一个表达式中存在多个运算符 时,进行运算的先后顺序。 ● 结合性,即在一个表达式中有多个优先级别相同的运算符时,先进行哪个运算符的运算。例如,在表达式2*3/5 (在C语言中,“*”为乘运算符。“/‖为除运算符)中,先 进 行 除呢,还是先进行乘。在这个表达式中,好像对运算结果没 有影响,但有时是有影响的。关于这些问题,后面将专门介绍。2. 流程控制语句 一般说来,程序中的语句是按照书写顺序执行的。但 是,有些情况下,需要改变默认的执行顺序,例如像图1.10 (a)那样要从两个或多个语句中挑选一个语句执行,或者 像图1.10(b)那样要重复执行某一个语句或语句块。前者 称为选择控制,后者称为重复控制。 (a)选择结构(b)重复结构图1.10 两种基本的流程控制结构 下面给出两个实例。 例1.4 由键盘输入两个数,输出其中的大数。 本例中函数max2( )的执行过程如图1.11所示。图1.11 函数max2()的执行过程 程序如下: #include &stdio.h& float max2(float x,float y) { if(x &= y) /* 选择判断 */ max = /* 条件满足进行的运算*/ else max = /* 条件不符进行的运算*/ printf(&The max is:%f&,max); } int main(void) { float a,b; printf(&Input two real numbers:\n&); /* 输入提示*/ scanf(&%f%f&,&a,&b); /* 输入数据 */ max2(a,b); /* 调用函数max2( ) */ return 0; } 说明: (1)本例的函数max2()中有一个选择结构,条件是 “x &= y‖。满足该条件,则执行运算max = x;不满足,则 执 行运算max = y。这样,就在max中保存了x和y中的大者。 (2)在主函数中,函数scanf(D%f %f‖,&a,&b)的功能 是从键盘上输入两个实数,分别存放到地址&a和&b中。地址 &a和&b是变量a和b地址,“&‖是一个运算符。用于计算其 后 面变量的地址。 (3)在函数scanf(D%f%f‖,&a,&b)中,“%f‖表示要输 入的数据是实型数据。也就是说,格式说明符的类型,要与 输入数据的类型一致。另外,键入的两个数据之间应当以空 格、制表符(按Tab键)或回车分隔。 程序运行时的情形如下: Input two real numbers: 1.235 2.345 例1.5 求累加和的值。 程序如下: #include &stdio.h& int sigma(int n) { int i = 0,sum = 0; while(i &= n) { sum = sum + i ++; } } int main(void) { int m, scanf(&%d&,&m); total = sigma(m); printf(&total = %d\n&,total); return 0; } 说明: (1)声明 int i = 0,sum = 0; 有两个功能:一是定义了两个整型变量;二 是对两个整型变量设定了初值。这称为变量的初 始化。变量在没有初始化时并且也没有执行赋值 操作之前,其值是不确定的。为了避免使用这些 不确定的值,应当尽量在变量定义的同时对其进 行初始化。 一般说来,存放和的变量的初始值应当为 0,而存放积的变量的初始值应当为1。 (2)在本例中,函数 sigma()用来计算。计算的方 法 是: 先设置sum的初值为0、 i的初值为0。i=0,sum=0i &= n 是sum = sum + i否先执行sum = sum + i。然后用表达式“i ++‖将自增 1,相当于执行操作:i = i + 1 每执行一次i的自增1, 用流程图表示如图1.12所 示。i ++return sum图1.12 函数sigma()的执行过程 除了上述两种控制语句外,C语言还提供了 其他一些控制语句,以后会专门介绍。 3. 块语句 块语句也称为复合语句,就是用一对花括 号将一组语句括起来。在一个块语句中可以包括 若干声明和若干语句。在例1.8的函数sigma() 中,while下面的用花括号括起的两个语句,就组成一个块语句。块语句在语法上相当于一条语句。因此,当语法上需要一个语句,而一个语句又不能满足需要时,就必须使用块语句。 1.3.3 名字与声明1. 标识符与关键字 标识符也称为名称。变量的名字、函数的名字、文件的名字等,都是关键字。在C语言程序中,所使用的标识符应当符合如下的词法规则: (1)标识符是大小写字母、数字和下划线组成的序列, 但不能以数字开头。例如,下面是合法的C标识符: a A Ab _Ax _aX A_x abcd 但是下列不是合法的C标识符: 5_A(数字打头) A-3(含非法字符) (2)C语言区别同一字母的大小写,如abc与abC被看作识不同的名标识符。 (3)C89要求C编译器能识别的标识符长度为不少于31个有效字符,C99要求C编译器能识别的 标识符长度为不少于63个有效字符。一个标识符中 超过了这个长度的字符可能会不被辨认。例如在符 合C99的系统中,当两个标识符的前63个字符都相同时,不管后面的有效字符是否相同,都可能被当作同一个标识符。(4)普通标识符不能使用对于系统有特殊意义的名称。这些对系统有特殊意义的名称称为关键 字。表1.1为C99关键字。 表1.1 C99关键字 auto _Bool break continue case default char do_Complex constdoubleforelsegotoenumifexternfloat_Imaginary inlineintshort switch volatilelongsigned typedef whileregistersizeof unionrestrictstatic unsignedreturnstruct void 在 一个 程 序 中 , 往 往 要 使 用 大 量的 名 字 。大 量 的 名 字 的 使 用 , 可 能 会造 成 名 字 的 冲 突 和使 用 错 误 。 为 此 , 除 了 上 述词 法 规 则外 , 人 们 还总结了在程序中使用“好” 名字的一些原则: (1)尽量做到“见名知 义”,以增加程序的可读性。 (2)尽量避免使用容易 混淆的字符,例如 0(数字)、O(大写字母)、 o(小写字母)、1(数字)-I(大写 字母)、i(小写字母)、2(数 字)、Z(大写字母)、z(小写字 母)表1.2匈牙利 前缀 a或ar部分常用匈牙利前缀数据讦类型 变量名举例 arAge数组bby c或ch d或dbl dw或w f或fl fn h L或l mBULL(布尔值)BYTE(无符号字 符) char double 无符号整数 float 函数 句柄 long 类的数据成员bDone,bbyCount,by c,ch d,dbl,dCost, dblCost wNumber f,fl,fCost,flCost fnFun1 hWnd L,l,lCountn或ip s sz x,yint指针 字符串 “0”结束的字符串 无符号整型或坐标n,i,nCount,iCountpInt,pWnd sName sz,szMystring (3)名字不要太短,一般函数名尽量使用动宾 结构,如PrintCalendar、IsPrime等。 (4)许多国外的Windows程序员还采用匈牙 利人Charles Simonyi提出的将类型作为变量名前 缀的命名方法――通常称为匈牙利命名法。表1.2为 部分常用匈牙利前缀。 2. 声明 在程序中,有许多东西是需要系统为其开辟 存 储空间的,例如变量、函数类型定义等。它们都有 自己的名字,并且要在内存中独立存储,为此可以 将它们称做程序实体。那么,如何建立它们的名字 与实体之间的关联呢?这就是声明的作用。 声明也称为说明,它的作用非常重要,包括如下一些: ●告诉编译器,一个名字是与哪个实体联系,不能张冠李戴 ●告诉编译器,也要程序员明白这个实体的类型。 ●告诉编译器,这个实体什么时候建立?在什么范围内可以 使用? 前面已经使用过了变量和函数的声明。所以,例1.2 中 的 就是建立变量名s与它的实体之间的关联。 在一个语句块中关于声明的进一步用法,后面还要陆续 介绍。目前要牢记的是,在使用一个程序实体之前,一定要 让编译器知道该程序实体的属性。 在C99之前,对变量和函数的声明不作为语句(尽管它们 也是用分号结尾),它们必须出现在C语句的前面(声明的位置 必须集中写在语句之前)。C99改变了这一做法,它吸取了 C++的做法,声明不必集中放在执语句之前,可以出现在程 序中的任意行。这样,C语句就有执行语句和非执行语句之 分。声明是非执行语句,表达式语句和流程控制语句是执行 语句。 1.3.4 变量及其赋值1. 变量 变量(variable)是一种程序实体。它具有一个值,并 且这个值是可以通过程序操作改变的。 2. 变量的赋值运算 在C语言中,符号“=‖称为赋值运算符,它连接了左右 两 个操作数(即运算量):右操作数也称右值,可以是一个表达 式,左操作数也称左值(lvalue),只能是变量。赋值操作 的过程是把右操作数的值先转换成左操作数 (变量)的类 型,并把该值存放到左操作数(变量)中。例如 int a; a = 2.6; printf(D%d‖,a); 这是因为计算机在执行上述语句时,首先将2.6 舍去小数部分截尾(truncation)成整型,赋值给 变量a。 应当注意,赋值运算符是“=‖。这个符号不是 等号。例如 int a = 2, b = 3; a = a + b; 的操作是把表达式a + b的值(2 + 3)送到(赋值给) 变量a。即经上述操作后,变量的a的值由2变为5。 图1.13表明这一操作过程:先计算a + b的值,然后 把这个结果送到变量a中。于是,变量a的值由2变 为5。 5a 2 2 b 3 3运算器a + b图1.13 a = a + b的操作过程 赋值运算符具有“自右至左” 的结合性,例如 int a = 0, b = 0, c = 0; a = b = c = 5 + 3; 相当于 int a, b, a = (b =(c = ( 5 + 3) )); 即先计算把5 + 3 的值,得8,赋值给变量c;再把变量c的值(8)赋值给变量b;最后把变量b的值(8)赋值给变 量a。图1.14表明这一操作过程。执行的结果,a、b、c三 个变量中的值均为8。也就是说,从一个变量向另一个变量 赋值后,原来变量中的值并不会消失或改变。所以,赋值操 作相当于拷贝,而不是移动。 a0b0c05 运算器 a + b3(a) 操作前变量a、b、c的值 a 0 b 0 c 8 5 运算器 a + b 3(b)执行操作c = 5 + 3后变量a、b、c的值 a 0 b 8 c 8运算器(c) 执行操作b = c = 5 + 3后变量a、b、c的值a8b8c8 运算器(d)执行操作a = b = c = 5 + 3后变量a、b、c的值图1.14 a = b = c = 5 + 3的操作过程 1.3.5 算术运算 算术运算是一切计算的基础,也是大家都认为 非常熟悉的。但是对于高级程序设计语言尤其是C语言中的算术运算符,还需要有一个再学习的过程。C语言中的算术运算符与普通数学中的算术运 算符有如下一些不同。 ● 运算符符号有所不同。 ● 种类有所不同。● 结合性可能会破坏交换率。1. C语言的基本算术运算符表1.3为C语言中的基本算术运算符及其说明。 表1.3 C语言中的基本算术运算符及其说明运算 符 名称 运算对象 功 能 示例表 达式 示例值*/ % + -乘除 模 加 减任何两个实数或整数任何实数或整数,但右 操作数不可为0 两个整数,但右操作数 不可为0 任何两个实数或整数 任何两个实数或整数求两数之积求两数之商 求整除的余 数 求两数之和 求两数之差5.5 * 4.0 22.0000004.5 / 5 13 % 8 8 + 3.5 10 - 4.6 0. 11..400000 说明: (1)这几个算术运算符的运算对象有两个,所以也称 为双目算术运算符。 (2)这几个算术运算符的优先级别为:*、/、%高于 +、-。并且它们都比赋值运算符的优先级别高。所以,在一 个表达式中有赋值运算符,也有算术运算符时,不使用圆括号,可以先进行算术运算,后进行赋值运算(3)这几个算术运算符均为“自左至右”。 (4)需要特别注意的是整数除和模运算的结果都是整数。例1.6 分析下面的程序的执行结果。 /* 文件名:ex010601.c */#include &stdio.h& int main(void) { printf (&300 * 2 / 3 = %d\n&,300 * 2 / 3); printf (&2 / 3 * 300 = %d\n&,2 / 3 * 300); return 0; } 观察上面的程序,按照交换率,似乎它们的计算结果应该相 同。但是,非常遗憾!结果完全不同: 300 * 2 / 3 = 200 2 / 3 * 300 = 0 原因在于算术运算符具有自左至右的结合性,即对于第1 个表达式语句,执行的顺序为: 300 * 2 = 600,600 / 3 = 200 对于第2个表达式语句,执行的顺序则为: 2 / 3 = 0(注意是整数相除),0 * 300 = 0 因此,使用整数除,应当特别小心。 2. 自反算术赋值运算符 前面介绍过这样的赋值表达式: a=a+b 它的作用是将变量a的值加上变量b的值,再送回到变量a 中。或者说是将变量a的值增加一个变量b的值。这样类似的 运算很多。为此C语言为这种运算提供了一种简洁形式: a+=b 这样,就可以用一个复合运算符代替原来的两个运算符。 这种复合运算符称为自反算术赋值运算符。除自反加以外,还 有下列一些: - = (自反减赋值) * = (自反乘赋值) / = (自反除赋值) % = (自反模赋值) 自反算术赋值的结合方向与赋值运算符一样,为自右向 左。另外,它的优先级别相当低,与赋值是同一级别。例如表 达式语句: c = b * = a + 2; 相当于如下两个表达式语句: b = b * (a + 2); c = b; 3. 自加和自减运算 自反算术赋值运算中有两种更特殊的情况,即: i = i + 1 即 i += 1 和 i = i C 1 即 i -= 1 这是两种极为常用的操作。把i称为计数器,用来记录完 成某一工作的次数。C语言为它们专门提供了两个更简洁的运 算符: i ++ 或 ++ i 和 i -- 或 -- i 前一种(i ++和i --)称为后缀形式;后一种(++ i和-- i)称为 前缀形式,都称为自加或自减运算符。 例如: int i = 5; int i = 5; i ++; ++ y = i; y = 两段程序执行的结果i值都为6,y的值也都为6。但 是把它们引用在表达式中就表现出区别了。例如: int i = 5; x = i ++; /* 相当于 x = i = i + 1;*/ y = i; 的执行结果为:x为5,y为6。即后缀方式是“先引用后增 值”。而 int i = 5; x = ++i; /* 相当于 x = i = i + 1; */ y = 的执行结果为:x为6,y为6。即前缀方式是“先增值后引用”。自加和自减运算符的结合方向是“自右至左”,它的运算 对象只能是整型变量而不能是表达式或常数。例如:5 ++或(x + y)++是错误的。 4. 正负号运算符正负号运算符为+(正号)和-(负号),它们是一元运算符。例如,-5和+6?5。它们的优先级别高于*、/运算符。例如: -a * b 先使a变符号再乘以b。其实正负号运算相当于一次算术赋 值运算,例如: -a -a * b 相当于a = 0 C a 相当于(0 - a) * b 它的结合方向为自右至左。综上所述,凡赋值运算符及其变种(包括自反算术赋值运算符、自加自减运算符和正负号 运算符)的结合方向都是自右至左的。1.3.6 赋值类运算符的副作用及限制在程序设计中,效率与易读性是一对主要矛盾。人们为了 提高程序的效率,往往要使用技巧把程序写得尽可能简洁一 些。但这样就降低了程序的可读性和可理解性。可读性差的后 果是易于隐藏错误,难于纠正错误,不易维护,降低了程序的 可靠性。鉴于“软件危机”的教训,现代人们进行程序设计时 要 遵守的基本规范是:可靠性第一,效率第二。为保证可靠性第 一,就要清晰易读第一。这就要求进行程序设计时,把程序写 得清晰易懂一些。初学者从一开始就应当培养这个良好的程序 设计风格。 C语言允许在一个表达式中使用一个以上的赋值类运算 符(包括赋值符,自反算术赋值符,自加、自减运算符等)。 这种灵活性在给程序带来简洁性的同时也会引起副作用。这 种副作用表现在两个方面. 1. 费解、易于误解――对人的副作用下面是容易引起误解的两个例子。① c = b* = a + 2;容易误解为 b *= c = b + 2; ② x = i ++ +j;应该理解为x =(i + +) + j呢?还是x = i +(+ +j)呢?实际上C编译器总是从左至右尽量多地将若干个 字符组成一个运算符(对标识符也如此),因此i + + + j被处理 成(i ++) + j而不是i + (++ j)。 克服这类副作用的方法是:尽量把程序写得易懂一些。为了使表达式清晰易懂,可以采用这样一些措施:(1) 将费解处分解。 例如将上面第①个表达式语句分写为 a = a + 2; b = b * c = 或 c = a + 2; c = b*c; 对第②个表达式语句,可分写为: x = i + i ++; (2)加一些“冗余”括号为了避免出现差错,在易于误解的地方加一些“冗余” 括 号。例如,c=b*=a+2可以改写为 c=b*=(a+2); 或 便清晰些了。 c=(b*=(a+2));所谓“冗余”括号是指如果不加这些括号的话计算机也 不会错,但为了让人不致误解而多加的括号。(3) 加注释说明。注释是提高程序清晰性的有力工具。对C语言来说,注 释不会影响程序的效率。所以,一方面想保证程序的效率,一方面又怕别人误解(当然自己不能误解)的情况下,可以加注释说明。如对c = b* = a + 2可以写为: 2. 不定解――对机器的副作用 先看一个例子: j = 3; i =(k = j + 1)+(j = 5); 执行这段程序时,不同机器上得到i的值可能是不同 的。有的机器先执行(k=j+1)然后再执行(j=5),i值得9。而有 的机器是先执行(j=5)后执行(k=j+1),i的值就成了11。 在数学中,a+b和b+a是一样的,因为符合交换律,所以(a+b)+(c+d)也可以写成(c+d)+(a+b)。换言之,(a+b)+(c+d)的求值顺序不影响结果(可以先求a+b,也可以 先求c+d)。但在C表达式中含有一个以上的赋值类运算符 时,交换律不再适用。由于C语言对表达式的求值顺序(方向)无统一规定,而是由各个C编译系统自己决定,这就造成了同一程序在不同计算机系统运行时会得到不同的结果。 为了提高程序的可移植性,应当使表达 式分解,使之在任何机器上运行都能得到同 一结果。因此上面语句可改为: j = 3; i =k + k = j + 1; j = 5; 第2章 基本数据类型2.1 2.2 2.3 2.4 基本数据类型的特征 数据常量 数据类型转换 数据的控制台输入与输出 C语言提供有丰富的数据类型:char(字符类型) 整 基 本 数据类型 浮点型 型 short(短整型) int(整型) long(长整型) float(单精度浮点型) double(双精度浮点型) long double(长双精度浮点型)C 语 言 数据类型导 出 数据类型void类型 T*(指针类型) enum(枚举) struct{?}(结构体类型) union{?}(共用体类型) T[?](数组类型) 文件类型 函数类型用户定制类型构造类型 2.1 基本数据类型的特征C语言提供的基本数据类型包括char(字符)型、int(整)型、float(单精 度实)型、double(双精度实)型。并且 还可以通过使用short、long、signed 和unsigned修饰char和int,用long修 饰double,形成更多的类型。 2.1.1 数值的定点表示与浮点表示定点表示和浮点表示,是C语言基本数据类型 的重要特征。为了说明什么是“定点”,什么是 “ 浮 点”,先看π值的几种表示形式: 日常的表示法 3.1.1 0.2 31. -3 C语言中的表示形式 3..
0. 31.1.59e-3 实型常量实型常量有十进制的定点和浮点两种表示方法,但并不存在其他进制的表示。 (1)定点表示的实数简称定点数,实际上是以小数形 式表示实数。 定点表示的实数是由一个正号或负号(正号可以省略) 后接若干个十进制数字和一个小数点所组成,这个小数点 可以处在任何一个数字位的前面或后面。例如,数字长度为 4,小数点位于中间,那么可以表示10.28,也可以表示0.01,与这种方法性质类似的定点表示还有使用分数的形式。定点数的固定窗口形式使得他既不能够表示非常大的数又 并且当除法发生时,大量 的精度丢失. (2)浮点表示的实数简称浮点数,实际上是以指数形式 表示实数。 浮点表示的实数是由一个十进制整数或定点数后接一 个字 母 E(大、 小写均可 )和一个 1至3位的十进制整数所组 成,字母E之前的部分称为该浮点数的尾数,之后的部分成 为该浮点数的指数或阶,该浮点数的值就是它的尾数乘以 10的指数幂。 对于一个浮点数,若将它尾数中的小数点调整到最左 边 第 一 个 非 零 数 字 的 后 面 , 如 1 . 23 4 e 1 , 则 称 它 为 规 格 化 (或标准化)浮点数。浮点数可以表示较大精度范围的一个 实数。 ? 定点数:小数点固定。 ? 浮点数:小数点不固定(位置不固定)随阶码浮动。 1、定点表示法小数点固定在数值部分的最高位之前或最低位之后。 例如: 1.01011. 2、浮点表示法 N=?S*2?P S ―― 二进制小数,称 “尾数”,S ≥0 P ―― 称为数N的阶码,为非负正数 2 ―― 阶码“底”浮点形式存储 3 . 1 4 1 5 9 +1数值部分(尾数)指数(阶码) 2.1.2 整数的有符号类型与无符号类型内存中的数值是以补码形式存放的,一个正数的补码就 是该数的二进制数(如10的补码为01010)。 求一个负数的补码的方法如下: 如-10的补码可以这样求: ① 先取该数的绝对值; 即先取10 ② 然后以二进制形式表示; 10的二进制码为 01010 ③ 再对其取反; 取反得10101 ④ 然后加1; 加1,得 10110,即-10的16位存储 形式为:10110。 2.1.3 类型宽度与取值范围C语言对不同类型的数据分配不同宽度的存储空间,典型 的存储空间宽度有:1个字节(8位)、2个字节(16位)、4个字节(32位)、8个字节(64位)和10个字节(80位)几种。显然,不同的长度,对应的数据的取值范围是不同的。当然,同样长度的取 值范围还与有无符号、是定点表示(整型)还是浮点表示(实 型)有关。另外还取决于所用的编译系统。大多数编译系统对 一个带符号整数的数值范围处理为:-2n-1 ~ 2n-1-1。其中n为该 整数所占的比特数。如果一个整数所占的比特数为16,则该想 整数的范围为-32 768 ~ 32 767。也有一些编译系统对一个带符 号整数的数值范围处理为:-2n-1-1 ~ 2n-1-1。如果一个整数所占 的比特数为16,则该想整数的范围为-32 767 ~ 32 767。 不同长度整型数据的取值范围数据长度 (比特) 取值范围Signed (有符号)8 16 32 64 -128~ 127 -32 768 ~ 32 767 -2 147 483 648 ~ 2 147 483 647 -(263) ~ 263-1Unsigned (无符号)0 ~ 255 0 ~ 65 535 0 ~ 4 294 967 295 0 ~ 264-1(18 446 744 073 709 551 615) 由于内存和效率的原因,数据的表示总是有限的。比如 2/3=0....计算机不可能用无限位的比特来表示这个 数。那么它就只能用有限的数位来表示浮点数。设用十进制表 示。 0.XXXXXXX *10^(n) 这里0.XXXXXXX是一个小于1.0大于等于0.1的小数,而n 是一个整数。如上所说,浮点数分两个部分:有效数位部分和 指数部分。一般来说分配给这两个部分的表示数位都是固定 的。比如有8位(10进制),把其中7位用来表示有效数位,另外 一位表示指数部分。那么上面2/3的例子就是
其意思是0.^0。 在实际的计算机中,假设有32位(2进制),拿23位当有效 数位,8位当指数部分,1位当符号位。在有效数位部分,因为 有23个有效数位,设十进制的有效数字位为X,则有223=10x, 即相当于十进制的x=23*log10(2)=6.92369位。即约是7位十进制 有效数字。 而指数部分有 8*log10(2)=2.4082位 C语言中不同长度实型数据的取值范围和数字精度宽度 数据类型 (比特)机内表示(位数) 取值范围 阶码 尾数 8 23 符号 1 |3.4e-38| ~ 3.4e+38| |1.7e-308| ~|1.7e+308| 大约7位十进制有效数字, (23*log102=6.92369) 8*log102=2.4082。7位精度 16位十进制有效数字 (52*log102=15.6356) 11*log102=3.3113.7位精度 18位十进制有效数字, 7位精度 有效数字和精度32float64double1152180Long double128|1.2e-4932| ~|1.2e+4932| C语言提供了一个测定某一种类型数据所占存储空间长度的运算符“sizeof‖它的格式为: sizeof (类型标识符或数据) 当不了解所使用的编译器中的某数据类型的宽 度时,可以使用这个运算符计算之。 例2.1 用sizeof运算符测定所用的C系统中各种类型 数据的长度。/****** 文件名:ex020101.c ******//****** 测定数据类型长度 ******/ #include &stdio.h& int main(void) { int i = 0; printf (&char: %d bytes.\n&,sizeof(char)); printf (&short: %d bytes.\n&,sizeof(short)); printf (&i: %d bytes\n&,sizeof (i));/* 计算变量i的字节数*/printf (&int: %d bytes\n&,sizeof(int)); printf (&long: %d bytes\n&,sizeof(long)); printf (&float: %d bytes\n&,sizeof(float)); printf (&double: %d bytes\n&,sizeof(double)); printf (&1.23456: %d bytes\n&,sizeof(1.23456));/* 计算常量的字节数*/return 0;} 用VC++6.0 编译并运行,得到以下结果: char: 1 bytes short: 2 bytes i: 4 bytes int: 4 bytes long: 4 bytes float: 4 bytes double: 8 bytes 1.23456: 8 bytes 实型常数不分单、双精度,都按双精度double型处理 实型变量说明的格式和书写规则与整型相同。 例如: float x,y; (x,y为单精度实型量) double a,b,c; (a,b,c为双精度实型量) 实型常数不分单、双精度,都按双精度double型处理。 以下程序说明float、double的不同#include &stdio.h& void main() { a=; b=; printf(&%f\n%lf\n&,a,b); }打印结果为:
由于a 是单精度浮点型,有效位数只有七位。而整数已 占五位,故小数二位后之后均为无效数字。b 是双精度型, 有效位为十六位。但Turbo C 规定小数后最多保留六位,其 余部分四舍五入。2.2 数据常量2.2.1 整型常量1. 整数常量的三种进制 在C语言中,整型常量可以使用十进制数、八进制数、 十六进制数等几种形式书写。C语言规定,程序中凡出现以 数字0开头的数字序列,一律作为八进制数处理;凡出现以 0x开头,后面跟若干位数字的,一律作为十六进制数处理; 其它数字作为十进制数处理。 下面是合法的整型常量:5121――(十进制正整数)0111――(八进制正整数,等于十进制数73)010007――(八进制正整数,等于十进制数4103)0177777――(八进制正整数,等于十进制65535) 0XFFFF――(十六进制正整数,等于十进制数6――(十六进制正整数,等于十进制数163) -32768――(十进制负整数) 下面不是合法的整型常量:09876――(非十进制数,又非八进制数,因为有 数字8和9) 20fa――(非十进制数,又非十六进制数,因为不 是以0x开头) 0x10fg――(出现了非法字符g) 2. 整数常量类型的确定在C语言中整数可以进一步分为short、int、 long和long long等类型。那么,对于一个常数如 何分辨其类型呢?一般说来,有以下原则: 1)默认原则:在没有任何特别标志的情况下,可 以按照常数所在的范围,决定其类型。例如,在 16位的机器中,当一个常整数的值在十进制 -3(八进制数0~0177777、十六制数 0x0~0xFFFF),则被看作一个short int或int型 整数。超出上述范围的整常数,则被看作长整数 (32位)表示。例如,234、36、 0xFFFE等被看作是int型,而-3、 x10000等被看作是long型。 2)后缀字母标识法: 用L或l表示long类型整数。 用LL或ll表示long long类型整数。 用U或u表示unsigned类型。 例如: -12L――(十进制long整数) -12LL――(十进制long long整数) 774545L――(十进制long整数) 076L――(八进制long整数,等于十进制数62) 0100000L――(八进制long整数,等于十进制3l――(十六进制long整数,等于十进制数18) 0X8000l――(十六进制long整数,等于十进制数3u――(十进制unsigned int类型) 12345UL――(十进制unsigned long类型) 在16位字长的机器中,一旦把一个常数表示成 long整数,系统便将其存储空间扩充为4个字节。从 值的大小上看,12L与12没有区别,但它们占用的存 储空间不相同。2.2.2 字符类型及其常量1. 可打印字符 字符类型的数据在内存中以相应的ASCII代码存放。例如,’a?的ASCII码为97,则在内存中的二进制存储形式为:。 例2.2 /* 文件名:ex020201.c */ #include &stdio.h& int main(void) { /* 定义了一个字符类型的变量ch */ ch ='a'; printf (&%d&,ch); /* 使用整型格式码 */ return 0; }运行结果为: 97 例2.3#include &stdio.h& int main(void) { ch ='A'; ch = ch + 32; i = printf (&%d is %c\n&, i, ch); printf(&%c is %d\n&, ch, ch); return 0; } 运行结果如下: 97 is a a is 97/* 注意格式码 */ /* 注意格式码 */ 例2.4 #include &stdio.h& int main(void) { c = 0362; //八进制数=十进制数242 printf (&%d\n&, c); return 0; } 运行结果: -14 //有的系统直接输出十进制数242 Turbo C把char型隐含指定为signed型,即最左端一位 作为符号位。 (14)10=( 取反(+1= ( = (242)10 2. 字符常量 ASCII字符分为可打印字符和不可打印字符两 种。在C语言程序中,可打印字符常量是用一对单撇 号括 起 来的 一 个字 符 ,如 ‘a? ,‘ A?,‘??, , ‘ # ’ 。 需 要注意如下几点: 单撇号只是字符与其它部分的分隔符,或者说 是字符常量的定界符,不是字符常量的一部分,当 输出一个字符常量时不输出此撇号。 不能用双引号代替撇号 ,如“a”不是字符常 量。 撇号中的字符不能是单撇号或反斜杠,如‘ ′? 或‘\’不是合法的字符常量。 3. 转义字符 转义字符(反斜杠码)是C语言提供的处理一 些特殊字符(包括一些不可打印字符)方法。重要 有如下一些: 用反斜杠开头后面跟一个字母代表一个控制字 符(不可打印字符); 用\\代表字符“\”,用\′代表撇号字符; 用\后跟1到3位八进制数代表ASCII码为该八 进制数的字符; 用\x后跟1到2位十六进制数代表ASCII码为该 十六进制数的字符。 转义字符表转义字符形式 \n \t \v \b 换行 水平制表 垂直制表 退格 意 义\r\f \a \\回车走纸换页 报警(如铃声) 反斜杠\?\“ \’ \ddd \xhh问号双撇号 单撇号 1~3位八进制常数 1~2位十六进制常数 例2.5 本例只能在针式打印机上输出 /* 文件名:ex020501.c */ /*打印人民币符号&¥& */ #include &stdio.h& int main(void) { printf(&Y\b=\n&); return 0; } 该程序运行时先打印一个字符“Y‖。这时打印 头已走到下一个位置,用控制代码\b使打印头回 退一格,即回到原先已打印好的Y位置再打印字符 “=‖,两字符重迭形成人民币符号“¥”。当然, 这 一输出只能在打印机上实现,而不能在显示器上实 现。因为显示器无此重迭显示功能(在显示后一字 符时原在该位置上的字符消失)。 转义字符除用来形成一个外设控制命令外,还 用来输出不能直接从键盘上输入或不能用字符常量 书写出的ASCII字符。这时要在反斜杠\后跟一个 代码值,这个代码值最多用三位八进制码数(不加 前缀)或两位十六进制数(以x作前缀)表示。 例2.6 本例在不同的编译器上输出不同的符号 /* 文件名:ex020601.c */ #include &stdio.h& int main(void) { ch='\362'; /*将八进制数362的ASCII字符赋给ch*/ printf (&%c\n&,ch); return 0; } 运行可在显示屏上输出 ≥ 不同的编译器可能显示不同。 4. 字符串常数 在C语言中,把用一对双撇号括起来的零个或多个字符序 列称为字符串常数。如: “hello”, “Programming in C” ,“A” , “a” , “ ”等。 字符串以双撇号为定界符,但双撇号并不属于字符串。要 在字符串中插入撇号,应借助转义字符。 例如要处理字符串“I say: ?Goodby!? ”时,可以把它写为 “I say: \ ? Goodby! \? ” 字符串中的字符数称为该字符串的长度。字符串常数在机 器内存储时,系统自动在字符串的末尾加一个“字符串结束标 志”,它是转义字符“\0”。如字符串“hello”在内存中存储 为: h e l l o \0 2.2.3 实型常量C语言中的实型(浮点)数据常量用带小数点和小数分 量的形式表示,如12.345,也可以用科学记数法表示。 C语言将实型数据分为:float、double和long double三 种类型,并且默认的实型数据是double类型的。因此,对于 带小数点的常量,C语言编译器会将之作为double类型看 待。如果要特别说明某带小数点的常量是float类型或long double类型,可以使用后缀字母: 用f或F表示float类型,如123.45f 1.2345e+2F. 用l或L表示long double类型,如.2345E+3L 使用科学记数法(指数形式)时,要求e的左边必须有 数值部分(有效数字),可以是整数,也可以是小数形式; 指数必须是整数形式。例如,e5、2e1.23、.e5等都是不合法 的。 2.2.4 符号常量 前面介绍的常量都是直接常量,从字面上即可直接看出 它们的值是什么,因此又称“字面常量”。 符号常量则是在一个程序(或程序的一部分)中指定的用 名字代表的常量,从字面上不能直接看出其类型和值。 例2.7 求圆面积和周长的两个程序。 程序1: /****** 计算圆的周长和面积 ******/#include &stdio.h&double calcuArea (double r); double calcuCircum(double r); int main(void) { printf (&area=%f&, calcuArea (2.0)); printf (&\tcircumference=% f\n&, calcuCircum (2.0)); return 0; } double calcuArea(double r) /* 计算圆面积 */ { return (3.* r* r); } double calcuCircum(double r) /* 计算圆周长 */ { return (2.0*3.*r); } 运行结果为: area = 12.566371 circumference = 12.566371 程序2:计算圆的周长和面积 #include &stdio.h& #define PI 3. /*定义符号常数*/ #define R 2.0int main(void) { double calcuArea(double r); double circumference(double r); printf(&area=%f&,calcuArea(R)); printf (&\tcircumference=%f\n&, circumference(R)); return 0; } double calcuArea(double r) { return (PI* r* r); } double circumference(double r) { return (2.0* PI* r); } 程序2的运行结果与程序1完全相同。程序2中PI代替3.,用R代替2.0,使程序更容易理 解,可读性好,而且当需要修改R的值时只需要改 一处即可,方便又不易出错。定义符号常量的一种 方法是使用#define命令,它是一种“预编译命 令”,在编译整个程序之前系统会先对程序中的预 编译命令进行处理。上面#define命令的作用是在预编译时将程序中凡出现PI的地方全部以3.代替,凡出现R的地方一律以2.0代替。 2.3 数据类型转换在下列情况下,C语言编译器,可能将数据从 一种类型转换成另一种类型: (1)显式转换:使用转换表达式。 (2)隐式转换,包括: ● 当二元运算符两端的操作数类型不同时进行 的转换; ● 函数参数传递中的数据类型转换; ● 函数返回时的数据类型转换; ● 其他情形。 2.3.1 几个概念1. 数据类型的提升与降格 提升可以分为如下3类情况: (1)类型提升:由整数转换为浮点数。 (2)整数提升:由短整数类型转换为长 整数类型。 (3)同一长度的整数有符号与不有符号 的,属于同一级别。 2. 符号位变为数据的最高位和最高位变成符号位 例2.8 分析下面程序的执行结果。 #include &stdio.h& int main(void) { unsigned short us1 = 32767, us2 = 65535, signed short ss = -7; us = printf(&(1)ss = %d, us = %u\n&,ss,us); ss = us1; printf(&(2)us1 = %u, ss = %d\n&,us1,ss); ss = us2; printf(&(3)us2 = %u, ss = %d\n&,us2,ss); return 0; } 程序执行结果如下: (1) ss = -7, us = 65529 (2) us1 = 32767, ss = 32767 (3) us2 = 65535, ss = -1 不同类型的变量之间通过赋值操作,使右值类型转换为左值类型。下面分2种情形讨论。 (1)第1种情形是把一个有符号的数-7(在变量ss中), 赋 值 给 无 符 号 类 型 的变量 us 后 ,在 无 符号变 量 中的数据 变成为65529了。这种变化是由于将原来的符号数中的符 号变成了无符号数中的最高位而产生。如图2.4所示,当一 个-7的16位补码被当作16位无符号数时,由于正数的原码 =补码,所以11 1001 = 65535(全1)-110=65529。 1000000000000111-7原码1111111111111001-7补码符号位变最高数据位类型转换1111111111111001无符号数 (2)第2种情形是将一个一般的unsigned类型数 据转换成同长度的signed类型数据。在一般情况 下,不会出现数据的错误。 (3)在第3种情形却出现了错误。这是因为当无符号数较小,其最高位为0时,转换成符号数后,最高位虽然被当作了符号位,但并没有影响数据的有效值。而如果无符号数大到使最高位为1,则转换成有符号数后,被当成了负数的补码。于是,出现 数据错误。 1111111111111111无符号数65535最高位变符号位类型转换1111111111111111有符号数据 补码1000000000000001有符号数据 原码 3. 截去小数与四舍五入 当一个实数(浮点数)转换为整数时,实数的 小数部分全部舍去,并按整数形式存储。例如将 实数3276.85赋给一个整型变量i,i的值为3276。 但应注意,实数的整数部分不要超过整型数允许 的最大范围(微机上为-3),否则数据 出错。当由double型转换为float型时,去掉多余的 有效数字,但整数部分按四舍五入处理。小数部 分则未按四舍五入处理。 4. 丢失精度 四舍五入会丢失一些精度,截去小数也会丢失 一些精度。此外,由long型转换成float或double 型时,有可能在存储时不能准确地表示该长整数的 有效数字,精度也会受损失,因为float型只有7位 精度。 5. 结果不确定与截去高位 浮点数降格时,即double转换为float,或 double、float转换成long int、short型。当数据值超 过了目标类型的取值范围时,所得到的结果将是不 确定的(其实也是有规律的,只是给出一个用户往 往难以理解的数值。例如,将实数32768.85赋给16 位整型变量i,由于32768超过了16位整数最大值 3 2 7 6 7 , 在 内 存 中 就 把 3 2 7 6 8 存 储 为0000形式,它代表整数-32768。如果 输出i,得-32768。若将32769.85赋给i,输出整数i的 值得-32767。这些牵涉到补码的知识,在此不详述)。 当较长的整数转换为较短的整数时,要将高位截去。例如long型为4个字节,short型为2个字节,将long型值赋给short类型,只将低字节内容送过 去。这就会有很大误差,得到的值是原数据值以32768为模的余数。 例2.9 下面是数据类型转换的一个例子。 #include &stdio.h& int main(void) { double a = 098765; short i,j; b = c = i = j = printf(&a=%f,b=%f,c=%ld, i=%d,j=%d\n&,a,b,c,i,j); return 0; }运行结果如下: a = 099, b = 063, c = 123456, i = -7616, j = 7616 长整数123456在计算机内存中的存储情况 2.3.2 数据类型的隐式转换 1. 赋值转换 2. 一般表达式转换 (1)一元转换操作数类型 float 阶大于或等于int的整型数据 阶小于int的有符号类型数据 阶小于int的无符号类型数据,所有值可以用int 类型表示 阶小于int的无符号类型数据,所有值不可用int 类型表示 标准C语言 转换 (无转换) (无转换) int int unsigned int 传统C语言 转换 double (无转换) int unsigned int unsigned int (2)二元转换 按照优先级顺序将各二元运算符两端的操作数提升成同 一类型。转换按照下面的算法进行。 if (一个操作数为long double)另一个操作数转换为long double else if(一个操作数为double) 另一个操作数转换为double else if(一个操作数为float) 另一个操作数转换为float else if(一个操作数为unsigned long) 另一个操作数转 换为unsigned long else if(一个操作数为long) 另一个操作数转换为 long else if(一个操作数为unsigned) 另一个操作数 转换为unsigned
3. 输出转换 例如,一个long型数在printf()中指定用%d 格式输出,相当于先将long转换为int型后再输出。 一个int型数也可按无符号方式输出(使用%u转换 等)。2.3.3 数据类型的显式转换C语言提供一种“强制类型转换”运算符,将 一个类型的变量强制转换为另一种类型。例如:(int)3.5中(int)的作用是将3.5转换成整型(类型标识符)表达式 例如: (char) (3-3.14159 *x) (float)(x=99) (得到字符型数) (得到实型单精度数) k=(int)((int)x+(float)i+j) (得到整型数) C系统提供的数学函数中多数要求参数为double型, 在调用这些函数时可以用显示转换方法进行类型转换。例 如: double atan ((double)i) double cos ((double)i) double sqrt ((double)i) double log ((double)i)double exp ((double)i) 2.4 数据的控制台输入与输出输入输出的对象是数据,而数据是以介质为载体的,因此进行输入输出操作就要与各种外部设备发生联系,要指定从哪个设备(文件)读入数据,将数据输出到哪个设备(文件)上去。本节只讨论从终端(键盘)输入和输出到终端(显示器)的输入输 出函数。通常也把这些函数称为控制台输入输出函 数。主要是用得最广泛的scanf函数、printf函数、 getchar函数和putchar函数等。其中scanf和printf用于格式化输入输出。 2.4.1 格式化输出函数printf( )1. printf( )基本格式 printf( )函数的一般形式如下:int printf(格式控制字符串,输出表达式1,输出表达式2,…);2. 格式说明字段结构 (1)基本格式码格式码 d/i 输出说明 带符号十进制定点格式 举 例 输出结果 975311int a=975311;printf(“%d”,a);uo x/X无符号十进制定点格式无符号八进制定点格式 无符号十六进制定点格式int a=975311;printf(“%u”,a);int a=975311;printf(“%o”,a); int a=975311;printf(“%x”,a);9753113560717 ee1cfcs f e/E g/G字符字符串 小数形式十进制 科学记数法 f和e中短者,不印无效0int a=68;printf(“%c”,a);Dchar s[]=”abcde”; printf(“%s”,s); abcde double a=123.456;printf(&%f&,a); 123.456000 double a=123.456;printf(&%E&,a); double a=123.456;printf(&%G&,a); 1.2 123.456p%输出地址,格式由实现定 义%double 0012FF74 ( a的地址) a=123.456;printf(&%p&,&a);printf(&%%&); % (2)长度修正符长度修 正符 lll h hh L可修饰的格 式码 d,i,o,u,x,Xd,i,o,u,x,X d,i,o,u,x,X d,i,o,u,x,X a,A,e,E,f,g,G参数类型long, long long int, unsigned long long int short, unsigned short char, unsigned char long double (3)域宽与精度说明 域宽与精度说明的格式为:m.n。 其中: m为输出域宽,用字符数表示。对实数,包括 了一个小数点的位置。 n为精度,其用法有如下几种情形: ● 配合格式码f、e/E时,指定小数点后面的位 数;未指定精度时,默认小数点后6位。 ● 配合格式码g/G时,指定有效位的数目。 ● 作用于字符串时,精度符限制最大域宽。 ● 作用于整型数据时,指定必须显示的最小位 数,不足时左侧补先导0。 例 2.10 /* 文件名:ex021001.c */ #include &stdio.h& int main(void) { printf(&%12.5f\n&,123.1234567); printf(&%12f\n&,123.1234567); printf(&%12.5g\n&,123.1234567); printf(&%5.10s%s\n&,&abcdefghijklm&,&a&); printf(&%12.8d\n&,12345); return 0; } 执行结果如图2.8所示。图2.8 例2.10的输出结果 (4)前缀修饰修饰符 0 + 空格 # * 数据在输出域中左对齐显示 用“0”而非空格进行前填充意 义在有符号数前输出前缀“+”或“-” 对正数加前缀空格,对负数加前缀“-” 在g和f前,确保输出字段中有一个小数点;在x前,确保输出的 十六进制数前有前缀0x 做占位符号 例2.11 下面的数据定义 double x = 333., y = -555.; int i = 123456; // (=(1e240)16格式 字段 %20d %20x %20f %#20x %-20f 数据 项表 i i x i x 3 3 3 . 0 1 2 3 4 6 3 3 3 . 输 出 结 果 1 2 3 4 5 6 1 e 2 4 0 0 1 2 3 4 6 说 明域中右对齐输 出0 x 1 e 2 4 0 确保加前缀0x 域中左对齐% 20f%020f %+20f %+20f %*.*fxx x y 20,8, x 3 0 0 0 0 0 0 0 0 0 0 33 3 33 3 3 5 5 5 3 ... . .0 1 2 3 4 6 填充空格前导0 1 2 3 4 6 填充0前导 0 1 2 3 4 6 0 1 2 3 4 6 确保加正负号 数据替代占位 符+ 3 3 30 1 2 3 4 5 6 8 例2.12 一个显示美国各州面积、森林覆盖面积和森林覆盖率的简单程序。 /****** 美国各州面积列表 ******/ #include &stdio.h& int main(void) { double ar ,por, printf(&%-12s%12s%12s%12s\n&,&State&,&Area&,&Forest&,&Percent&); printf(&------------------------------------------------\n&); ar = 50750; por = 33945; perc = por/ar*100; printf(&%-12s%12.0f%12.0f%10.2f%%\n&,&Alabama&,ar,por, perc); ar = 591000;por = 201642; perc = por/ar*100; printf(&%-12s%12.0f%12.0f%10.2f%%\n&,&Alaska&,ar,por, perc); ar = 114000;por = 30287; perc = por/ar*100; printf(&%-12s%12.0f%12.0f%10.2f%%\n&,&Arizona&,ar,por, perc); ar = 53187;por = 26542; perc = por/ar*100; printf(&%-12s%12.0f%12.0f%10.2f%%\n&,&Arkanasas&,ar,por, perc); ar = 158706;por = 61532; perc = por/ar*100; printf(&%12s%12.0f%12.0f%10.2f%%\n&,&California&,ar,por, perc); ar = 104000;por = 33340; perc = por/ar*100; printf(&%12s%12.0f%12.0f%10.2f%%\n&,&Colorado&,ar,por, perc); printf(&......\n&); return 0; } 程序执行结果如下: 3. printf()中输出表达式的运算顺序 例 2.13 /* 文件名:ex021301.c */ #include &stdio.h& int main(void) { int a= 1, b = 2; printf(& x = %d , y = %d\n&,++ a + b,++ b + a); return 0; } 程序执行结果如下: x = 5, y = 4 2.4.2 格式化输入函数scanf( )scanf( )函数的功能是将输入数据送入相应的存储单元。 具体地说,它是按格式参数的要求,从终端上把数据传送到地址参数所指定的内存空间中。其原型为: int scanf(格式控制字符串, 地址1, 地址2, …); 1. 地址参数 C语言允许程序员间接地使用内存地址,这个地址是通 过对变量名“求地址”运算得到的。求地址的运算符为&。 例 如对于定义: &a给出的是变量a两字节空间的首地址,&b给出的是变 量b四字节空间的首地址。 2. 格式说明字段 scanf( )与printf( )有相似之处,也有不同之处。 scanf( )格式控制字符串中的主要成分是格式说明字 段和数据项。scanf( )的格式说明字段的结构如图2.9 所示。% 宽度 长度修正 格式码a/A,c,d,e/E,f,g/G,i,,n,o,p,s,u,x/X,%l/L,h,ll,hh,j,z,t 十进制整数 格式码 d长度修正符 无 hh h l ll hh h l ll 无 hh h l ll 无 无 无 hh h l ll 无 无 l L 无 无输入数据类型 int char short long long long char short long long long unsigned unsigned char unsigned short unsigned long unsigned long long char 字符串 int char short long long long 地址 float double long double 字符搜索集合 %说 明 输入带符号十进制整数,可选加+或-i输入带符号整数,可选加+或-以及0(八进制)、0x(十六进制)u o x输入带符号十进制整数 输入无符号八进制整数,可选加+或输入无符号十六进制整数,可选加+或-c s n读取字符 连续读取字符,直到遇到文件结束符、空白或达到指定字段宽度 不读取字符,而是而是把scanf()所处理的字符总数写入到对应参数指定 的变量中。p f, e, g,a读取地址 读取带符号十进制实数[] %只能输入定义在搜索集合中的字符,例如%[abcdefgh]或%[a-h] 读取% 例 2.14 /* 文件名:ex021401.c */ #include &stdio.h& int main(void) { double a,b,c,d; scanf(&%f%f&,&a,&b); printf(&\na=%lf,b=%lf\n&,a,b); scanf(&%lf%lf&,&c,&d); printf(&\nc=%lf,d=%lf\n&,c,d); return 0; } 某次执行结果如下: 3. 数值数据流的分隔 scanf( )是从输入数值数据流中接收非 空的字符,再转换成格式项描述的格式,传 送到与格式项对应的地址中去。当操作者在 终端上键入一串字符时,系统怎么知道哪几 个字符算作一个数据项呢?有以下几种方法: (1)使用默认分隔符:空格、跳格符 (‘\t’)、换行符(‘\n’)。 例 2.15 /* 文件名:ex021501.c */ #include &stdio.h& int main(void) { float b,c; scanf (&%d%f%f&,&a,&b,&c); printf (&a=%d,b=%f,c=%f&,a,b,c); return 0; } 一次运行情况如下: 12 345 1 a=12, b=345.000000, c= 注意,当从键盘上键入一串字符流后, 只有键入回车时,系统才开始执行执行scanf( ) 规定的操作。 (2)根据格式项中指定的域宽分隔出数 据项。 例 2.16 /* 文件名:ex021601.c */ #include &stdio.h& int main(void) { float b,c; scanf (&%2d%3f%4f&,&a,&b,&c); printf (&a=%d,b=%f,c=%f&,a,b,c); return 0; } 一次运行情况如下: 54321 ? a=12,b=345.000000,c= (3)根据格式字符的含义从输入流中取得数据,当输入流 中数据类型与格式字符要求不符时,就认为这一数据项结束。 例 2.17 #include &stdio.h& int main(void) { printf (&input a,b,c:\n&); scanf (&%d%c%f&,&a,&b,&c); printf (&a=%d,b=%c,c=%f&,a,b,c); return 0; } 一次执行结果为: input a b c: 7?(带下划线者为输入流) a=1234,b=r,c= (4)格式控制字符串中的非空白字符 在scanf( )中的格式控制字符串中,除了格式说明字段中 的字符外,所出现的其他字符,都必须在输入数据流时照样 输入。 例2.18#include &stdio.h& int main(void) { int a, scanf(&input:%d$$$%d&,&a,&b); printf(&%d, %d\n&,a,b); return 0; }输入的情形如下: input:123$$$456 123,456 4. scnaf( )与输入缓冲区 在输入数据时,实际上并不是输入完一 个数据项就被读入送给一个变量,而是在键 入一行字符并按回车键之后才被输入,这一 行字符先放在一个缓冲区中,然后按scanf( ) 格式说明的要求从缓冲区中读数据。如果输 入的数据多于一个scanf( )所要求的个数,余 下的数据可以为下一个scanf( )接着使用。 例 2.19 #include &stdio.h& int main(void) { int a,b,c,d,e,f; scanf(&%d %d&,&a,&b); scanf(&%d %d&,&c,&d); scanf(&%d&,&e); scanf(&%d&,&f); printf(&a=%d,b=%d,c=%d,d=%d,e=%d,f=%d&,a,b,c,d,e,f); return 0; } 运行情况如下: 13 24 35 46 57 68 79 a=13,b=24,c=35,d=46,e=57,f=68 这个程序中的操作图 5. scanf( )用于字符输入 (1)所有空白字符、转义字符都将作为 有效字符被接收,因此不能再使用空白或 其他字符进行数据项的分隔。 (2)当定义有字段宽度时,scanf()将 在缓冲区中的输入流上,按宽度间隔地跳 取字符。 例2.20 #include &stdio.h& int main(void) { char c1,c2,c3; scanf(&%c%c%c&,&c1,&c2,&c3); printf(&\nc1=%c,c2=%c,c3=%c&,c1,c2,c3); return 0; } 一次运行结果如下: a b c1=a.c2= ,c3=b 另一次运行结果如下: abc c1=a,c2=b,c3=c 6. scanf()的停止与返回 scanf( )函数操作有四个作用: (1)首先从缓冲区中提取需要的数据。 (2)如果缓冲区中没有需要的数据,则要求从 键盘输入一个数据流。输入操作以回车操作结束。 (3)遇到下面的情形终止执行: 格式参数中的格式项用完――正常结束; 发生格式项与输入域不匹配时 ――非正常结 束。例如从键盘输入的数据数目不足。 (4)执行成功,返回成功匹配的项数,执行失 败,返回0。 2.4.3 字符输入输出函数getchar( )与putchar( )为了方便字符的输入输出,标准C还提供了两个简单的 库函数:getchar( )和putchar( )。它们的原型分别为:int getchar(void);int putchar(int c); getchar( )被执行后,就等待击键操作,然后从返回一个 字符值,并自动把击键结果回显在屏幕上。它虽然被定义为 返回int类型,但由于所读取的字符被保存在低字节中,所以可以赋值给一个char型变量。读取失败,返回-1。putchar(c)函数是将字符变量c中的字符输出到标准输出 设备(一般也是用户终端)上。 例 2.24 将输入的3个字母在屏幕上输出。#include &stdio.h& int main(void) { char ch1,ch2,ch3; ch2=getchar(); putchar(ch1); putchar(ch3); return 0; }运行结果如下:ch1=getchar(); ch3=getchar(); putchar(ch2); putchar('\n'); 注意:在执行getchar()时,虽然是读入一个字符,就回 显一个字符,但并不是从键盘按一个字符 ,该字符就被立 即送给一字符变量,而是等到一个回车键后,才将一行字符 输入缓冲区,然后getchar函数从缓冲区中取一个字符给一个 字符变量。这种情况称为行缓冲。 getchar( )的行缓冲(等回车)和回显也会为某些交互性应用带来不便。这时,可以用下面的两个库函数代替:getche( ):读字符,并回显,不等回车; getch( ):读字符,但不回显,不等回车。不过,这两个库函数在ANSI C标准中并没有定义,是一种常见扩充。对于多数C编译器,这两个函数的原型被定义 在&conio.h&头文件中。在有的编译器(如Visual C++)中,它们可能被冠以下划线前缀:_getche( )和_getch( )。 第3章3.1 3.2 3.3 3.4C语言的流程控制算法 判断 选择型程序设计 循环型程序设计 3.1 算法通过前两章的学习,不少读者可能 已经悟出,计算机尽管可以完成许多极 其复杂的工作,但实质上这些工作都是 按照人事先编好的程序的规定进行的。 所以人们常把程序称为计算机的灵魂。 随着计算机应用的日益广泛和深入,人 们在研究和开发新的软、硬件技术的同 时,也对程序本身和程序设计方法进行 了深入的探讨。 1976年瑞士计算机科学家Niklaus Wirth在他的惊世之作中提出了一个著 名的公式: 算法 + 数据结构 = 程序图3.1 Niklaus Wirth 他认为,“程序就是在数据的某些特定表示方式和 结构的基础上对抽象算法的具体表述”。Wirth企图用这个 公式来对程序进行一个概括性的定义。从今天的观点来 看,它只能是对过程化程序的一个抽象定义,对面向对象的程序而言则不尽然。不过对学习C语言这样的面向过程的程序设计语言而言,是完全适用的。也就是说,面向过 程的程序有两大要素:算法和数据结构。数据结构是程序 所处理的对象――数据的表示和组织形式。数据类型就是 其重要内容。关于数据结构的概念在学习完第5、6、7章 后,才会有较深的体验。 3.1.1 算法的组成要素与基本性质1. 算法的组成要素 (1)操作算法是由一系列操作组成的。每个操作的确定不仅取决于问题的需求,还取决于它们取自哪个操作集,它与使用的 工具系统有关。如算盘上的操作集由进、退、上、下、去等组成;做菜的操作集包括坐锅、加油、炒、煮、炸、蒸、焖、加水、加调料等;驾驶汽车的操作包括踩离合器、踩油 门、开电门、换档、左转、右转、开灯、关灯等。计算机算法要由计算机实现,组成它的操作集是计算机所能进行的操作。而且这些操作的描述与程序设计语言的级别有关。在高 级语言中所描述的操作主要包括:算术运算(+、-、*、/)、逻 辑运算(D与”、“或”、“非”等)、关系运算(==、>=、< = 、 >、<、!=等)、函数运算、位运算、I/O操作等。计算机算 法是由这些操作所组成的。 (2)控制结构 算法的另一要素是其控制结构。每一个算法都要由一系 列的操作组成。同一操作序列,按不同的顺序执行,就会得出不同的结果。控制结构即如何控制组成算法的各操作的执行顺序。结构化程序设计方法要求:一个程序只能由三种基 本控制结构(或由它们派生出来的结构)组成。1966年Bohm 和Jacopini证明,由这三种基本结构可以组成任何结构的 算法,解决任何问题。这三种基本结构是: (1)顺序结构。顺序结构中的语句是按书写的顺序执行的,即语句的执行顺序与书写顺序一致。这种结构像一串珍 珠项链一样清晰可读。这是一种理想的结构,但是光有这样的结构不可能处理复杂的问题。一般说来,程序中的语句是顺序执行的。但是,顺序执 行的程序的功能是非常有限的。为了提高程序的灵活性,必 须采用不同的程序流程结构。 (2) 选择结构。最基本的选择结构是当程序执行到某一语句时,要进行一下判断,从两种路径中选择一条。例如,要在两个数a,b中取一个最大的数就要经过比较判断,决定是 将a还是将b输出。选择结构给程序注入最简单的智能。由二分支选择,可以派生出多分支选择结构。 (3) 循环结构(或称重复结构)。这种结构是将一 条或多条语句重复地执行若干遍。就像驴子拉磨一 样,虽然每一圈的操作都比较简单,而且相同,但 磨上若干圈后就能把麦子磨成面粉。众所周知,电 子计算机的一大优势是速度快。当能把一个复杂问 题用循环结构来实现时,就能充分地发挥计算机的 高速度的优势。 2. 算法的基本性质 简单地说,算法就是进行操作的方法和操作步 骤。例如,菜谱实际上是做菜肴的算法,乐谱实际 上是演奏的算法,计算机程序是用某种程序设计语 言描述的解题算法。通常认为算法有如下一些性质: (1)有效性 有效性指算法所规定的操作都应当是能够有效执 行的。例如,对于操作汽车的算法,有效的操作就是 加速、刹车、换档、转动方向盘、鸣笛等,要让汽车 执行“跳起”就是无效的操作。同样,一个计算机算 法 必须是计算机能够执行的。 (2)确定性 确定性具有两重意义:一是所描述的操作应当具 有明确的意义,不应当有歧义性。例如,不能发出这 样的操作指令:“执行一个算术操作”。因为它既没 有 指出算术操作的类型,也没有指出操作数。 确定性的另一重意义: ● 操作作序列只有一个初始动作,序列 中每一动作仅有一个后继动作; ● 序列终止表示问题得到解答或问题没 有解答,不能没有任何结论。 (3)有穷性 有穷性指算法所规定的操作序列必须在 允许的时间内结束。例如,一个计算机算法 要执行100年以上,就失去有穷性。 3.1.2 算法描述工具为了描述算法,人们创建了许多算法描述工具。下面介 绍程序设计中常用的几种方法,并主要介绍如何用这些工具描述算法的三种基本结构。1. 流程图 流程图是一种流传很广的算法描述工具。这种工具的特 点是用一些图框表示各种类型的操作,用线表示这些操作的 执行顺序。我国国家标准GB 1526―89中推荐的一套流程图标 准 化 符 号 , 它 与 国 际 标 准 化 组 织 I S O ( I n t e r n a t i o n alStandard Organization)提出的ISO流程图符号是一致的。 图3.2为其中常用的一些符号。 过程判断数据预定义过程起止流程线连接注释图3.2常用的流程图标准化符号 下面对其中一些主要符号作简要说明。 (1) 平行四边形表示数据,其中可注明数据名 称、来源、用途或其它的文字说明。 (2) 处理矩形表示各种处理功能。例如,执行一 个或一组特定的操作,从而使信息的值、信息形式或 所在位置发生变化。矩形内可注明处理名称或其简要 功能。 (3) 预定义过程带有双竖边线的矩形,表示已命 名的处理。该处理为在另外地方已得到详细说明的一 个操作或一组操作。例如库函数或其它已定义的函数 等。矩形内可注明特定处理名称或其简要功能。 (4) 判断菱

我要回帖

更多关于 解方程练习题 的文章

 

随机推荐